Внимание! Все обсуждения относятся к запуску PHP в режиме CLI, а не в качестве модуля веб-сервера! Если вы когда-либо использовали функцию system() в PHP, вы, вероятно, задавались вопросом: как system() возвращает последнюю строку команды, а также выводит результаты выполнения команды на веб-страницу, а не куда-нибудь в стандартный веб-интерфейс? -серверы? И почему system() работает иначе, чем system() в C? Ответ, в общем-то, проще, чем может показаться.
Фактически, system() в PHP использует ту же функцию, что и exec() ( int php_exec (тип int, char *cmd, pval *array, pval *return_value TSRMLS_DC) ), он просто выводит результат построчно, не накапливая его в массив, как exec(), а используя в качестве буфера только строку.
Кстати, на такое поведение намекает документация к функции system():
Вызов system() также пытается автоматически очистить выходной буфер веб-сервера после каждой строки вывода, если PHP работает как серверный модуль.А php_exec по сути использует popen() для выполнения соответствующей команды, а это означает, что существует вероятность того, что вызываемая программа может не распознать STDIN как терминал и выдать ответ в другом формате, чем при запуске через оболочку.
Решение проблемы с буферизацией строк system()
Если вы просто хотите, чтобы информация отображалась по мере ее поступления, а не накапливалась построчно, вы можете просто использовать passthru вместо system. Этого достаточно, чтобы, скажем, git clone корректно отображал ход выполнения операции, но при этом ls всё равно будет отображать информацию в одном столбце, так как, по сути, passthru тоже использует php_exec, а значит popen, со всеми вытекающие последствияВариант решения с proc_open()
Если вы хотите, скажем, ls выводить информацию так же, как при запуске из терминала, а также если вам нужна поддержка цвета, вы можете использовать proc_open:$handle = proc_open("ls", array(0=>STDIN,1=>STDOUT,2=>STDERR), $pipes); $retval = proc_close($handle);
UNIX-путь
В принципе, вышеописанных методов должно быть достаточно, чтобы все у вас заработало.
Но если вам нужны какие-то особые извращения, или вы хотите полностью контролировать то, что происходит при запуске программы, то можно попробовать решить эту проблему старым UNIX-путем: через fork-exec (это будет работать только под *nix и при наличии расширение pcntl): function libcSystem($cmd) {
$pid = pcntl_fork();
if($pid < 0) {
return -1;
}
if($pid == 0) {
pcntl_exec('/bin/sh', array('-c', $cmd), $_ENV);
exit(127);
}
pcntl_waitpid($pid, $status);
return pcntl_wexitstatus($status);
}
Я надеюсь, что эта статья будет полезна тем, кто пишет PHP-скрипты для CLI и хочет понять, как заставить system() работать так, как должно работать в теории.
Теги: #php #system #system #C++ #passthru #proc_exec #php
-
Вышел Untangle Gateway, Версия 6.1
19 Oct, 24 -
Разбор Простой Капчи (C#)
19 Oct, 24 -
Игры И Люди
19 Oct, 24 -
Чего Не Знал Гордон Мур
19 Oct, 24 -
Bookradar.org — Сервис Поиска Книг
19 Oct, 24