2013-02-22 88 views
6

我有一个PHP脚本,它发送大量记录,并且我希望在每个记录可用时尽快刷新它:客户端能够处理每个记录到达时,它不需要等待整个响应。我意识到整个传输需要稍长的时间,因为它需要以多个数据包发送,但它仍然允许客户端尽早开始工作。防止用PHP和Apache输出缓冲

我已经尝试了所有不同的flush()ob_flush()函数,但是在页面结束之前似乎没有任何东西可以帮助获取通过行实际发送的数据。我已经确认它不是网络浏览器,因为我已经使用telnet对它进行了测试。

回答

4

唯一能解决问题的方案是将php.ini中的output_buffering指令设置为“关闭”。我不想为整个服务器做这个,只是这个特定的资源。通常情况下,您可以使用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

不知道这是否总是错误或PHP5.6中的某些内容发生了变化,但我不得不使用'php_flag output_buffering Off'来使'Off'工作。 – RiggsFolly 2015-09-18 14:19:35

+0

我将php.ini中的“output_buffering”从4096设置为Off,并重新引导整个服务器,并使用phpinfo()进行了验证;但我仍然面临同样的问题,服务器在向浏览器发送数据之前正在等待页面加载。 Apache2或Ubuntu 16.04中还有其他设置吗?我正在使用PHP7。 – Tarik 2017-08-06 11:58:59

3

你没有提到你正在使用的是什么Web服务器,但我会在这里出现一个肢体并猜测Apache2。我几乎碰到了你描述的同样的东西。我试图让我的CGI脚本传回信息,因为它已经准备好了,而不是缓冲整个事情。在卷曲等工作jiffy,但缓冲在浏览器(几乎任何浏览器),这至少是疯了。我经历了你描述的确切步骤。在我的情况下,分辨率是修改sites-enabled/terrifico.com配置文件中的Apache2(有问题的符合

SetEnvIfNoCase开始

(您可以忽略的上方,线下的东西,我只是展示它在那里我把它的参考。)

<VirtualHost *:80> 
ServerAdmin [email protected] 
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

要在运行时关闭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个字节。

+0

此代码确实是3x相同 - .- – 2017-09-01 08:47:57