php PHP读取shell_exec实时输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20107147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP reading shell_exec live output
提问by Palumbo Software
I'm just experimenting with PHP and shell_execon my Linux server. 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?
我只是shell_exec在我的 Linux 服务器上试验 PHP 。这是一个非常酷的功能,到目前为止我真的很喜欢它。有没有办法在命令运行时查看正在进行的实时输出?
For example, if ping stackoverflow.comwas run, while it is pinging the target address, every time it pings, show the results with PHP? Is that possible?
比如ping stackoverflow.com运行了,在ping目标地址的时候,每次ping都用PHP显示结果?那可能吗?
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 echopart in a loop but still no luck. Anyone have any suggestions on making it show the live output to the screen instead of waiting until the command is complete?
我试过把这个echo部分放在一个循环中,但仍然没有运气。任何人对让它在屏幕上显示实时输出而不是等到命令完成有什么建议吗?
I've tried exec, shell_exec, system, and passthru. 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.
我试过exec, shell_exec, system, 和passthru。他们每个人都在完成后显示内容。除非我使用了错误的语法或者我没有正确设置循环。
回答by Havenard
To read the output of a process, popen()is the way to go. 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.
读取进程的输出,popen()是要走的路。您的脚本将与程序并行运行,您可以通过读写它的输出/输入来与它进行交互,就好像它是一个文件一样。
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.
此代码应运行命令并在运行时将输出直接推送给最终用户。
回答by Amith
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
}
回答by HPierce
If you're willing to download a dependency, Symfony's processor componentdoes this. I found the interface to working with this cleaner than reinventing anything myself with popen()or passthru().
如果您愿意下载依赖项,Symfony 的处理器组件会执行此操作。我发现使用这个更干净的界面而不是用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. 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; } }
您还可以使用带有 foreach 构造的 Process 类在生成时获取输出。默认情况下,循环在进入下一次迭代之前等待新的输出:
$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. You can disable output buffering in PHP by turning it off in php.ini: 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.
作为警告,我遇到了一些问题,PHP 和 Nginx 在将输出发送到浏览器之前尝试缓冲输出。您可以通过在 php.ini: 中将其关闭来禁用 PHP 中的输出缓冲output_buffering = off。显然有一种方法可以在 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

