如何在每个`echo`调用之后刷新输出?

我有一个只生成日志到客户端的PHP脚本。
当我回应一些事情时,我希望能够将它传送给客户。
(因为在处理脚本时,页面是空白的)
我已经玩了ob_start()ob_flush() ,但他们没有工作。

什么是最好的解决scheme?

PS:在echo调用结束时进行刷新是有点肮脏的…

编辑:无论是解决工作,PHP或Apache错误?

编辑:

我正在阅读手册页上的表扬,并遇到一个错误 ,指出ob_implicit_flush 不起作用 ,以下是解决方法:

 ob_end_flush(); # CODE THAT NEEDS IMMEDIATE FLUSHING ob_start(); 

甚至可能发生的事情是,客户端没有收到来自服务器的数据包,直到服务器build立足够的字符来发送它认为值得发送的数据包。


老答案:

您可以使用ob_implicit_flush来告诉输出缓冲closures缓冲一段时间:

 ob_implicit_flush(true); # CODE THAT NEEDS IMMEDIATE FLUSHING ob_implicit_flush(false); 

我得到了同样的问题,并在手册中发布的示例之一。 必须将字符集指定为这里已经提到的海报之一。 http://www.php.net/manual/en/function.ob-flush.php#109314

 header( 'Content-type: text/html; charset=utf-8' ); echo 'Begin ...<br />'; for( $i = 0 ; $i < 10 ; $i++ ) { echo $i . '<br />'; flush(); ob_flush(); sleep(1); } echo 'End ...<br />'; 

所以这就是我发现的。

Flush在Apache的mod_gzip或者Nginx的gzip下不起作用,因为从逻辑上讲,它是在对内容进行压缩,并且这样做必须将内容缓冲到gzip中。 任何types的networking服务器gzipping会影响这一点。 总之,在服务器端,我们需要禁用gzip并减lessfastcgi缓冲区大小。 所以:

  • 在php.ini中:

     output_buffering = Off zlib.output_compression = Off 
  • 在nginx.conf中:

     gzip off; proxy_buffering off; 

也有这些线,特别是如果你没有访问php.ini:

 @ini_set('zlib.output_compression',0); @ini_set('implicit_flush',1); @ob_end_clean(); set_time_limit(0); 

最后,如果你有它,请注意下面的代码:

 ob_start('ob_gzhandler'); ob_flush(); 

PHPtesting代码:

 ob_implicit_flush(1); for ($i=0; $i<10; $i++) { echo $i; // this is to make the buffer achieve the minimum size in order to flush data echo str_repeat(' ',1024*64); sleep(1); } 

看似不成功的冲洗是自动字符集检测的副作用。

浏览器不会显示任何东西,直到它知道要显示的字符集为止,如果不指定字符集,则需要尝试猜测它。 问题在于,如果没有足够的数据,就无法做出正确的猜测,这就是为什么浏览器在显示任何内容之前似乎都需要填充1024字节(或类似的)缓冲区的原因。

因此,解决scheme是确保浏览器不必猜测字符集。

如果你正在发送文本,添加一个'; charset = utf-8“作为其内容types,如果是HTML,则将字符集添加到适当的元标记中。

你想要的是冲洗方法。 例:

 echo "log to client"; flush(); 

为什么不做一个函数来回显,如下所示:

 function fecho($string) { echo $string; ob_flush(); } 

使用正确的函数是flush()

 <html> <body> <p> Hello! I am waiting for the next message...<br /> <?php flush(); sleep(5); ?> I am the next message!<br /> <?php flush(); sleep(5); ?> And I am the last message. Good bye. </p> </body> </html> 

请注意,IE浏览器存在一个“问题”,当它至less为256字节时,只输出刷新的内容,因此页面的第一部分至less需要256字节。

我也有类似的事情要做。 运用

 // ini_set("output_buffering", 0); // off ini_set("zlib.output_compression", 0); // off ini_set("implicit_flush", 1); // on 

确实使输出在我的情况下频繁冲洗。

但是我不得不在特定的点(在我运行的循环中)刷新输出,所以两者都使用

 ob_flush(); flush(); 

一起为我工作。

我无法closures“output_buffering”与ini_set(…),不得不直接在php.ini中,phpinfo()显示其设置为“没有价值”时closures,这是正常的? 。

尝试这个:

 while (@ob_end_flush()); ob_implicit_flush(true); echo "first line visible to the browser"; echo "<br />"; sleep(5); echo "second line visible to the browser after 5 secs"; 

只要注意,这样你实际上是禁用当前脚本的输出缓冲区。 我想你可以用ob_start()重新启用它(我不确定)。

重要的是,通过像上面那样禁用输出缓冲区,您将无法使用header()函数redirect您的php脚本,因为每个执行脚本的http头只能发送一次。 但是,您可以使用JavaScriptredirect。 只要让你的PHP脚本回声以下几行:

  echo '<script type="text/javascript">'; echo 'window.location.href="'.$url.'";'; echo '</script>'; echo '<noscript>'; echo '<meta http-equiv="refresh" content="0;url='.$url.'" />'; echo '</noscript>'; exit; 

防病毒软件也可能会干扰输出冲洗。 就我而言,卡巴斯基反病毒软件2013在将数据块发送到浏览器之前保留了数据块,即使我使用的是可接受的解决scheme。

有时候,问题来自Apache设置。 Apache可以设置为gzip输出。 在.htaccess文件中,您可以添加例如:

 SetEnv no-gzip 1 

注意,如果你在某些共享的托pipe网站,如Dreamhost,你不能禁用PHP输出缓冲,而不经过不同的路线:

更改输出缓冲区caching如果使用PHP FastCGI,则PHP函数flush(),ob_flush()和ob_implicit_flush()将无法按预期方式运行。 默认情况下,输出缓冲在比PHP更高的层次上(具体来说,通过mod_gzip的form / function类似的Apache模块mod_deflate )。

如果您需要无缓冲输出,则必须使用CGI (而不是FastCGI),或者联系支持人员请求为您的站点禁用mod_deflate

https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview

我迟到讨论,但我读了很多人都说追加flush(); 在每个代码的末尾看起来很脏,而且他们是对的。

最好的解决scheme是禁用deflate,gzip和所有来自Apache,中间处理程序和PHP的缓冲。 然后在你的php.ini你应该有:

  output_buffering = Off zlib.output_compression = Off implicit_flush = Off 

临时解决scheme是在你的php.ini 如果你可以用flush()解决你的问题。 但是你认为把它放在任何地方都是肮脏和丑陋的。

 implicit_flush = On 

如果你只把它放在你的php.ini中,你不需要把flush(); 在你的代码了。

这是我的代码:(为PHP7工作)

 private function closeConnection() { @apache_setenv('no-gzip', 1); @ini_set('zlib.output_compression', 0); @ini_set('implicit_flush', 1); ignore_user_abort(true); set_time_limit(0); ob_start(); // do initial processing here echo json_encode(['ans' => true]); header('Connection: close'); header('Content-Length: ' . ob_get_length()); ob_end_flush(); ob_flush(); flush(); }