В чем разница между shell_exec() и exec() в PHP для выполнения команд?
Основные различия между shell_exec() и exec()
Обе функции выполняют системные команды через оболочку (shell), но возвращают результаты по-разному. Главное отличие — в формате возвращаемого значения и возможности получить код возврата.
1. shell_exec() — возвращает весь вывод как строку
shell_exec() выполняет команду и возвращает весь вывод целиком в виде одной строки. Если команда не выдала вывода или произошла ошибка, возвращается null.
// Пример: получаем список файлов как строку
$files = shell_exec('ls -la');
echo "Файлы:\n" . $files;
// Если команда не имеет вывода (например, mkdir)
$result = shell_exec('mkdir /tmp/testdir');
var_dump($result); // null — вывода нет
Когда использовать:
- Нужен полный вывод команды в виде текста
- Команда гарантированно возвращает результат (например,
whoami,date) - Вы не планируете обрабатывать вывод построчно
2. exec() — возвращает вывод как массив и код возврата
exec() передает вывод команды в массив (каждая строка — отдельный элемент) и позволяет получить код возврата (0 — успех, любое другое число — ошибка).
// Пример: получаем список файлов построчно
exec('ls -la', $output, $return_code);
echo "Код возврата: $return_code\n";
echo "Файлы:\n";
foreach ($output as $line) {
echo "- $line\n";
}
// Проверяем успешность создания папки
exec('mkdir /tmp/testdir', $output, $return_code);
if ($return_code === 0) {
echo "Папка создана успешно";
} else {
echo "Ошибка создания папки";
}
Когда использовать:
- Нужно знать, успешно ли выполнилась команда (через код возврата)
- Вывод нужно обрабатывать построчно
- Команда может вернуть ошибку, и вы хотите это отследить
Дополнительные функции: system() и passthru()
Для полноты картины стоит упомянуть еще две функции:
- system() — выполняет команду и сразу выводит результат в браузер/консоль. Возвращает последнюю строку вывода.
- passthru() — выполняет команду и передает сырой бинарный вывод (полезно для изображений, аудио).
// system() — вывод сразу на экран
system('ls -la'); // строки появятся в браузере
// passthru() — для бинарных данных
header('Content-Type: image/png');
passthru('cat image.png');
Важные замечания по безопасности
Все эти функции крайне опасны, если вы передаете пользовательский ввод. Никогда не делайте так:
// ОПАСНО! Никогда так не делайте!
$user_input = $_GET['filename'];
shell_exec("rm -rf $user_input"); // злоумышленник может выполнить любую команду
Всегда используйте escapeshellcmd() или escapeshellarg() для экранирования:
// Безопасный вариант
$filename = escapeshellarg($user_input);
shell_exec("ls -la " . $filename);
Краткая таблица выбора:
- Нужен весь вывод как строка → shell_exec()
- Нужен код возврата или построчная обработка → exec()
- Нужно сразу вывести результат пользователю → system()
- Работа с бинарными данными → passthru()
Альтернативный подход: Использование proc_open() для максимального контроля
Если вам нужен полный контроль над выполнением команды (например, управление stdin, stdout, stderr по отдельности, или выполнение в фоне), лучше использовать proc_open().
// Запускаем команду с отдельным управлением потоками
$descriptorspec = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'] // stderr
];
$process = proc_open('ls -la', $descriptorspec, $pipes);
if (is_resource($process)) {
// Читаем stdout
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
// Читаем stderr
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
// Закрываем процесс
$return_code = proc_close($process);
echo "Вывод: $stdout\n";
echo "Ошибки: $stderr\n";
echo "Код возврата: $return_code\n";
}
Преимущества proc_open():
- Раздельное чтение stdout и stderr
- Возможность отправлять данные в stdin команды
- Неблокирующий режим (можно выполнять в фоне)
- Полный контроль над дескрипторами
Недостатки:
- Сложнее в использовании
- Требует больше кода
- Избыточен для простых команд
Для большинства повседневных задач exec() или shell_exec() более чем достаточно. Но если вы пишете что-то сложное (например, интерактивный терминал или управление процессами), proc_open() — ваш выбор.
Ответов пока нет.
Войдите чтобы оставить ответ