我只是在我的Linux服务器上试验PHP和shell_exec
。这是一个非常酷的功能,到目前为止我真的很享受它。有没有办法查看命令运行时正在进行的实时输出?
例如,如果运行了ping stackoverflow.com
,那么在ping目标地址时,每次ping时,都会用PHP显示结果?这可能吗?
我很想看到缓冲区正在运行时的实时更新。也许这是不可能的,但肯定会很好。
这是我正在尝试的代码,我尝试过的每一种方法总是在命令完成后显示结果。
<?php
$cmd = 'ping -c 10 127.0.0.1';
$output = shell_exec($cmd);
echo "<pre>$output</pre>";
?>
我已经尝试将echo
部分放在一个循环中,但仍然没有运气。任何人都有任何关于让它在屏幕上显示实时输出而不是等到命令完成的建议吗?
我已尝试exec
,shell_exec
,system
和passthru
。它们中的每个人都在完成后显示内容。除非我使用错误的语法或者我没有正确设置循环。
答案 0 :(得分:75)
要阅读流程的输出,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>';
此代码应运行命令并在运行时将输出直接推送给最终用户。
答案 1 :(得分:21)
首先,感谢Havenard提供的片段 - 它帮助了很多!
我发现有用的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)
);
}
?>
样本用法:
$result = liveExecuteCommand('ls -la');
if($result['exit_status'] === 0){
// do something if command execution succeeds
} else {
// do something on failure
}
答案 2 :(得分:4)
如果您愿意下载依赖项,Symfony's processor component会执行此操作。我找到了使用此清洁工的界面,而不是使用popen()
或passthru()
重新创建任何内容。
这是由Symfony文档提供的:
您也可以使用带有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; } }
作为警告,我遇到了一些问题PHP和Nginx尝试在将输出发送到浏览器之前缓冲输出。您可以在php.ini中关闭PHP中的输出缓冲:output_buffering = off
。显然a way to disable it in Nginx,但我最终使用PHP内置服务器进行测试以避免麻烦。
我在Gitlab上提出了一个完整的例子:https://gitlab.com/hpierce1102/web-shell-output-streaming