脚本执行时如何获取部分输出?

6

描述:

我有一个脚本,它需要较长时间执行多个操作。在通常情况下,PHP脚本的输出将在该脚本完全执行后发送。如果我的脚本需要很长时间才能响应用户,则可能会让用户感到失望。

问题解决:

假设我的脚本中有一个循环,将执行10次。每次执行后,我希望在浏览器输出"元素X完成。Y时间。" X和Y的值将发生变化。

问题:

有没有办法实现这种效果?也许可以通过从此脚本调用新脚本并通过AJAX向浏览器发送数据来实现。

还是说只能使用PHP实现来达到这种效果?

编辑:

我看到我要澄清这个问题。我希望这些信息动态出现在页面上。我已经尝试了输出缓冲区函数,但仍无法满足我的需求。以下是测试代码:

for ($i = 0; $i <= 10; $i++) {
    ob_start();
        
    echo "Output " . $i . "<br />";
        
    ob_flush(); //also only flush() etc.
    

    sleep(1);
}

为什么不在循环结束时使用 print 输出而不是返回输出? - symlink
打印?我不明白。假设我将输出回显到浏览器,与测试代码进行比较。 - Xarvalus
可能是"Transfer-Encoding: chunked" header in PHP的重复问题。 - Kemal Fadillah
@Xarvalus 在我评论的时候你还没有添加测试代码。现在我看到你正在循环内部使用echo,而不是连接和返回$output。当然,你仍然需要使用flush() - symlink
3个回答

6

是的,只用PHP就可以实现这个目标。我记得在一段时间前我正在追踪WordPress时看到了一些相关代码。当它更新模块时,需要FTP、解压、复制文件等操作,这需要很长时间,而它喜欢让用户知道它正在做什么。在检查他们的send_message()函数并阅读PHP的ob_flush()页面后,我认为你想要的是:

echo "stuff\n"; // adding a newline may be important here,
                // a lot of io routines use some variant of get_line()
ob_end_flush(); // to get php's internal buffers out into the operating system
flush(); // to tell the operating system to flush it's buffers to the user.

PHP手册上的人还暗示说,明确设置带有MIME类型和字符集的header()可能会有所帮助,这样浏览器就会在开始时知道它正在处理的实体的类型,而不必等待整个二进制对象可用后再尝试解密。

如果这不起作用,您需要进一步修改系统php.ini以关闭输出缓冲和压缩,此时您可能需要查看ajax解决方案。

Ajax解决方案可能类似于:

您的脚本输出一些HTML/JavaScript以命中Ajax请求,刷新所有缓冲区,并停止关注用户,然后开始某些操作,或者仅指示在某个地方的数据库中启动某些大型操作,供cron作业获取。您页面上的JavaScript将具有计时器循环,以轮询Ajax端点的状态,直到Ajax回复已完成为止。Ajax端点将通过查询数据库或检查输出文件等方式检查任务的状态,并立即将其了解到的所有内容都输出并终止,让客户端决定何时再次询问是否完成。这是一个涉及更多移动部件的更复杂的过程,但如果值得您花费时间来制作,则可以为用户实现非常好的最终产品。


运行得很好。此外,我不得不从代码中删除ob_start()。另外,会抛出一个通知"ob_end_flush(): failed to delete and flush buffer. No buffer to delete or flush",但它只是在当前情况下出现,以后不会成为问题。感谢您的帮助。 - Xarvalus

3

在你的代码输出 "Element X finished. Y time." 后立即调用 flush();

默认情况下,PHP 会将所有输出存储在输出缓冲区中,直到准备好发送到浏览器为止。 flush()ob_flush() 强制输出被发送。


1
在每个循环中尝试调用 ob_flushob_clean。第一个函数发送输出缓冲区,第二个函数则清空它。

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