我有一个发送大量记录的PHP脚本,我想在每个记录可用时立即刷新:客户端能够在每个记录到达时处理它,它不需要等待整个回应。我意识到整个传输需要稍长的时间,因为它需要以多个数据包发送,但它仍然允许客户端更快地开始工作。
我已经尝试了所有不同的flush()
和ob_flush()
函数,但似乎没有任何东西可以帮助在页面完成之前获取实际通过该行发送的数据。我已经确认它不是网络浏览器,因为我已经使用telnet进行了测试。
答案 0 :(得分:5)
对我有用的唯一解决方案是将php.ini中的output_buffering
指令设置为“Off”。我不想为整个服务器执行此操作,只需要这个特定的资源。通常你可以使用PHP脚本中的ini_set
,但无论出于什么原因,php都不允许以这种方式设置output_buffering
(参见the php manual)。
事实证明,如果您使用的是Apache,您可以从服务器配置中设置一些php ini指令(包括output_buffering
),包括.htaccess文件。所以我在.htaccess文件中使用以下内容来禁用仅为该文件的output_buffering:
<Files "q.php">
php_value output_buffering Off
</Files>
然后在我的静态服务器配置中,我只需要AllowOverride Options=php_value
(或更大的锤子,如AllowOverride All
),以便在.htaccess文件中允许这样做。
答案 1 :(得分:3)
你没有提到你正在使用的是什么网络服务器,但是我会在这里试探看看Apache2。我点击的几乎与你描述的完全相同。我试图让我的cgi脚本在准备好时传回信息,而不是缓冲整个事情。在卷曲等工作jiffy,但缓存在浏览器(几乎任何浏览器),这至少令人抓狂。我完成了你描述的确切步骤。我的解决方案是修改Apache2中的sites-enabled/terrifico.com
配置文件(该行以
SetEnvIfNoCase
(您可以忽略该行上方和下方的内容,我只是将其显示在我放置位置的参考位置。)
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName test.terrifico.com
ServerAlias test.terrifico.com
SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary
DocumentRoot /var/www/test.terrifico.com
从盯着来回的网络流量开始,我终于明白了浏览器正在宣传其接受通货紧缩(即文本)。例如,这就是浏览器和curl之间的区别。突出的是
接受编码:gzip,放气,SDCH
有一些关于chunking
,但这并没有影响这个特殊问题。因此,浏览器正在请求mod_deflate
启动,这使我在我的cgi脚本中得到它们时小心翼翼地喷出了字节。你可以在浏览器中更改它,但是在服务器上更改它一次似乎更合理。
也许这有帮助。
答案 2 :(得分:3)
要在PHP中运行时关闭输出缓冲而不更改php.ini
或拥有.htaccess
文件,只需在脚本开头使用ob_end_flush()
或ob_end_clean()
即可。例如:
这应该在没有缓冲的情况下输出:
<?php
ob_end_clean();
for ($i = 0; $i < 5; $i++)
{
echo "$i\n";
flush();
usleep(0.5e6);
}
如果output_buffering
开启,则无论flush()
调用是什么,都会通过缓冲(一次一个)输出:
<?php
for ($i = 0; $i < 5; $i++)
{
echo "$i\n";
flush();
usleep(0.5e6);
}
尽管名称如此,ob_implicit_flush
会在每次输出后隐式调用flush()
,而不是ob_flush()
。在开头关闭输出缓冲区后,这在这个实例中很方便:
<?php
ob_end_clean(); // disable output buffer
ob_implicit_flush(); // call flush() automatically after every output
for ($i = 0; $i < 5; $i++)
{
echo "$i\n";
usleep(0.5e6);
}
这修复了PHP方面。 mod_deflate
或类似的东西可能还有其他东西(请参阅Ted Collins的答案),我发现Firefox在开始输出任何内容之前至少需要1024个字节。