用PHP实时输出运行进程

我正在试图在网页上运行一个进程,实时返回它的输出。 例如,如果我运行“ping”过程,它应该每次更新我的页面,当它返回一个新行(现在,当我使用exec(命令,输出)我强迫使用-c选项,并等待,直到进程完成看到输出在我的网页上)。 是否有可能在PHP中做到这一点?

我也想知道当有人离开这个页面时,什么是正确的方法来杀死这种过程。 在“ping”过程的情况下,我仍然能够看到在系统监视器中运行的进程(什么是有道理的)。

这对我工作:

$cmd = "ping 127.0.0.1"; $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); flush(); $process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array()); echo "<pre>"; if (is_resource($process)) { while ($s = fgets($pipes[1])) { print $s; flush(); } } echo "</pre>"; 

这是一个很好的方式来显示你的shell命令的实时输出:

 <?php header("Content-type: text/plain"); // tell php to automatically flush after every output // including lines of output produced by shell commands disable_ob(); $command = 'rsync -avz /your/directory1 /your/directory2'; system($command); 

您将需要此function来防止输出缓冲:

 function disable_ob() { // Turn off output buffering ini_set('output_buffering', 'off'); // Turn off PHP output compression ini_set('zlib.output_compression', false); // Implicitly flush the buffer(s) ini_set('implicit_flush', true); ob_implicit_flush(true); // Clear, and turn off output buffering while (ob_get_level() > 0) { // Get the curent level $level = ob_get_level(); // End the buffering ob_end_clean(); // If the current level has not changed, abort if (ob_get_level() == $level) break; } // Disable apache output buffering/compression if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); apache_setenv('dont-vary', '1'); } } 

它不适用于我尝试过的每一个服务器上,但是我希望我可以提供关于在你的phpconfiguration中寻找什么的build议,以确定你是否应该拉你的头发试图让这种types的行为工作在你的服务器上! 其他人知道吗?

下面是一个简单的PHP示例:

 <?php header("Content-type: text/plain"); disable_ob(); for($i=0;$i<10;$i++) { echo $i . "\n"; usleep(300000); } 

我希望这能帮助那些在这里search的人。

这里描述了使用现代HTML5服务器端事件解决这个老问题的更好的解决scheme:

http://www.w3schools.com/html/html5_serversentevents.asp


例:

http://sink.agiletoolkit.org/realtime/console

代码: https : //github.com/atk4/sink/blob/master/admin/page/realtime/console.php#L40

(在Agile Toolkit框架中作为模块实现)

试试这个(在Windows机器上testing+ wamp服务器)

  header('Content-Encoding: none;'); set_time_limit(0); $handle = popen("<<< Your Shell Command >>>", "r"); if (ob_get_level() == 0) ob_start(); while(!feof($handle)) { $buffer = fgets($handle); $buffer = trim(htmlspecialchars($buffer)); echo $buffer . "<br />"; echo str_pad('', 4096); ob_flush(); flush(); sleep(1); } pclose($handle); ob_end_flush(); 

首先检查flush()是否适合你。 如果确实如此,那么很好,如果不行,可能意味着Web服务器由于某种原因正在缓冲,例如启用了mod_gzip。

对于像ping这样的东西,最简单的方法是在PHP中循环,多次运行“ping -c 1”,并在每次输出后调用flush()。 假设PHP被configuration为当用户closuresHTTP连接(这通常是默认的,或者你可以调用ignore_user_abort(false)来确保)closuresHTTP连接,那么你不需要担心失控的ping进程。

如果确实有必要只运行一次subprocess并持续显示其输出,那可能会更困难 – 您可能需要在后台运行它,将输出redirect到一个stream,然后让PHP回显那个stream回到用户身上,穿插着定期的flush()调用。

如果你想通过PHP来运行系统命令,请查看exec文档 。

我不会推荐在高stream量网站上做这个,但是为每个请求分配一个stream程是一个相当大的过程。 某些程序提供了将其进程ID写入文件的选项,以便您可以检查并终止进程,但是对于像ping这样的命令,我不确定这是否可行,请检查手册页。

只需在远程主机上打开希望监听的端口上的套接字(IE:端口80用于HTTP),就可以更好地为您服务,这样您就知道在用户空间以及networking上的一切进展顺利。

如果你试图输出二进制数据看看PHP的头function ,并确保你设置适当的内容types和内容处置 。 查看文档 ,了解有关使用/禁用输出缓冲区的更多信息。

对于命令行用法:

 function execute($cmd) { $proc = proc_open($cmd, [['pipe','r'],['pipe','w'],['pipe','w']], $pipes); while(($line = fgets($pipes[1])) !== false) { fwrite(STDOUT,$line); } while(($line = fgets($pipes[2])) !== false) { fwrite(STDERR,$line); } fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); return proc_close($proc); } 

如果你想运行一个文件,你可能需要先给它执行权限:

 chmod('/path/to/script',0755); 

我在Windows上尝试了各种PHP执行命令,发现它们有很大的不同。

  • 不要为stream操作: shell_execexecpassthru
  • 工作types: proc_openpopen – “kind of”,因为你不能传递参数给你的命令(即不会传递给my.exe --something ,将与_my_something.bat一起_my_something.bat )。

最好的(最简单的)方法是:

  1. 你必须确保你的exe文件正在刷新命令(见printf冲洗问题 )。 如果没有这个,你很可能会收到大约4096字节的文本,无论你做什么。
  2. 如果可以的话,使用header('Content-Type: text/event-stream'); (而不是header('Content-Type: text/plain; charset=...'); )。 这不会在所有的浏览器/客户端工作! 如果没有这个function,stream式传输将会起作用,但至less第一行将被浏览器缓冲。
  3. 你也可能想禁用cachingheader('Cache-Control: no-cache');
  4. closures输出缓冲(在php.ini中或ini_set('output_buffering', 'off'); )。 这可能也必须在Apache / Nginx /前面使用的任何服务器上完成。
  5. 打开压缩(在php.ini或ini_set('zlib.output_compression', false); )。 这可能也必须在Apache / Nginx /前面使用的任何服务器上完成。

所以在你的C ++程序中,你需要做类似的事情(同样,对于其他解决scheme,请参阅printf flush)问题 :

 Logger::log(...) { printf (text); fflush(stdout); } 

在PHP中,你可以这样做:

 function setupStreaming() { // Turn off output buffering ini_set('output_buffering', 'off'); // Turn off PHP output compression ini_set('zlib.output_compression', false); // Disable Apache output buffering/compression if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); apache_setenv('dont-vary', '1'); } } function runStreamingCommand($cmd){ echo "\nrunning $cmd\n"; system($cmd); } ... setupStreaming(); runStreamingCommand($cmd); 

尝试更改php.ini文件集“output_buffering =关”。 你应该能够得到页面上的实时输出使用系统命令而不是exec ..系统命令将刷新输出

检查了所有的答案,没有什么作品…

find解决scheme

它在Windows上工作(我认为这个答案是有帮助的用户在那里search)

 <?php $a = popen('ping www.google.com', 'r'); while($b = fgets($a, 2048)) { echo $b."<br>\n"; ob_flush();flush(); } pclose($a); ?>