如何在PHP中实时获取Shell脚本的反馈?

3
我该如何在PHP中执行一个Shell脚本,并给浏览器提供实时反馈? 根据system函数的文档:
系统调用(system())会尝试在每行输出后自动刷新Web服务器的输出缓冲区,如果PHP作为服务器模块运行。
我不清楚他们所说的'服务器模块'是什么意思。
PHP代码示例:
<?php

system('/var/lib/script_test.sh');

示例 shell 代码:

#!/bin/bash

echo "Start..."
for i in {1..10}
do
        echo "$i..."
        sleep 1
done
echo "Done."

这段代码的作用:等待大约10秒钟,然后将内容刷新到输出缓冲区。

我希望它的作用是:在每行输出后将内容刷新到输出缓冲区。


服务器模块 = PHP嵌入在Web服务器内部(例如mod_php),而不是运行在“cgi”模式下。 - Marc B
2个回答

2
这可以通过使用popen()来完成,它会给你一个句柄,可以访问你打开的任何进程的stdout。使用ob_flush()可以将数据块发送到客户端,可以使用XHR显示数据。

当然,浏览器没有任何义务按原样显示它。实际上,最好的方法是使用ajax轮询或类似的方式,并以非阻塞的方式运行该进程。 - Tyler Eaves
@TylerEaves,好想法。虽然我正在使用 AJAX 调用来加载运行 shell 脚本的 PHP 页面,但如果我可以使用 popen() 来不断刷新,那对我的情况来说是理想的。 - Highway of Life
我在一个应用程序中实现了这个功能(不是 PHP),我的方法是在外部页面分配一个作业 ID,然后我有一个表格,结构为 jobid / message / timestamp(Unix 整数风格)。对于每一行/输出组,我都插入到消息表中。每秒钟(这是一个内部网络应用程序,因此延迟很低),我通过 AJAX 进行轮询,传递作业 ID 和上次处理的时间戳,并返回一个时间戳和文本的 JSON 数组。将文本添加到我的消息 div 上。完成。简单易懂。可以适用于多个用户。 - Tyler Eaves
@Highway of Life 是的,那就是想法。 - rook
在Internet Explorer中,XHR不允许您读取部分响应,因此在IE中,只有在shell脚本完全完成时,您才能获取页面上的信息。请参见:http://css.dzone.com/articles/partial-xmlhttprequest - MrCode

2

一种选择是在shell脚本中写入文件,在每个步骤中说明它所处的位置。在您的网页上,每隔X秒/分钟使用ajax调用。ajax调用将调用一个读取状态文件并返回状态或已完成步骤的PHP脚本。

这种方法的优点是页面实时信息将对多个访问者可用,而不仅仅是实际启动shell脚本的访问者。显然,这可能或可能不符合您的需求。

当然,缺点是ajax间隔越长,更新就越过时。


一个文件是冗余的,这就是为什么popen存在和stdout处理程序。 - rook
需要文件访问而不是popen的情况包括但不限于:跨脚本链接,实时数据提取和xhr结果广播。 - That Realty Programmer Guy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接