- PHP: exec () не работает в фоновом режиме даже с помощью «> / dev / null 2> & 1 &»
- exec
- Возвращаемые значения
- Ошибки
- Список изменений
- Примеры
- Примечания
- Смотрите также
- User Contributed Notes 20 notes
- Вывод в реальном времени результатов выполнения shell_exec в PHP
- Подсказки использования shell_exec
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
PHP: exec () не работает в фоновом режиме даже с помощью «> / dev / null 2> & 1 &»
Вызов сценария (создает PDF-файл и отправляет его по электронной почте) работает, но процесс не работает в фоновом режиме (я проверил его с помощью инструкции сна внутри gutschein.php). Браузер висит до завершения выполнения gutschein.php.
Я также проверил следующее:
exec("/usr/bin/php gutschein.php >/dev/null 2>&1 &");
shell_exec("/usr/bin/php gutschein.php >/dev/null 2>&1 &");
Это ничего не меняет. Скрипт фактически работает на сервере linux. Кто-нибудь знает, что я делаю неправильно?
Попробуйте систему и / или passthru. У меня были проблемы с exec раньше, потому что он останавливается, пытаясь заполнить возвращаемый массив данными до тех пор, пока процесс не завершится.
Они будут воспроизводить исходный вывод так, что даже если они будут работать, вам может понадобиться обработать это с помощью отброшенного выходного буфера.
Вы можете использовать экран: screen -d -m /usr/bin/php gutschein.php
Вот экранное руководство, если вам нужна дополнительная информация о параметрах.
Посмотрите мой опыт в ЗДЕСЬ . То, как я стараюсь и работает для меня –
php -q /path/to/my/test/script/cli_test.php argument1 < /dev/null &
exec('php -q /path/to/my/test/script/cli_test.php argument1 < /dev/null &')
Все выходные данные должны быть перенаправлены, иначе скрипт будет висеть до тех пор, пока выполняется gutschein.php. Пытаться
exec('/usr/bin/php gutschein.php &> /dev/null &');
Можете ли вы попробовать одну из следующих двух команд для запуска фоновых заданий с PHP:
$out = shell_exec('nohup /usr/bin/php /path/to/gutschein.php >/dev/null 2>&1 &');
$pid = pclose(popen('/usr/bin/php gutschein.php', 'r'));
Он выполнит команду в фоновом режиме и вернет вам PID, который вы можете проверить с помощью условия $pid > 0 чтобы убедиться, что он сработал.
/** * @author Micheal Mouner * @param String $commandJob * @return Integer $pid */ public function PsExec($commandJob) < $command = $commandJob . ' >/dev/null 2>&1 & echo $!'; exec($command, $op); $pid = (int) $op[0]; if ($pid != "") return $pid; return false; >
Это сработало для меня .. проверьте это
также, return processId фонового процесса
Браузер может ожидать ответа, поэтому пусть ваш скрипт производит какой-либо вывод и завершает «основной процесс». просто
должен выполнять эту работу.
exec
Если параметр output указан, то массив будет заполнен строками вывода программы. Завершающие пробелы, такие как \n , не будут включены в массив. Обратите внимание, что если массив уже содержит какие-либо элементы, то exec() добавит новые элементы в конец массива. Если же вы не хотите, чтобы функция добавляла новые элементы в конец, вызовите unset() на этом массиве, прежде чем передать его в exec() .
Если аргумент result_code присутствует вместе с output , тогда статус возврата выполненной команды будет записан в этой переменной.
Возвращаемые значения
Последняя строка из результата команды. Если требуется выполнить команду и получить все данные команды без какой-либо обработки, используйте функцию passthru() .
Возвращает false в случае возникновения ошибки.
Для получения результата выполнения команды, убедитесь, что параметр output инициализирован и используется.
Ошибки
Выдаёт ошибку уровня E_WARNING , если функция exec() не может выполнить команду command .
Выбрасывает исключение ValueError , если параметр command не указан или содержит нулевые байты.
Список изменений
Версия | Описание |
---|---|
8.0.0 | Если параметр command не указан или содержит нулевые байты, функция exec() теперь выбрасывает исключение ValueError ; ранее она выдавала ошибку уровня E_WARNING и возвращала false . |
Примеры
Пример #1 Пример функции exec()
// выводит имя пользователя, от имени которого запущен процесс php/httpd
// (применимо к системам с командой "whoami" в системном пути)
$output = null ;
$retval = null ;
exec ( 'whoami' , $output , $retval );
echo "Вернёт статус $retval и значение:\n" ;
print_r ( $output );
?>?php
Результатом выполнения данного примера будет что-то подобное:
Вернёт статус 0 и значение: Array ( [0] => cmb )
Примечания
Если вы собираетесь передавать функции пользовательские данные, используйте функции escapeshellarg() или escapeshellcmd() для того, чтобы пользователи не смогли обмануть систему, запустив произвольную команду.
Замечание:
Если вы собираетесь использовать эту функцию в программе, работающей в качестве демона, убедитесь, что стандартный вывод функции направлен в файл или другой поток, в противном случае PHP зависнет вплоть до конца выполнения программы.
Замечание:
В Windows функция exec() стартует cmd.exe для запуска команды. Если вы хотите запустить внешнюю программу без запуска cmd.exe, то используйте функцию proc_open() с установленной опцией bypass_shell .
Смотрите также
- system() - Выполнить внешнюю программу и отобразить вывод
- passthru() - Выполнить внешнюю программу и отобразить необработанный вывод
- escapeshellcmd() - Экранировать метасимволы командной строки
- pcntl_exec() - Запустить указанную программу в области текущего процесса
- Оператор исполнения
User Contributed Notes 20 notes
This will execute $cmd in the background (no cmd window) without PHP waiting for it to finish, on both Windows and Unix.
function execInBackground ( $cmd ) <
if ( substr ( php_uname (), 0 , 7 ) == "Windows" ) <
pclose ( popen ( "start /B " . $cmd , "r" ));
>
else <
exec ( $cmd . " > /dev/null &" );
>
>
?>
(This is for linux users only).
We know now how we can fork a process in linux with the & operator.
And by using command: nohup MY_COMMAND > /dev/null 2>&1 & echo $! we can return the pid of the process.
This small class is made so you can keep in track of your created processes ( meaning start/stop/status ).
You may use it to start a process or join an exisiting PID process.
// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process ( 'ls -al' );
// or if you got the pid, however here only the status() metod will work.
$process = new Process ();
$process . setPid ( my_pid );
?>
// Then you can start/stop/ check status of the job.
$process . stop ();
$process . start ();
if ( $process . status ()) echo "The process is currently running" ;
>else echo "The process is not running." ;
>
?>
/* An easy way to keep in track of external processes.
* Ever wanted to execute a process in php, but you still wanted to have somewhat controll of the process ? Well.. This is a way of doing it.
* @compability: Linux only. (Windows does not work).
* @author: Peec
*/
class Process private $pid ;
private $command ;
public function __construct ( $cl = false ) if ( $cl != false ) $this -> command = $cl ;
$this -> runCom ();
>
>
private function runCom () $command = 'nohup ' . $this -> command . ' > /dev/null 2>&1 & echo $!' ;
exec ( $command , $op );
$this -> pid = (int) $op [ 0 ];
>
public function setPid ( $pid ) $this -> pid = $pid ;
>
public function getPid () return $this -> pid ;
>
public function status () $command = 'ps -p ' . $this -> pid ;
exec ( $command , $op );
if (!isset( $op [ 1 ]))return false ;
else return true ;
>
public function start () if ( $this -> command != '' ) $this -> runCom ();
else return true ;
>
public function stop () $command = 'kill ' . $this -> pid ;
exec ( $command );
if ( $this -> status () == false )return true ;
else return false ;
>
>
?>
Вывод в реальном времени результатов выполнения shell_exec в PHP
Для чтения вывода процесса используется popen(). Она позволяет PHP скрипту работать параллельно с определённой программой и даёт возможность взаимодействовать с ней, читать и записывать во вывод/ввод программы будто бы в файл.
Допустим, мы хотим запустить в операционной системе, где установлен веб-сервер, такую команду:
Тогда в PHP скрипте мы присваиваем переменной значение, которое будет отправлено в ОС для выполнения в качестве команды:
Если мы хотим просто получить результат и вывод в реальном времени нас не интересует, тогда можно использовать passthru():
Но если вы хотите отображать вывод в реальном времени пока работает программа, то можно сделать так:
while (@ ob_end_flush()); // если есть, прекращает все буферы вывода $proc = popen($cmd, 'r'); echo ''; while (!feof($proc)) < echo fread($proc, 4096); @ flush(); >echo '';
Этот код запустит команду и будет отправлять пользователь её вывод в реальном времени.
Подсказки использования shell_exec
1.
Если вы пытаетесь запустить команду вроде "gunzip -t" через shell_exec и получаете пустой результат, вам следует добавить 2>&1 к концу команды, например:
echo shell_exec("gunzip -c -t $path_to_backup_file");echo shell_exec("gunzip -c -t $path_to_backup_file 2>&1");Похоже, в примере выше, разрыв строки вывода gunzip препятствует shell_exec напечатать что-либо ещё.
2.
Быстрое напоминание тем, что пытается использовать shell_exec в UNIX-подобных платформах и не может заставить работать свой скрипт. В системе PHP делает запуск программ как веб-пользователь (обычно www, www-data или http для Apache), поэтому вам нужно убедиться, что веб-пользователь имеет достаточно прав для файлов, директорий или программ, которые вы пытаетесь использовать в команде shell_exec. В противном случае, будет казаться, что ничего не происходит.
Скорее всего неправильным (и точно опасным), но рабочим способом является добавление Apache прав запускать программы от имени суперпользователя без пароля.
Для Debian (и производных вроде Kali Linux, Linux Mint, Ubuntu) это делается так:
sudo usermod -a -G sudo www-dataВ файл /etc/sudoers
www-data ALL=(ALL) NOPASSWD: ALLДля Arch Linux / BlackArch это делается так:
sudo usermod -a -G wheel httpДобавить (раскомментировать) строчку:
%wheel ALL=(ALL) NOPASSWD: ALL3.
Помните, что shell_exec() does не захватывает STDERR (стандартный вывод ошибок), поэтому используйте "2>&1" для его перенаправления в STDOUT (стандартный вывод) и захвата.
4.
Простой способ захватить STDERR (стандартный вывод ошибок) и отбросить STDOUT (стандартный вывод) это добавить '2>&1 1> /dev/null' к концу вашей команды
5.
Как shell_exec, так и обратная кавычка (`) возвращают NULL, если выполняемая команда не выводит что-либо.
Это позволяет нам делать примерно такие трюки:
Здесь мы просто выводим пустой пробел если команда завершилась успешно, что удовлетворяет это слегка странной проблеме. Отсюда вы можете использовать trim() для вывода команды.
6.
Ошибка Subversion "svn: Can't recode string" может быть вызвана неправильной (отсутствующей) локалью (locale). Попробуйте
(или любую другую локаль, какую вы предпочитаете) перед вызовом shell_exec()