简体   繁体   English

PHP读取shell_exec实时输出

[英]PHP reading shell_exec live output

I'm just experimenting with PHP and shell_exec on my Linux server.我只是在我的 Linux 服务器上试验 PHP 和shell_exec It's a really cool function to use and I am really enjoying it so far.这是一个非常酷的功能,到目前为止我真的很喜欢它。 Is there a way to view the live output that is going on while the command is running?有没有办法在命令运行时查看正在进行的实时输出?

For example, if ping stackoverflow.com was run, while it is pinging the target address, every time it pings, show the results with PHP?比如ping stackoverflow.com ,在ping目标地址的时候,每次ping都用PHP显示结果? Is that possible?那可能吗?

I would love to see the live update of the buffer as it's running.我很想看到缓冲区在运行时的实时更新。 Maybe it's not possible but it sure would be nice.也许这是不可能的,但肯定会很好。

This is the code I am trying and every way I have tried it always displays the results after the command is finished.这是我正在尝试的代码,我尝试过的每一种方式总是在命令完成后显示结果。

<?php

  $cmd = 'ping -c 10 127.0.0.1';

  $output = shell_exec($cmd);

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

?>

I've tried putting the echo part in a loop but still no luck.我试过把echo部分放在一个循环中,但仍然没有运气。 Anyone have any suggestions on making it show the live output to the screen instead of waiting until the command is complete?任何人对让它在屏幕上显示实时输出而不是等到命令完成有什么建议吗?

I've tried exec , shell_exec , system , and passthru .我试过execshell_execsystempassthru Everyone of them displays the content after it's finished.他们每个人都在完成后显示内容。 Unless I'm using the wrong syntax or I'm not setting up the loop correctly.除非我使用了错误的语法或者我没有正确设置循环。

To read the output of a process, popen() is the way to go.要读取进程的输出, popen()是要走的路。 Your script will run in parallel with the program and you can interact with it by reading and writing it's output/input as if it was a file.您的脚本将与程序并行运行,您可以通过读写它的输出/输入来与它进行交互,就好像它是一个文件一样。

But if you just want to dump it's result straight to the user you can cut to the chase and use passthru() :但是,如果您只想将结果直接转储给用户,您可以切入正题并使用passthru()

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

If you want to display the output at run time as the program goes, you can do this:如果你想在程序运行时在运行时显示输出,你可以这样做:

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>';

This code should run the command and push the output straight to the end user at run time.此代码应运行命令并在运行时将输出直接推送给最终用户。

First of all, thanks Havenard for your snippet - it helped a lot!首先,感谢 Havenard 提供的片段 - 它帮助很大!

A slightly modified version of Havenard's code which i found useful.我发现有用的 Havenard 代码的稍微修改版本。

<?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)
                 );
}
?>

Sample Usage :示例用法:

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

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

If you're willing to download a dependency, Symfony's processor component does this.如果您愿意下载依赖项, Symfony 的处理器组件会执行此操作。 I found the interface to working with this cleaner than reinventing anything myself with popen() or passthru() .我发现使用这个更干净的界面而不是用popen()passthru()自己重新发明任何东西。

This was provided by the Symfony documentation:这是由 Symfony 文档提供的:

You can also use the Process class with the foreach construct to get the output while it is generated.您还可以使用带有 foreach 构造的 Process 类来获取生成的输出。 By default, the loop waits for new output before going to the next iteration:默认情况下,循环在进入下一次迭代之前等待新的输出:

 $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; } }

As a warning, I've run into some problems PHP and Nginx trying to buffer the output before sending it to the browser.作为警告,我遇到了一些问题,PHP 和 Nginx 在将输出发送到浏览器之前尝试缓冲输出。 You can disable output buffering in PHP by turning it off in php.ini: output_buffering = off .您可以通过在 php.ini 中将其关闭来禁用 PHP 中的输出缓冲: output_buffering = off There's apparently a way to disable it in Nginx , but I ended up using the PHP built in server for my testing to avoid the hassle.显然有一种方法可以在 Nginx 中禁用它,但我最终使用 PHP 内置服务器进行测试以避免麻烦。

I put up a full example of this on Gitlab: https://gitlab.com/hpierce1102/web-shell-output-streaming我在 Gitlab 上提供了一个完整的例子: https ://gitlab.com/hpierce1102/web-shell-output-streaming

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM