Для чтения вывода процесса используется 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()
Связанные статьи:
- Как получить User Agent в PHP. Как настроить browscap.ini (100%)
- Как в PHP 8 показать все ошибки (100%)
- Ошибка «No such file or directory: AH02454: FCGI: attempt to connect to Unix domain socket /run/php/php8.1-fpm.sock (*:80) failed» (РЕШЕНО) (100%)
- Изменение в директиве upload_max_filesize в php.ini на Linux не имеют эффекта (разрешение проблемы) (50%)
- Решение проблемы с ошибкой Symbolic link not allowed или link target not accessible (50%)
- Как изменить адрес страницы входа в phpMyAdmin (RANDOM - 50%)