<?php
for($i=0;$i<20;$i++)
{
echo 'printing...<br />';
ob_flush();
flush();
usleep(300000);
}
?>
包含代码的网址:http://domainsoutlook.com/sandbox/delayed.php
我有一台专用服务器,所以我可以进行更改。我正在运行Apache和Nginx作为代理服务器。
<?php
for($i=0;$i<20;$i++)
{
echo 'printing...<br />';
ob_flush();
flush();
usleep(300000);
}
?>
包含代码的网址:http://domainsoutlook.com/sandbox/delayed.php
我有一台专用服务器,所以我可以进行更改。我正在运行Apache和Nginx作为代理服务器。
这就是我找到的结果:
在Apache的mod_gzip或Nginx的gzip情况下,Flush不起作用,因为它压缩内容,必须缓冲内容以进行压缩。任何类型的Web服务器压缩都会影响此操作。简而言之,在服务器端,我们需要禁用gzip并减小fastcgi缓冲区大小。因此:
在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();
PHP测试代码:
ob_implicit_flush(1);
for($i=0; $i<10; $i++){
echo $i;
//this is for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
这是为了缓冲区达到最小大小以便刷新数据
。哦,该死!... 看起来还没有绕过它的方法:https://stackoverflow.com/q/57207571/1066234 - Avatarecho str_repeat(' ', 4096);
似乎足够了。https://www.php.net/manual/en/function.flush.php#51679 - Avatar你正在使用 ob_flush
却没有使用 ob_start
,因此对其进行刷新时没有任何内容可供刷新。
此外,这也取决于 Web 服务器和代理及其设置。
您应该禁用 Nginx 的缓冲(在配置文件中添加 proxy_buffering off;
并重新启动 Nginx)。
另外,请检查您的 php.ini 文件是否包含 output_buffering = Off
和 zlib.output_compression = Off
。
主PHP文件;
<?php
header('Content-Type: text/HTML; charset=utf-8');
header( 'Content-Encoding: none; ' );//disable apache compressed
session_start();
ob_end_flush();
ob_start();
set_time_limit(0);
error_reporting(0);
..... bla bla
for(each)........
{
bla bla..
echo "<br>>>>".$i."<<<br>";
ob_flush();
flush(); //ie working must
}
?>
它正在工作中..
Content-Encoding
最终使刷新在 Firefox 上运行,但某种方式 Chrome 仍然期望压缩响应,因此它抛出了一个 ERR_CONTENT_DECODING_FAILED
错误。 - Jelle De Loeckerecho str_pad('',4096)."\n";
完整的代码:
<?php
if (ob_get_level() == 0) ob_start();
for( $i=0 ; $i<20 ; $i++) {
echo 'printing...<br />';
echo str_pad('',4096)."\n";
ob_flush();
flush();
usleep(300000);
}
ob_end_flush();
?>
output_buffering = Off
zlib.output_compression = Off
fastcgi_keep_conn on; # < solution
proxy_buffering off;
gzip off;
fastcgi_keep_conn on
有帮助!谢谢! - artnikpro<!DOCTYPE html>
<html>
<head></head>
<body>
<?php
$vars = array('output_buffering', 'zlib.output_compression');
print('<p>');
foreach ($vars as $var) {
print("$var : ");
var_dump(ini_get($var));
print('<br />');
}
print("ob_get_level() : " .ob_get_level());
print('</p>');
if (ob_get_level()) {
$bytes = ob_get_length();
ob_flush();
}
$nb_iterations = !empty($_GET['nb']) ? max(2, (int) $_GET['nb']) : 5;
$size = !empty($_GET['size']) ? $_GET['size'] : 0;
for ($i = 1; $i < $nb_iterations; $i++) {
sleep(1);
print(str_repeat(' ', 1024 * $size ));
print("<p>wait $i s</p>");
if (ob_get_level()) {
$bytes += ob_get_length();
print($bytes + strlen($bytes));
ob_flush(); // this is working, results aren't depending on output_buffering value
}
flush(); // this is needed
}
?>
</body>
</html>
我可以设置的最低配置为
location ~ ^/test.php$ {
gzip off;
fastcgi_pass unix:/var/run/php5-fpm/ssl.socket;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $request_filename;
# if too low => upstream sent too big header while reading response header from upstream
fastcgi_buffer_size 128;
fastcgi_buffers 2 128;
fastcgi_busy_buffers_size 128;
}
SecResponseBodyAccess Off
这是一种有点不太正规的解决方法,但目前这是我唯一让它工作的方法。
我想补充一下Roger的回答。
如果你正在使用Apache2中的FastCGI php5-fpm模块,你还必须确保在Apache2配置中添加-flush参数。
例如:
<IfModule mod_fastcgi.c>
...
FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -flush -socket /tmp/php5-fpm.sock -idle-timeout 480 -pass-header Authorization
</IfModule>
使用以下代码检查您的服务器API:
echo phpinfo();
如果您找到了您的服务器API
Server API : CGI/FastCGI
如果是在CentOS系统中,则需要在"/etc/httpd/conf.d/fcgid.conf"文件中添加此行。
OutputBufferSize 0
为了测试,请重启您的Apache服务器并尝试以下代码
ob_start();
for($i = 0; $i < 10; $i ++) {
echo $i;
echo '<br />';
flush();
ob_flush();
sleep(1);
}
fcgid_module
,你应该在设置fcgid_module的httpd conf文件中添加FcgidOutputBufferSize 0
。 - Zoltán Kurgya我只能通过添加session_write_close();来刷新。
if (ob_get_level() == 0)
{
if(!ob_start("ob_gzhandler"))ob_start();
}
echo ('bla bla bla');
$ans=ob_get_contents();
ob_end_clean();
header('Connection: close');
header('Content-Length: '.strlen($ans));
header('Status: 200');
echo $ans;
session_write_close();
ob_flush();
flush();
ob_start()
开始一个输出缓冲区,并且应该在flush()
之后使用ob_flush()
。 - RobertPitt