PHP 读取shell_exec实时输出

php
2022-08-30 09:55:43

我只是在尝试PHP和我的Linux服务器。这是一个非常酷的功能,到目前为止,我真的很喜欢它。有没有办法查看命令运行时正在进行的实时输出?shell_exec

例如,如果运行了,当它ping目标地址时,每次ping时,都会用PHP显示结果?这可能吗?ping stackoverflow.com

我很想看到缓冲区正在运行时的实时更新。也许这是不可能的,但它肯定会很好。

这是我正在尝试的代码,我尝试过的每种方式都始终在命令完成后显示结果。

<?php

  $cmd = 'ping -c 10 127.0.0.1';

  $output = shell_exec($cmd);

  echo "<pre>$output</pre>";

?>

我尝试过将零件放入循环中,但仍然没有运气。有人对让它向屏幕显示实时输出而不是等到命令完成有任何建议吗?echo

我已尝试 、 、 和 。他们每个人都在完成后显示内容。除非我使用了错误的语法,或者我没有正确设置循环。execshell_execsystempassthru


答案 1

读取流程的输出是要走的路。您的脚本将与程序并行运行,您可以通过读取和写入其输出/输入来与它进行交互,就好像它是一个文件一样。popen()

但是,如果您只想将其结果直接转储给用户,则可以切入追逐并使用:passthru()

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

如果要在程序运行时显示输出,可以执行以下操作:

while (@ ob_end_flush()); // end all output buffers if any

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

此代码应运行该命令,并在运行时将输出直接推送给最终用户。

更多有用信息

请注意,如果您使用的是会话,那么运行其中一个会话将阻止用户加载其他页面,因为会话强制要求不会发生并发请求。若要防止这成为问题,请在循环之前调用。session_write_close()

如果您的服务器位于nginx网关后面,则nginx缓冲可能会破坏所需的行为。将标头设置为提示nginx它不应该这样做。由于首先发送标头,因此必须在脚本的开头调用它,然后再发送任何数据。header('X-Accel-Buffering: no');


答案 2

首先,感谢Havedard的片段 - 它帮助很大!

哈弗纳德代码的略微修改版本,我发现它很有用。

<?php
/**
 * Execute the given command by displaying console output live to the user.
 *  @param  string  cmd          :  command to be executed
 *  @return array   exit_status  :  exit status of the executed command
 *                  output       :  console output of the executed command
 */
function liveExecuteCommand($cmd)
{

    while (@ ob_end_flush()); // end all output buffers if any

    $proc = popen("$cmd 2>&1 ; echo Exit status : $?", 'r');

    $live_output     = "";
    $complete_output = "";

    while (!feof($proc))
    {
        $live_output     = fread($proc, 4096);
        $complete_output = $complete_output . $live_output;
        echo "$live_output";
        @ flush();
    }

    pclose($proc);

    // get exit status
    preg_match('/[0-9]+$/', $complete_output, $matches);

    // return exit status and intended output
    return array (
                    'exit_status'  => intval($matches[0]),
                    'output'       => str_replace("Exit status : " . $matches[0], '', $complete_output)
                 );
}
?>

样品用法 :

$result = liveExecuteCommand('ls -la');

if($result['exit_status'] === 0){
   // do something if command execution succeeds
} else {
    // do something on failure
}

推荐