Web

Отладка проблем с функцией exec

Команда 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 для выявления сообщений об ошибках. Хотя в основном они делают одно и то же, пути возврата выходных данных различаются:

  1. exec()— либо возвращает результат как результат функции, либо через необязательный параметр $output.

Также предоставляет параметр $return_var, который содержит код ошибки/код выхода из запущенного приложения или оболочки. Вы можете получить:

  • ENOENT (2) — Нет такого файла
  • EIO (127) — Ошибка ввода-вывода: файл не найден

// выполнение команды, сопряженный с stderr, output + код ошибки

var_dump(exec("ffmpeg -h 2>&1", $output, $errno), $output, $errno));

 

  1. shell_exec()это то, что вы хотите запускать в основном для выражений в стиле shell.
    Обязательно назначьте/распечатайте возвращаемое значение, например, так: var_dump(shell_exec("..."));

`встроенные обратные кавычки → идентичны shell_exec.

  1. system()аналогичен exec, но всегда возвращает результат как результат функции. Дополнительно позволяет фиксировать код результата.

  2. passthru()еще одна альтернатива exec, но всегда отправляет любые результаты в STDOUT (выходной буфер PHP). Это часто делает его наиболее подходящей альтернативой exec.

  3. popen() или лучше proc_open()разрешает отдельно захватывать STDOUT и STDERR.

  • Большинство ошибок оболочки попадают в журнал ошибок PHP или Apache, если их не перенаправить. Проверьте свой системный журнал или журнал Apache, если ничего не дает полезных сообщений об ошибках.

Наиболее распространенные проблемы:

  1. Для устаревших тарифных планов веб-хостинга все еще может быть включен safe_mode или disable_functions. Ни одна из функций PHP exec не будет работать (лучше всего найти лучшего провайдера, иначе изучите "CGI" но не устанавливайте свой собственный интерпретатор PHP, пока не разберетесь).

  2. Точно так же иногда могут быть установлены AppArmor/SELinux/Firejail. Они ограничивают способность каждого приложения порождать новые процессы.

  3. Предполагаемый двоичный файл не существует. Практически ни у одного веб-хоста нет предустановленных инструментов вроде ffmpeg. Вы не можете просто запускать произвольные команды shell без подготовки. Некоторые вещи должны быть установлены!

  4. PATH отключен. Если вы установили пользовательские инструменты, вам нужно убедиться, что они доступны. Использование var_dump(shell_exec("ffmpeg -opts")) выполнит поиск по всем общим путям, или как было сказано/ограничено Apache (часто только /bin:/usr/bin).

  5. Проверьте с помощью print_r($_SERVER);, что содержит ваш PATH и покрывает ли он инструмент, который вы хотели запустить. В противном случае вам может понадобиться изменить настройки сервера (/etc/apache2/envvars) или использовать полные пути: 

// запуск с абсолютными путями к двоичным файлам

var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'"));

 

Это в некоторой степени подрывает концепцию shell. Лично я не считаю это предпочтительным. Однако это имеет смысл в целях безопасности; более того, конечно, при использовании пользовательских установок.

Дополнительно:

  1. Для того чтобы запустить двоичный файл в системе BSD/Linux, его необходимо сделать "исполняемым". Именно это делает chmod a+x ffmpeg.

  2. Кроме того, путь к таким пользовательским двоичным файлам должен быть доступен для чтения пользователю Apache, под которым работают ваши PHP-скрипты.

  3. Более современные установки используют встроенный в PHP режим FPM (suexec+FastCGI), где учетная запись вашего хостинга равна той, под которой работает PHP.

  4. Протестируйте с помощью SSH. Это само собой разумеется, но прежде чем выполнять команды через PHP, было бы разумно протестировать его в реальной оболочке. Проверьте, например, ldd ffmpeg, есть ли все lib-зависимости и работает ли он в противном случае.

  5. Используйте namei -m /Usr/local/bin/ffmpeg для проверки всего пути, если не уверены, что могут возникнуть проблемы с разрешением доступа.

  6. Входные значения (GET, POST, имена ФАЙЛОВ, данные пользователя), передаваемые в качестве аргументов команд в строках exec, должны быть экранированы с помощью escapeshellarg().

$q = "escapeshellarg";

var_dump(shell_exec("echo {$q($_GET['text'])} | wc"));

 

  1. Следите за тем, чтобы не комбинировать обратные символы с любой из функций *exec():

$null = shell_exec(`wc file.txt`);

Обратные символы выполнят команду и оставят shell_exec с выводом уже выполненной команды. Используйте обычные кавычки для обертывания параметра команды.

Также проверьте в сеансе shell, как предполагаемая программа работает с другой учетной записью: 

sudo -u www-data gpg –k

В частности для PHP-FPM проверяйте с соответствующим идентификатором пользователя. www-data/apache в основном используются только в старых настройках mod_php.

  1. Многие инструменты cmdline зависят от некоторой конфигурации для каждого пользователя. Этот тест часто показывает, чего не хватает.

  2. Вы не можете получить вывод для фоновых процессов, запущенных с помощью ... & или nohup ..... В таких случаях вам определенно нужно использовать перенаправление файла журнала exec("cmd > log.txt 2>&1 &");

Схожие статьи

Web

Как выполнить многократную вставку в базу данных с помощью запроса foreach insert в mysql

Web

Распаковка файла с помощью php

Что делает руководитель веб-разработки в рамках своей должности?
Web

Что делает руководитель веб-разработки в рамках своей должности?

Web

Как установить расширения для Chrome в Opera?

×