如何在每次“ echo”调用后刷新输出?

我有一个只生成客户端日志的 php 脚本。
当我重复某些内容时,我希望它能够即时传输到客户端。
(因为当脚本处理时,页面是空白的)
我已经尝试了 ob_start()ob_flush(),但是它们不起作用。

最好的解决办法是什么?

附注: 在 echo呼叫结束时冲水有点脏..。

编辑: PHP 或者 Apache 错误,答案都不起作用?

150096 次浏览

你需要的是 冲水方法。 例如:

echo "log to client";
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 有一个“问题”,它只输出至少256字节的刷新内容,因此页面的第一部分至少需要256字节。

为什么不创建一个 echo 函数,像这样:

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

编辑:

我正在阅读手册页上的评论,碰到了 一只虫子,说明 ob_implicit_flush 不起作用和以下是它的解决方案:

ob_end_flush();


# CODE THAT NEEDS IMMEDIATE FLUSHING


ob_start();

如果这不起作用,那么甚至可能发生的情况是,客户端不从服务器接收数据包,直到服务器构建了足够的字符来发送它认为值得发送的数据包。


老答案:

你可以使用 ob_implicit_flush,它会告诉输出缓冲关闭一段时间的缓冲:

ob_implicit_flush(true);


# CODE THAT NEEDS IMMEDIATE FLUSHING


ob_implicit_flush(false);

我也有类似的事情要做,吸毒

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

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

但是我必须在一个特定的点(在我运行的循环中)刷新输出,因此使用两者

ob_flush();
flush();

一起工作对我很有帮助。

我做不到 关闭 “ output _ buffer” Ini _ set (...) ,必须直接转动它 在 php.ini 中,phpinfo ()显示其设置 “没有价值”,是不是 正常。

这是我的发现。

Flush 不能在 Apache 的 mod _ gzip 或 Nginx 的 gzip 下工作,因为逻辑上它是 gzip 内容,要做到这一点,它必须缓冲 gzip 内容。任何形式的 web 服务器 gzip 都会影响这一点。简而言之,在服务器端,我们需要禁用 gzip 并减小 fastcgi 缓冲区大小。所以:

  • 在 php.ini 中:

    output_buffering = Off
    
    
    zlib.output_compression = Off
    
  • In nginx.conf:

    gzip  off;
    
    
    proxy_buffering  off;
    

Also have these lines at hand, especially if you don't have access to 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 to make the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);


sleep(1);
}

冲洗似乎无法工作是自动字符集检测的副作用。

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

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

如果要发送文本,请在其内容类型中添加“ ; charset = utf-8”,如果是 HTML,则将字符集添加到适当的 meta 标记中。

我已经得到了同样的问题,并在手册中张贴的一个例子工作。字符集必须指定为这里已经提到的海报之一。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 />';

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

SetEnv no-gzip 1

试试这个:

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()函数重定向您的 php 脚本,因为每个脚本执行 http 头文件时,php 只能发送一次。 然而,你可以使用 javascript 重定向,只需要让你的 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年的 Kaspersky Anti-Virus 是在把数据块发送到浏览器之前先保存数据块,即使我使用的是一个公认的解决方案。

请注意,如果您在某些共享主机网站,如 Dreamhost,您无法禁用 PHP 输出缓冲在没有通过不同的路由:

更改输出缓冲区缓存如果您正在使用 PHP FastCGI,PHP 函数 ush ()、 ob _ rush ()和 ob _  隐式的 flash ()不會 默认情况下,输出缓冲在较高的级别 比 PHP (特别是,由 Apache 模块 mod _ flate,这是 在形式/函数上与 mod _ gzip 相似)。

如果需要未缓冲的输出,则必须使用 使用 CGI(而不是 或对 请求禁用 mod _ flate的联系支持 你的网站。

Https://help.dreamhost.com/hc/en-us/articles/214202188-php-overview

我已经迟到了,但是我读到很多人都说附加了 ush () ; 在每个代码的末尾看起来都很脏,他们是对的。

最好的解决方案 是从 Apache、中间处理程序和 PHP 禁用 flate、 gzip 和所有缓冲。那么在你的 php.ini 里,你应该有:

            output_buffering = Off
zlib.output_compression = Off
implicit_flush = Off

临时解决方案 是在 php.ini 如果中使用这个函数,这样就可以使用 ush ()解决问题; 但是如果把它放在任何地方,您会认为它是肮脏和丑陋的。

implicit_flush = On

如果只将它放在 php.ini 中,那么就不需要再在代码中放入 ush () ; 。

这是我的代码: (为 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();
}

对于那些即将到来的2018年:

唯一对我有效的解决办法是:

<?php


if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){


echo "<br> Line to show.";
echo str_pad('',4096)."\n";


ob_flush();
flush();
sleep(2);
}


echo "Done.";


ob_end_flush();
?>

保留“4096”部分非常重要,因为它似乎“填补”了缓冲区..。

这对我来说很好用(Apache 2.4/PHP 7.0) :

@ob_end_clean();
echo "lorem ipsum...";
flush();
sleep(5);
echo "<br>dolor...";
flush();
sleep(5);
echo "<br>sit amet";

由于各种宿主环境中的细节问题,gzip 压缩一直处于打开状态,这一点很少被提及。

这是一种现代的方法,将 PHP-FPM 作为快速 CGI 使用,这并不需要。Htaccess 重写规则或环境变量:

在 php.ini 或. user.ini 中:

output_buffering = 0
zlib.output_compression = 0
implicit_flush = true
output_handler =

在 PHP 脚本中:

header('Content-Encoding: none'); // Disable gzip compression
ob_end_flush(); // Stop buffer
ob_implicit_flush(1); // Implicit flush at each output command

请参阅官方 PHP 文档中的 此评论以了解 ob _ end _ rush ()的需要。

header( 'X-Accel-Buffering: no' );
header( 'Content-Type: text/html; charset=utf-8' );


echo 'text to display';
echo '<span style="display: none;">' . str_repeat ( ' ', 4096 ) . '</span>';
flush();
usleep( 10 );