zaLinux.ru

Вывод в реальном времени результатов выполнения shell_exec в PHP  


Для чтения вывода процесса используется popen(). Она позволяет PHP скрипту работать параллельно с определённой программой и даёт возможность взаимодействовать с ней, читать и записывать во вывод/ввод программы будто бы в файл.

Допустим, мы хотим запустить в операционной системе, где установлен веб-сервер, такую команду:

ping -c 10 zalinux.ru

Тогда в PHP скрипте мы присваиваем переменной значение, которое будет отправлено в ОС для выполнения в качестве команды:

$cmd = 'ping -c 10 zalinux.ru';

Если мы хотим просто получить результат и вывод в реальном времени нас не интересует, тогда можно использовать passthru():

echo '<pre>';
passthru($cmd);
echo '</pre>';

Но если вы хотите отображать вывод в реальном времени пока работает программа, то можно сделать так:

while (@ ob_end_flush()); // если есть, прекращает все буферы вывода

$proc = popen($cmd, 'r');
echo '<pre>';
while (!feof($proc))
{
    echo fread($proc, 4096);
    @ flush();
}
echo '</pre>';

Этот код запустит команду и будет отправлять пользователь её вывод в реальном времени.

Подсказки использования 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

В файл

sudo vim /etc/sudoers

Добавить (раскомментировать) строчку:

%wheel ALL=(ALL) NOPASSWD: ALL

3.

Помните, что shell_exec() does не захватывает STDERR (стандартный вывод ошибок), поэтому используйте "2>&1" для его перенаправления в STDOUT (стандартный вывод) и захвата.

4.

Простой способ захватить STDERR (стандартный вывод ошибок) и отбросить STDOUT (стандартный вывод) это добавить '2>&1 1> /dev/null' к концу вашей команды


Например:

<?php
$output = shell_exec('ls file_not_exist 2>&1 1> /dev/null');
?>

5.

Как shell_exec, так и обратная кавычка (`) возвращают NULL, если выполняемая команда не выводит что-либо.

Это позволяет нам делать примерно такие трюки:

shell_exec ("silentcmd && echo ' '");

Здесь мы просто выводим пустой пробел если команда завершилась успешно, что удовлетворяет это слегка странной проблеме. Отсюда вы можете использовать trim() для вывода команды.

6.

Ошибка Subversion "svn: Can't recode string" может быть вызвана неправильной (отсутствующей) локалью (locale). Попробуйте

<?php
putenv('LANG=en_US.UTF-8');
?>

(или любую другую локаль, какую вы предпочитаете) перед вызовом shell_exec()


Рекомендуемые статьи:

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *