我有一个PHP脚本,它发送了大量的记录,我想尽快刷新每个记录:客户端能够在每个记录到达时对其进行处理,而不需要等待整个响应。我意识到整个传输需要稍长的时间,因为它需要在多个数据包中发送,但它仍然允许客户端更快地开始工作。我已经尝试了所有不同的flush()和ob_flush()函数,但似乎没有什么能帮助在页面完成之前实际发送数据。我已经确认它不是Web浏览器,因为我已经使用telnet测试过了。
flush()
ob_flush()
92dk7w1h1#
对我来说唯一有效的解决方案是将php.ini中的output_buffering指令设置为“Off”。我不想对整个服务器这样做,只想对这一个特定的资源这样做。通常你可以在PHP脚本中使用ini_set,但是不管出于什么原因,php不允许以这种方式设置output_buffering(参见the php manual)。事实证明,如果你使用Apache,你可以从你的服务器配置中设置一些php ini指令(包括output_buffering),包括一个.htaccess文件。所以我在一个.htaccess文件中使用了下面的代码来禁用这个文件的output_buffering:
output_buffering
ini_set
<Files "q.php"> php_value output_buffering Off </Files>
字符串然后在我的静态服务器配置中,我只需要AllowOverride Options=php_value(或更大的锤子,如AllowOverride All),以便在.htaccess文件中允许它。
AllowOverride Options=php_value
AllowOverride All
hs1ihplo2#
你没有提到你使用的是什么Web服务器,但我在这里要冒险猜测Apache 2。我撞到了和你描述的几乎一样的东西。我试图让我的cgi脚本在它准备好的时候传递回信息,而不是缓冲整个事情。在curl等中可以工作,但在浏览器(几乎任何浏览器)中都可以缓冲,这至少让人抓狂。我完全按照你描述的步骤做了。在我的案例中,解决方案是修改Apache 2中的sites-enabled/terrifico.com配置文件(有问题的行以设置环境IfNoCase(You我可以忽略那条线上面和下面的东西,我只是为了参考我放置它的位置而显示它。
sites-enabled/terrifico.com
<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之间的区别。重点是Accept-Encoding:gzip,deflate,sdch有一点关于chunking,但这并没有影响这个特定的问题。所以,浏览器请求mod_deflate启动,这打败了我在cgi脚本中小心地吐出的字节。您可以在浏览器中更改它,但在服务器上更改一次似乎更明智。也许这能帮上忙
chunking
mod_deflate
ybzsozfc3#
要在PHP运行时关闭输出缓冲而不更改php.ini或拥有.htaccess文件,只需在脚本的开头使用ob_end_flush()或ob_end_clean()。举例来说:这应该不带缓冲输出:
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()。在这个示例中,在开始时关闭输出缓冲区后,这可能很方便:
ob_implicit_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柯林斯的答案),我观察到Firefox在开始输出任何东西之前至少需要1024字节。
3条答案
按热度按时间92dk7w1h1#
对我来说唯一有效的解决方案是将php.ini中的
output_buffering
指令设置为“Off”。我不想对整个服务器这样做,只想对这一个特定的资源这样做。通常你可以在PHP脚本中使用ini_set
,但是不管出于什么原因,php不允许以这种方式设置output_buffering
(参见the php manual)。事实证明,如果你使用Apache,你可以从你的服务器配置中设置一些php ini指令(包括
output_buffering
),包括一个.htaccess文件。所以我在一个.htaccess文件中使用了下面的代码来禁用这个文件的output_buffering:字符串
然后在我的静态服务器配置中,我只需要
AllowOverride Options=php_value
(或更大的锤子,如AllowOverride All
),以便在.htaccess文件中允许它。hs1ihplo2#
你没有提到你使用的是什么Web服务器,但我在这里要冒险猜测Apache 2。我撞到了和你描述的几乎一样的东西。我试图让我的cgi脚本在它准备好的时候传递回信息,而不是缓冲整个事情。在curl等中可以工作,但在浏览器(几乎任何浏览器)中都可以缓冲,这至少让人抓狂。我完全按照你描述的步骤做了。在我的案例中,解决方案是修改Apache 2中的
sites-enabled/terrifico.com
配置文件(有问题的行以设置环境IfNoCase
(You我可以忽略那条线上面和下面的东西,我只是为了参考我放置它的位置而显示它。
字符串
从盯着来回的网络流量,我终于明白了,浏览器是广告,它接受任何通缩(这是文本)。例如,这就是浏览器和curl之间的区别。重点是
Accept-Encoding:gzip,deflate,sdch
有一点关于
chunking
,但这并没有影响这个特定的问题。所以,浏览器请求mod_deflate
启动,这打败了我在cgi脚本中小心地吐出的字节。您可以在浏览器中更改它,但在服务器上更改一次似乎更明智。也许这能帮上忙
ybzsozfc3#
要在PHP运行时关闭输出缓冲而不更改
php.ini
或拥有.htaccess
文件,只需在脚本的开头使用ob_end_flush()
或ob_end_clean()
。举例来说:这应该不带缓冲输出:
字符串
如果
output_buffering
打开,则输出缓冲(一次全部),而不管flush()
调用:型
ob_implicit_flush
在每次输出后都会隐式调用flush()
,而不是ob_flush()
。在这个示例中,在开始时关闭输出缓冲区后,这可能很方便:型
这修复了PHP端。
mod_deflate
或类似的东西可能还有其他原因(请参阅Ted柯林斯的答案),我观察到Firefox在开始输出任何东西之前至少需要1024字节。