Захватывать результаты из php exec(), пока команда все еще выполняется?

#php #exec

#php #exec

Вопрос:

Когда я запускаю exec из PHP вот так:

 $result = exec('command');
  

Результаты этого будут сохранены в $result . Но в моем текущем случае моя команда может занять несколько минут и выводит результаты по мере выполнения. Есть ли способ получить выходные данные во время ее выполнения? Я знаю, что passthru метод будет выводить результаты в браузере, но на самом деле я хочу это напрямую.

Комментарии:

1. возможно использовать CGI вместо PHP?

Ответ №1:

Вам следует взглянуть на proc_open

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

-Редактировать- Если вы используете

 $result = exec('command > /path/to/file amp;');
  

Она будет выполняться в фоновом режиме, и вы можете прочитать выходные данные в /path/to/file

Ответ №2:

Возможно, не лучший способ сделать это (но сработал для меня):

 <?php

$cmd = "ping 127.0.0.1 -c 5"; //example command

$descriptorspec = array(
    0 => array("pipe", "r"), 
    1 => array("pipe", "w"), 
    2 => array("pipe", "a")
);

$pipes = array();

$process = proc_open($cmd, $descriptorspec, $pipes, null, null);

echo "Start process:n";

$str = "";

if(is_resource($process)) {
    do {
        $curStr = fgets($pipes[1]);  //will wait for a end of line
        echo $curStr;
        $str .= $curStr;

        $arr = proc_get_status($process);

    }while($arr['running']);
}else{
    echo "Unable to start processn";
}

fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

echo "nnnDonen";

echo "Result is:n----n".$str."n----n";

?>
  

Ответ №3:

укажите второй аргумент

 exec('command', $result);
  

Если аргумент вывода присутствует, то указанный массив будет
заполняется каждой строкой выходных данных команды. Завершающий
пробелы, такие как n, не включены в этот массив. Обратите внимание, что если
массив уже содержит некоторые элементы, exec() добавит к
конец массива. Если вы не хотите, чтобы функция добавляла элементы,
вызовите unset() для массива перед передачей его в exec().

Комментарии:

1. Спасибо, но, насколько я понимаю, для этого все еще требуется, чтобы exec полностью завершил работу, прежде чем я смогу получить результат. Я специально хочу получить выходные данные во время выполнения команды, чтобы я мог обновить индикатор выполнения.

2. @Zenox: а. в таком случае это невозможно. PHP не является асинхронным

Ответ №4:

Возможно, удастся достичь того, что вам нужно, используя passthru() в сочетании с буферизацией вывода. Хотя и не уверен.

Ответ №5:

Для тех, кому это может помочь, я использовал ответ Эдди и изменил его для своих целей (вывод файла дампа MySQL без заполнения оперативной памяти сервера)

 $dumpCommand = "mysqldump --skip-lock-tables -u $dbuser -p$dbpasswd $dbname";
$dumpFileName = 'backup_'.$dbname.'-'.date('Ymd-Hi').'.sql';

$descriptorSpec = array(
    0 => array("pipe", "r"), 
    1 => array("pipe", "w"), 
    2 => array("pipe", "a")
);

$pipes = array();

$process = proc_open($dumpCommand, $descriptorSpec, $pipes, null, null);

if(!is_resource($process)) {
    die('Unable to start process');
}

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$dumpFileName.'"');

do {
    echo fgets($pipes[1]); // Will wait for EOL
    $arrStatus = proc_get_status($process);
} while($arrStatus['running']);

fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);