68

我有一个只向客户端生成日志的 php 脚本。
当我回显某些内容时,我希望将其即时传输到客户端。
(因为在处理脚本时,页面是空白的)
我已经玩过ob_start()and ob_flush(),但它们没有用。

最好的解决方案是什么?

PS:在通话结束时放一个flush有点脏echo......

编辑:答案都不起作用,PHP 还是 Apache 故障?

4

18 回答 18

66

我遇到了同样的问题,并且手册中发布的示例之一有效。必须将字符集指定为此处已经提到的海报之一。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 />';
于 2012-10-05T06:14:10.273 回答
43

编辑:

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

ob_end_flush();

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_start();

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


老答案:

您可以使用ob_implicit_flushwhich 将告诉输出缓冲关闭缓冲一段时间:

ob_implicit_flush(true);

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_implicit_flush(false);
于 2010-06-28T14:36:19.843 回答
40

所以这就是我发现的。

Flush 在 Apache 的 mod_gzip 或 Nginx 的 gzip 下不起作用,因为从逻辑上讲,它正在对内容进行 gzip 压缩,为此它必须缓冲内容以对其进行 gzip。任何类型的 Web 服务器 gzipping 都会影响这一点。简而言之,在服务器端,我们需要禁用 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 to make the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}
于 2011-02-12T15:19:14.300 回答
16

对于那些在 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();
?>

并且保留de“4096”部分非常重要,因为它似乎“填充”了缓冲区......

于 2018-02-21T20:23:53.277 回答
12

刷新似乎无法正常工作是自动字符集检测的副作用。

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

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

如果您要发送文本,请添加一个 '; charset=utf-8' 为其内容类型,如果是 HTML,则将字符集添加到相应的元标记中。

于 2012-04-24T21:19:00.057 回答
9

你想要的是flush方法。例子:

echo "log to client";
 flush();
于 2010-06-28T14:29:24.340 回答
5

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

function fecho($string) {
 echo $string;
 ob_flush();
}
于 2010-06-28T14:36:11.167 回答
4

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

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

在我的情况下确实使输出刷新频繁。

但是我必须在特定点(在我运行的循环中)刷新输出,所以同时使用

ob_flush();
flush();

一起为我工作。

我无法用ini_set(...)关闭“output_buffering”,必须直接在php.ini中打开它,phpinfo()在关闭时显示其设置为“无值”,这正常吗?.

于 2011-01-21T19:50:44.720 回答
4

不经常提到的一件事是 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

有关ob_end_flush() 的需要,请参阅官方 PHP 文档的此评论。

于 2019-01-18T14:13:12.190 回答
3

正确使用的功能是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 字节。

于 2010-06-28T14:34:57.580 回答
3

这对我来说很好(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";
于 2018-06-27T15:52:26.197 回答
1

防病毒软件也可能会干扰输出刷新。就我而言,卡巴斯基反病毒软件 2013 在将数据块发送到浏览器之前会保存数据块,即使我使用的是公认的解决方案。

于 2015-05-19T08:04:30.443 回答
1
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 );
于 2021-07-28T10:12:37.827 回答
0

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

SetEnv no-gzip 1
于 2013-10-21T09:37:29.713 回答
0

试试这个:

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 脚本,因为 php 每次脚本执行时只能发送一次 http 标头。但是,您可以使用 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;
于 2014-09-19T16:49:24.373 回答
0

请注意,如果您在某些共享托管站点(例如 Dreamhost)上,则根本无法禁用 PHP 输出缓冲,而无需经过不同的路线:

更改输出缓冲区缓存 如果您使用 PHP FastCGI,PHP 函数 flush()、ob_flush() 和 ob_implicit_flush() 将无法按预期运行。默认情况下,输出在比 PHP 更高的级别进行缓冲(具体来说,通过Apache 模块 mod_deflate,它在形式/功能上与 mod_gzip 相似)。

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

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

于 2017-04-17T02:44:40.713 回答
0

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

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

            output_buffering = Off
            zlib.output_compression = Off
            implicit_flush = Off

临时解决方案是在你的 php.ini 中有这个,如果你可以用 flush(); 解决你的问题;但是你觉得到处都放着又脏又丑。

implicit_flush = On

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

于 2017-08-06T14:01:25.373 回答
0

这是我的代码:(适用于 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();
}
于 2017-10-02T16:02:21.197 回答