PHP使用sleep()函数的输出问题

7
我正在尝试每秒运行一个循环,持续25秒。
for($i = 0; $i <= 25; $i += 1){ 
    echo $i;
    sleep(1)
}

问题在于它只有在完全完成后才输出,因此在循环继续 25 次之后。有没有办法在每次休眠之前输出并且不等待完整的循环完成?

谢谢!


你使用的浏览器和内容是什么?有些浏览器在遇到闭合标签之前不会呈现HTML。如果你想要“实时更新”的内容,纯文本可能是更好的选择。 - mwalker
1
这似乎是一个更好地在客户端处理的问题。您可以使用AJAX每秒从服务器获取数据。 - Peter Ajtai
2
这绝对不应该在服务器上以你尝试的方式完成.. 相反,在浏览器中使用一些ajax和setTimeout之类的东西。 - Scott Evernden
3个回答

8

我刚开始学习时遇到了同样的问题,写了一个简单的脚本来解决你所需要的功能。

<?PHP
ob_start();
$buffer = str_repeat(" ", 4096)."\r\n<span></span>\r\n";

for ($i=0; $i<25; $i++) {
  echo $buffer.$i;
  ob_flush();
  flush();
  sleep(1);
}

ob_end_flush();
?>

您可能会问的问题可以在这里找到(关于\r\n),以及在这里找到(关于ob_flush())。希望这能帮助您。


我尝试了很多不同的输出缓冲建议,这是唯一一个真正起作用的!惊讶的是,这是第一个提到填充输出长度的建议。 - Louis W

8
你想要实现的是从PHP向浏览器递增输出内容。是否能够实现取决于你的服务器以及如何调用PHP。
在使用FastCGI而不是Apache模块时,可能更容易遇到这种问题,因为服务器和PHP进程之间的耦合度不高。一旦数据离开PHP进程,FastCGI通信就会使用输出缓冲区,只有在请求完全完成或此缓冲区已填满时,输出才发送到浏览器。此外,为了避免任何一个运行时间过长,PHP进程往往会在一定时间后终止。
尽管如此,ob_end_flush()(或ob_flush())和flush()的组合仍应导致PHP请求清除下游缓冲区,因此这仍然可能有效。您还需要调查是否需要延长PHP脚本的时间限制。
如果您正在使用mod_php,则可以将内容逐步写入浏览器。使用flush()命令确保PHP模块立即刷新。如果没有输出缓冲区或某个Apache模块(例如mod_gzip),则它应该立即发送到用户的浏览器。此外,在默认配置下,您可以让PHP脚本运行任意长时间(使用PHP中的set_time_limit()),尽管当然会消耗一些内存。
您可能会遇到一些浏览器的问题,因为它们在下载了一定量的页面后才开始渲染页面。某些版本的IE可能会等待1KB。我发现Chrome可以等待更多。许多人通过添加填充来解决此问题,例如在文档顶部添加一个长达1或2 KB的注释。

4
调用 flush 函数会强制 PHP 在继续执行之前将所有输出缓冲推送到客户端。
for($i = 0; $i <= 25; $i += 1){ 
    echo $i;
    flush();
    sleep(1);
}

编辑:

在我的lighttpd服务器上测试后,我发现它会将输出缓冲为4096个字符的块,并且我认为其他浏览器可能具有类似的缓冲方案。此外,GZIP可以完全阻止flush。不幸的是,由于HTTP的性质,没有办法测试它是否有效。

还有另一个使用此策略的问题是它会使PHP进程对其他请求被阻塞。这可能会导致请求积累。


嗯...似乎没有起作用...也尝试了ob_start(),ob_flush()和flush()。 - dzm
1
通常使用 ob_end_flush()(跳过 ob_start())和 flush() 的组合即可。您是否在 PHP 服务器和您之间有代理服务器? - Annika Backstrom
在命令行中运行对我有效,但在浏览器中不行...在sleep(1)后加上一个分号之后就可以了。 - Aaron W.
@Dave 尝试使用命令行中的curl,这样可以避免浏览器缓存的问题。如果情况是这样的话,你只能通过更换浏览器来解决此问题。 - Kendall Hopkins

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