PHP 错误:ob_flush() [ref.outcontrol]:无法刷新缓冲区。没有可刷新的缓冲区。

13

请问有人能够保存并运行这两个文件,并告诉我为什么会出现错误信息 " ob_flush() [ref.outcontrol]: failed to flush buffer. No buffer to flush" 吗?我尝试通过搜索引擎来解决,结果显示需要使用 ob_start();,但是当我使用它之后,for循环中的内容不会逐行输出,而是等整个循环结束后一次性返回。由于我对PHP比较陌生,所以不知道该去哪里寻找解决方案。

test_process.php

// This script will write numbers from 1 to 100 into file
// And sends continuously info to user
$fp = fopen( '/tmp/output.txt', 'w') or die('Failed to open');
set_time_limit( 120);
ignore_user_abort(true);

for( $i = 0; $i < 100; $i++){
    echo "<script type=\"text/javascript\">parent.document.getElementById( 'foo').innerHTML += 'Line $i<br />';</script>";
    echo str_repeat( ' ', 2048);
    flush();
    ob_flush();
    sleep(1);
    fwrite( $fp, "$i\n");
}

fclose( $fp);

主页面.html

<html>
    <head>
        <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript" charset="utf-8"></script>

        <style type="text/css" media="screen">
            .msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
            .new{ background-color:#3B9957;}
            .error{ background-color:#992E36;}
        </style>

    </head>
    <body>

        <iframe id="loadarea" width="1024px" height="768px"></iframe><br />
        <script>
            function helper() {
                document.getElementById('loadarea').src = 'test_process.php';
            }
            function kill() {
                document.getElementById('loadarea').src = '';
            }
        </script>

        <input type="button" onclick="helper()" value="Start">
        <input type="button" onclick="kill()" value="Stop">
        <div id="foo"></div>


</body>
</html>

请检查php.ini中关于输出缓冲区的配置,它可以被自动启用到on_start模式。另外一种检查它是否启用的方法是在开头使用ob_end_flush()函数并移除所有的flush。你也可以使用phpinfo();函数来检查它。 - dvicino
嘿,谢谢你的回复。我尝试启用输出缓冲,但它返回整个for循环对象,而不是逐行返回... - user1191027
3个回答

33

只有在输出缓冲区处于活动状态时(例如通过ob_start()或配置设置),才需要使用ob_flush()。如果没有,请删除ob_flush()。或者您可以将其设置为条件性的:

 if (ob_get_level() > 0) {ob_flush();}

在显示之前请记住缓存可以发生在您和UA之间的任何路线上:在PHP中,在Web服务器中,在任何代理或网络跳跃中,在您的本地网络中,在您的本地计算机中,在您的本地浏览器中。最多,您可以提示(如果没有输出缓冲区处于活动状态,则ob_flush对您没有任何好处),如果您需要它,您不应该使用HTTP而是使用其他直接套接字连接。 - Wrikken
但出于某种原因,当ob_flush()存在时它可以工作,但同时也会抛出那个错误,所以如果那个错误能够消失就更完美了。lol - user1191027
只有当错误显示时,还是即使 display_errors 关闭也会出现?因为如果是前者,很可能只是非空内容的数量触发了其他地方的刷新。 - Wrikken
我将那行代码替换为关闭 display_errors,但它仍然返回整个对象而不是逐行返回。 - user1191027
啊哈!如此简短而甜美 :) 今天的代码研究结束了! - Anupam Rekha
显示剩余3条评论

14
我认为你将ob_flush()flush()混淆了。虽然ob_start()ob_flush()处理PHP内部输出缓冲区以捕获所有输出,但flush()是刷新像其他编程语言中的STDOUT的正常函数。
例子:
<?php
ob_start();
echo "Foobar\nFoobar\nFoobar\n";
// Nothing printed yet
ob_flush(); // Now it is printed.

echo "Foobar\n"; // Printed directly, because contains a line ending.

echo "Foobar"; // Not printed, because normally buffers are flushed on line endings
flush();  // Printed.

编辑:

你的输出结果可能没有被打印出来,因为你的Web服务器可能会缓存内容。尝试关闭压缩和输出缓冲:

@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);

请注意,Safari和Internet Explorer有一个内部的1K缓冲区。因此,您需要添加1 KB的填充数据(如空格)以使它们渲染。

编辑2: 你的实现有问题。你想要用ajax轮询你的数据。在客户端使用jQuery:

<div id="counter">0%</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
<script type="text/javascript">
function doPoll(){
    $.post('script-that-returns-stuff.php', function(data) {
        $("#counter").html(data);
        setTimeout(doPoll,5000);
    });
}
doPoll();
</script>

然后在script-that-returns-stuff.php文件中:

<?php
$file = explode("\n", file_get_contents("/tmp/output.txt"));
$last_line = $file[count($file)-1];
echo $last_line."%";

嗨 - 謝謝你的回應。我試了你的建議,但不知何故它並沒有逐行返回結果,而是在處理完成後才返回整個for循環的結果。 - user1191027
然后以简洁的方式实现它。创建一个JavaScript,每秒轮询服务器和一个PHP脚本,返回文件中行数。然后在客户端显示它。 - iblue
好的,请查看编辑2,其中包含一个AJAX实现。它每5秒轮询一次。如果要更频繁地轮询,请减少setTimeout中的数字。 - iblue
嘿,我尝试了一下,但是使用while或for循环时它不会刷新,它只返回循环处理的结果,而不是每次循环时的结果。 - user1191027
1K缓冲区是我在PHP中实现EventSource循环的神秘问题。我通过在循环开始处添加echo str_repeat(" ", 1024), "\n";来克服它,突然间,一切都正常了! - Jacob Pritchett

2

ob_start()在哪里?

ob_flush将输出缓冲区刷新到文件句柄。也许你搞错了。

一个例子:

ob_start(); //start output buffering
echo 'hello world'; //not outputed
ob_flush(); //sends the output buffer so displays hello world.

手册


嗨,谢谢您的回复。我没有在上面的代码中包含它,因为当我这样做时,它不会逐行返回,而是只有在处理完成后才会返回整个for循环结果。 - user1191027

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接