Команда exec не работает на моем сервере, она ничего не делает, у меня отключен safe_mode, и я убедился, что все консольные команды работают, я пробовал использовать абсолютные пути. Я проверил разрешения для приложений, и все приложения, которые мне нужны, имеют разрешения на выполнение. Я не знаю, что еще делать, вот краткое изложение кодов, которые я пробовал:
echo exec('/usr/bin/whoami');
echo exec('whoami');
exec('whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
echo 'Error<br>';
print_r($output);
}
exec('/usr/bin/whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
echo 'Error<br>';
print_r($output);
}
Вот вывод последних двух кодов:
Error
Array ( )
Я связался со службой сервера, и они не могут мне помочь, они не знают, почему команда exec не работает.
Ответ 1
Посмотрите файл /etc/php.ini:
; Эта директива позволяет отключить определенные функции в целях безопасности.
; Она получает список имен функций, разделенных запятыми. Эта директива
; *НЕ* зависит от того, включен или выключен безопасный режим.
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-functions
disable_functions =
Убедитесь, что exec не определен следующим образом:
disable_functions=exec
Если это так, то просто удалите эту строку и перезапустите apache.
Для облегчения отладки я обычно запускаю файл php вручную (можно запросить вывод на большее число ошибок, не определяя их в основном ini). Для этого добавьте заголовок:
#!/usr/bin/php
ini_set("display_errors", 1);
ini_set("track_errors", 1);
ini_set("html_errors", 1);
error_reporting(E_ALL);
в начало файла, дайте им права доступа chmod +x myscript.php и выполните ./myscript.php. Надо быть осторожным при выполнении данных операций, особенно на загруженном сервере, который много пишет в файл журнала.
И еще дополнительно: это похоже на проблемы с разрешениями. Создайте сценарий bash, который делает что-нибудь простое, echo "hello world",и попробуйте его запустить. Убедитесь, что у вас есть разрешения для файла и для папки, содержащей файл.
Ответ 2
Поскольку вы выходите из контекста PHP в собственную оболочку, у вас будет много проблем с отладкой.
Лучшее и самое надежное, что я использовал, — это запись вывода скрипта в файл журнала и его отслеживание во время выполнения PHP.
<?php
shell_exec("filename > ~/debug.log 2>&1");
Затем в отдельной оболочке:
tail -200f ~/debug.log
Когда вы выполняете свой PHP-скрипт, ваши ошибки и выходные данные вашего вызова оболочки будут отображаться в вашем файле debug.log.
Ответ 3
Вот несколько вариантов решения вашей проблемы:
-
Для отладки всегда оборачивайте вашу функцию exec/shell_exec в var_dump().
-
error_reporting(-1); должен быть включен, как и display_errors, в крайнем случае даже set_error_handler("var_dump"); — хотя бы для того, чтобы проверить, не вызвал ли сам PHP execvp или что-то еще.
-
Используйте 2>&1(объедините оболочки STDERR с потоком STDOUT), чтобы узнать, почему вызов не удался.
В некоторых случаях вам может потребоваться заключить вашу команду в дополнительный вызов оболочки:
// захват потока STDERR через стандартную оболочку
echo shell_exec("/bin/sh -c 'ffmpeg -opts 2>&1' ");
-
Чередуйте различные функции exec для выявления сообщений об ошибках. Хотя в основном они делают одно и то же, пути возврата выходных данных различаются:
- exec()— либо возвращает результат как результат функции, либо через необязательный параметр $output.
Также предоставляет параметр $return_var, который содержит код ошибки/код выхода из запущенного приложения или оболочки. Вы можете получить:
- ENOENT (2) — Нет такого файла
- EIO (127) — Ошибка ввода-вывода: файл не найден
// выполнение команды, сопряженный с stderr, output + код ошибки
var_dump(exec("ffmpeg -h 2>&1", $output, $errno), $output, $errno));
-
shell_exec()— это то, что вы хотите запускать в основном для выражений в стиле shell.
Обязательно назначьте/распечатайте возвращаемое значение, например, так: var_dump(shell_exec("..."));
``встроенные обратные кавычки → идентичны shell_exec.
-
system()— аналогичен exec, но всегда возвращает результат как результат функции. Дополнительно позволяет фиксировать код результата.
-
passthru()— еще одна альтернатива exec, но всегда отправляет любые результаты в STDOUT (выходной буфер PHP). Это часто делает его наиболее подходящей альтернативой exec.
-
popen() или лучше proc_open()— разрешает отдельно захватывать STDOUT и STDERR.
-
Большинство ошибок оболочки попадают в журнал ошибок PHP или Apache, если их не перенаправить. Проверьте свой системный журнал или журнал Apache, если ничего не дает полезных сообщений об ошибках.
Наиболее распространенные проблемы:
-
Для устаревших тарифных планов веб-хостинга все еще может быть включен safe_mode или disable_functions. Ни одна из функций PHP exec не будет работать (лучше всего найти лучшего провайдера, иначе изучите "CGI" — но не устанавливайте свой собственный интерпретатор PHP, пока не разберетесь).
-
Точно так же иногда могут быть установлены AppArmor/SELinux/Firejail. Они ограничивают способность каждого приложения порождать новые процессы.
-
Предполагаемый двоичный файл не существует. Практически ни у одного веб-хоста нет предустановленных инструментов вроде ffmpeg. Вы не можете просто запускать произвольные команды shell без подготовки. Некоторые вещи должны быть установлены!
-
PATH отключен. Если вы установили пользовательские инструменты, вам нужно убедиться, что они доступны. Использование var_dump(shell_exec("ffmpeg -opts")) выполнит поиск по всем общим путям, или как было сказано/ограничено Apache (часто только /bin:/usr/bin).
-
Проверьте с помощью print_r($_SERVER);, что содержит ваш PATH и покрывает ли он инструмент, который вы хотели запустить. В противном случае вам может понадобиться изменить настройки сервера (/etc/apache2/envvars) или использовать полные пути:
// запуск с абсолютными путями к двоичным файлам
var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'"));
Это в некоторой степени подрывает концепцию shell. Лично я не считаю это предпочтительным. Однако это имеет смысл в целях безопасности; более того, конечно, при использовании пользовательских установок.
Дополнительно:
-
Для того чтобы запустить двоичный файл в системе BSD/Linux, его необходимо сделать "исполняемым". Именно это делает chmod a+x ffmpeg.
-
Кроме того, путь к таким пользовательским двоичным файлам должен быть доступен для чтения пользователю Apache, под которым работают ваши PHP-скрипты.
-
Более современные установки используют встроенный в PHP режим FPM (suexec+FastCGI), где учетная запись вашего хостинга равна той, под которой работает PHP.
-
Протестируйте с помощью SSH. Это само собой разумеется, но прежде чем выполнять команды через PHP, было бы разумно протестировать его в реальной оболочке. Проверьте, например, ldd ffmpeg, есть ли все lib-зависимости и работает ли он в противном случае.
-
Используйте namei -m /Usr/local/bin/ffmpeg для проверки всего пути, если не уверены, что могут возникнуть проблемы с разрешением доступа.
-
Входные значения (GET, POST, имена ФАЙЛОВ, данные пользователя), передаваемые в качестве аргументов команд в строках exec, должны быть экранированы с помощью escapeshellarg().
$q = "escapeshellarg";
var_dump(shell_exec("echo { $q($_GET['text']) } | wc"));
-
Следите за тем, чтобы не комбинировать обратные символы с любой из функций *exec():
$null = shell_exec(`wc file.txt`);
Обратные символы выполнят команду и оставят shell_exec с выводом уже выполненной команды. Используйте обычные кавычки для обертывания параметра команды.
Также проверьте в сеансе shell, как предполагаемая программа работает с другой учетной записью:
sudo -u www-data gpg –k
В частности для PHP-FPM проверяйте с соответствующим идентификатором пользователя. www-data/apache в основном используются только в старых настройках mod_php.
-
Многие инструменты cmdline зависят от некоторой конфигурации для каждого пользователя. Этот тест часто показывает, чего не хватает.
-
Вы не можете получить вывод для фоновых процессов, запущенных с помощью ... & или nohup ..... В таких случаях вам определенно нужно использовать перенаправление файла журнала exec("cmd > log.txt 2>&1 &");