Exec: примеры (PHP)
exec(string $command, array &$output = null, int &$result_code = null): string|falseОписание функции exec
Функция exec() выполняет внешнюю программу, переданную ей в качестве аргумента. Она является частью семейства функций PHP для выполнения команд операционной системы и часто используется для взаимодействия с сервером.
Функция находит применение в задачах системного администрирования через веб-интерфейс, обработки файлов с помощью внешних утилит, запуска скриптов других языков или длительных фоновых процессов.
Сигнатура функции: exec(string $command, array &$output = null, int &$result_code = null): string|false
- $command (string): Команда для выполнения.
- $output (array &): Если передан массив, он будет заполнен каждой строкой вывода команды. Конечные пробелы в строках удаляются.
- $result_code (int &): Если присутствует этот аргумент, в него будет записан код возврата выполненной команды.
Функция возвращает последнюю строку вывода команды или false в случае ошибки.
Краткие примеры использования
Выполнение команды и получение последней строки вывода.
$last_line = exec('ls -la', $output, $return_code);
echo "Последняя строка: $last_line\n";
echo "Код возврата: $return_code";Последняя строка: ... Код возврата: 0
exec('whoami', $output_full);
print_r($output_full);Array
(
[0] => www-data
)exec("cp несуществующий_файл новое_место 2>&1", $out, $code);
echo "Команда завершилась с кодом: $code";
print_r($out);Команда завершилась с кодом: 1
Array
(
[0] => cp: cannot stat 'несуществующий_файл': No such file or directory
)Альтернативные функции в PHP
Возвращает весь вывод команды в виде строки. Удобна, когда нужен полный вывод без разбиения на строки.
Выполняет команду, выводит результат непосредственно в браузер (или stdout) и возвращает последнюю строку. Полезна для быстрой отладки.
Выполняет команду и передает сырой вывод напрямую в браузер (или stdout). Часто используется для двоичных данных, например, изображений.
Обеспечивает максимальный контроль над выполнением процесса: позволяет работать с stdin, stdout и stderr отдельно. Предпочтительна для сложных взаимодействий.
Функцию exec обычно выбирают, когда нужен массив строк вывода и код возврата.
Аналоги в других языках программирования
import subprocess
result = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print(result.stdout)
print(f"Код возврата: {result.returncode}")... вывод команды ... Код возврата: 0
const { exec } = require('child_process');
exec('ls -la', (error, stdout, stderr) => {
console.log(stdout);
if (error) console.log(`Код ошибки: ${error.code}`);
});Exec в MySQL
В MySQL прямой аналог отсутствует. Близкая по духу функция SYSTEM() (доступна с MySQL 8.0.19) выполняет команду оболочки, но возвращает только код выхода, а не её вывод.
SYSTEM ls -la; -- Возвращает только код выходаТипичные ошибки
// ОПАСНО
$user_input = $_GET['filename'];
exec("rm /tmp/$user_input"); // Пользователь может ввести "..\/..\/etc\/passwd"Решение: использование escapeshellarg().
$user_input = $_GET['filename'];
exec("rm /tmp/" . escapeshellarg($user_input));exec("some_failing_command", $output);
echo "Всё ок"; // Команда могла завершиться с ошибкойВсё ок
Решение: всегда проверять код возврата и перенаправлять stderr в stdout.
exec("some_failing_command 2>&1", $output, $code);
if ($code !== 0) {
echo "Ошибка: ";
print_r($output);
}Изменения в последних версиях PHP
В PHP 8.0 значительных изменений в поведении функции exec не было. Однако в PHP 7.4 и более ранних версиях стоит отметить:
- Ведется постоянная работа над безопасностью функций, выполняющих команды оболочки.
- Рекомендации по использованию escapeshellarg() и escapeshellcmd() остаются критически важными.
- В целом, поведение функции остается стабильным на протяжении многих выпусков.
Расширенные примеры
// Запуск длительной команды в фоне и запись вывода в файл
$command = 'nohup ./long_script.sh > /tmp/output.log 2>&1 & echo $!';
$pid = exec($command);
echo "Запущен процесс с PID: $pid";$commands = [
"sleep 2 && echo 'Первый'",
"sleep 1 && echo 'Второй'",
];
$pids = [];
foreach ($commands as $cmd) {
$pid = exec("nohup bash -c '" . escapeshellcmd($cmd) . "' > /dev/null 2>&1 & echo $!");
$pids[] = $pid;
}
echo "Запущены процессы: " . implode(', ', $pids);Использование proc_open предпочтительнее, но с exec можно эмулировать через echo.
$input_data = "Строка 1\nСтрока 2";
$command = "cat";
exec("echo " . escapeshellarg($input_data) . " | " . $command, $output);
print_r($output);Array
(
[0] => Строка 1
[1] => Строка 2
)// Использование timeout
$result = exec("timeout 5s slow_command.sh 2>&1", $output, $code);
if ($code == 124) {
echo "Команда была остановлена по таймауту.";
}$args = ['-l', '-a', 'каталог с пробелами'];
$safe_args = array_map('escapeshellarg', $args);
$command = "ls " . implode(' ', $safe_args);
// ls '-l' '-a' 'каталог с пробелами'
exec($command, $output);