PHP读取shell_exec实时输出

PHP读取shell_exec实时输出,php,Php,我只是在Linux服务器上试用PHP和shell\u exec。这是一个非常酷的功能使用,我真的很喜欢到目前为止。有没有办法查看命令运行时正在进行的实时输出 例如,如果在ping目标地址时运行了ping stackoverflow.com,那么每次ping时都会使用PHP显示结果?可能吗 我希望看到缓冲区运行时的实时更新。也许这是不可能的,但肯定会很好 这就是我正在尝试的代码,我尝试过的每一种方法都会在命令完成后显示结果 <?php $cmd = 'ping -c 10 127.0.

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

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

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

这就是我正在尝试的代码,我尝试过的每一种方法都会在命令完成后显示结果

<?php

  $cmd = 'ping -c 10 127.0.0.1';

  $output = shell_exec($cmd);

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

?>

我试着把
echo
部分放在一个循环中,但仍然没有成功。有没有人建议让它在屏幕上显示实时输出,而不是等到命令完成


我试过
exec
shell\u exec
system
passthru
。每个人都会在完成后显示内容。除非我使用了错误的语法或者我没有正确设置循环。

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

但是,如果您只想将结果直接转储给用户,您可以直接使用
passthru()

echo';
passthru($cmd);
回声';
如果要在程序运行时显示输出,可以执行以下操作:

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

if($result['exit_status'] === 0){
   // do something if command execution succeeds
} else {
    // do something on failure
}
while(@ob_end_flush());//结束所有输出缓冲区(如果有)
$proc=popen($cmd,'r');
回声';
而(!feof($proc))
{
echo-fread($proc,4096);
@冲洗();
}
回声';

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

首先,感谢Havenard提供的代码片段,它帮助了很多

哈夫纳德代码的一个稍加修改的版本,我发现它很有用


如果您愿意下载依赖项,请执行此操作。我发现使用这个清洁器的界面比自己用
popen()
passthru()
重新发明任何东西都好

这由Symfony文档提供:

您还可以将Process类与foreach构造一起使用来获取 生成时的输出。默认情况下,循环等待新的 在进入下一个迭代之前输出:

作为警告,PHP和Nginx在将输出发送到浏览器之前尝试缓冲时遇到了一些问题。您可以通过在PHP.ini中关闭输出缓冲来禁用PHP中的输出缓冲:
output\u buffering=off
。显然有很多问题,但为了避免麻烦,我最终使用了PHP内置服务器进行测试


我在Gitlab上给出了一个完整的例子:

为什么不先在shell中执行该文件?使用passthru()而不是shell_exec(),我现在就研究passthru。我在研究passthru()的时候发现了一个类似的代码,但我一定把它搞糟了。我试了大约一个小时让它工作。谢谢你,这正是我想要的,工作完美。是的,诀窍是强制执行根本不会发生缓冲。这段代码确保了这一点。通常,PHP只会在累积至少4KB的数据时刷新输出。从python进程捕获输出时,需要禁用输出缓冲:python-u/path/to/watch。。。或者PYTHONUNBUFFERED=1 watch…@erikvande即使在这种情况下,您也可能希望查看
mkfifo()
。如果您在Nginx中,您还应该添加
头('X-Accel-Buffering:no')
以确保针对单个响应关闭gzip和fastcgi_缓冲。我想知道为什么这段代码不起作用,这就是为什么。对于整个.sh脚本,这段代码能起作用吗?我想得到一个从PHP调用的.sh脚本的即时反馈?请看我的问题:它会起作用的。类似于:liveExecuteCommand(“sh/path/to/script.sh”);好极了这正是我想要的。不过有一个小建议:在exit_状态下抛出一个intval(…),以整数而不是字符串的形式返回。非常有用。请不要使用尾随分号编写shell命令,否则
exit_状态将始终为0。是的,在Nginx中,您还应该执行
头('X-Accel-Buffering:no')
以确保针对单个响应关闭gzip和fastcgi_缓冲,而不是针对所有请求关闭它。我花了太长时间才弄明白。
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>';
<?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
}
$process = new Process('ls -lsa');
$process->start();

foreach ($process as $type => $data) {
    if ($process::OUT === $type) {
        echo "\nRead from stdout: ".$data;
    } else { // $process::ERR === $type
        echo "\nRead from stderr: ".$data;
    }
}