如何在每次“echo”调用后刷新输出?
我有一个 php 脚本,它只向客户端生成日志。
当我回显某些内容时,我希望将其即时传输到客户端。
(因为当脚本正在处理时,页面是空白的)
我已经尝试过 ob_start()
和 ob_flush()
,但它们不起作用。
最好的解决方案是什么?
PS:在 echo 调用末尾添加刷新有点脏...
编辑:答案都不起作用,PHP 或 Apache 故障?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(21)
https://stackoverflow.com/a/48914827/7485823
一个可爱且实用的解决方案 - 有一个陷阱:很多输出中有多余的空白。
它在
将
str_repeat
更改为str_pad
可最大限度地减少该问题。但是将填充字符从空白“”更改为空“\x00”似乎可以进一步减少问题。在 Chrome、Edge 和 Firefox 中生成 15 个字符的字符串,
我无法判断该字符串在哪里被截断。但是服务器上的缓存已满,并且输出已发送,并且您的输出不会因冗余空白的威胁而混乱。
https://stackoverflow.com/a/48914827/7485823
A lovely and practically solution - with a a catch: A lot of redundant blanks in your output.
It produces in
Changing
str_repeat
tostr_pad
minimizes the issue. But changing the padding character from blank " " to null "\x00" seems the reduce the problem even further.Produces in Chrome, Edge and Firefox a 15 character string
I cannot tell where the string is truncated. But the cache on the server is filled and the output is send AND your output is not cluttered by a menace of redundant blanks.
对我来说最好的解决方案(也希望对你来说):
在 php 的开头:
然后,只有这个在你的循环中:
示例:
Best solution for me (and hope for you):
At the beginning of php:
Then, only this in your loop:
Example:
情况有点复杂,但并非绝望,因为即使在其他阶段,输出也会因不同原因而被缓冲,例如 gzip、Apache、PHP(快速)GCI 与 CLI(来自命令行
$ php -a) - 而且也有不同的浏览器!
这也是为什么 PHP 确实将其评为“不是错误”,所以更多类似“rtfm”的内容,仍然可能值得改进 - 这意味着,您应该(必须?)看看全部 手册的相关部分,不仅仅是针对某一单一功能?!我知道,这可能会让人筋疲力尽,但如果您不了解系统,那么在一段时间内的微小差异和微小变化都会让您失败 - 而且很多“does为我工作”——评论表明了这一点。
PHP手册中经常有通用章节,例如输出缓冲,它也试图解释系统和用户级缓冲区之间的差异!必读!
虽然对上面的很多答案和评论做了一些具体的评论,但恐怕我仍然不被允许发表评论......
所以只有一些基本提醒根据我的“研究”(学习)结果,如果您至少深入研究了您的设置并阅读了大部分 PHP 手册:
请始终查看您的当前设置,由
php.ini
和/或.htaccess
等部分组成;例如使用
// 但不要在公共/生产系统上保留对该信息的访问权限!
例如我对 PHP 8.2.17 的默认设置是...
output_buffering = 4096
(剧透:其他版本的 PHP 可能使用整数而不是布尔值 - 请务必查看您版本的手册 - 它总是能给人带来惊喜)
output_buffering
为一个值将把 user -level buffering 像ob_start()
一样打开,var_dump( ini_set('output_buffering', 0) );
在脚本级别关闭它- 导致false
指示失败,无法设置flush()
ob_implicit_flush()
控制> (默认参数值为 bool $enable = true ),它会在代码块的每一位上自动刷新(系统缓冲区!),flush()
可以获得更多的输出控制好吧,你是对的,我应该展示更多内容:
免责声明:使用(标准)'text/html'而不带s.th 。就像
最终会进入“Quirks-Mode”,这将提供另一层惊喜 - 但做你喜欢的事;)
对我有用:)好吧,即使不明显,所以祝你好运和耐力!
长寿和繁荣 \\//-
BR 克劳斯
The situation is a little complex, but not hopeless, cause output will be buffered for different reasons, even at other stages, e.g. gzip, Apache, PHP (Fast)GCI vs. CLI (from commandline
$ php -a
) - and there are different browsers, too!That's also why PHP did rate it as "NOT a bug", so more something like "rtfm", which still may be worth an improvement -- meaning, you should (must?) have a look at all related parts of the manual, not only at that for one single function?! I know, this might feel exhausting, but if you don't understand the system, also small differences and also small changes during time will make you fail - and the lot of "does not work for me"-comments show that.
There are often general chapters in the PHP manual, e.g. Output Buffering, which also tries to explain the differences between System and User-Level Buffers! A MUST READ!
Although having some specific remarks on a lot of answers and comments above, I'm afraid, I'm still not allowed to comment...
So just a few basic reminders from my "research" (learning) results, if at least you dig into your setting and have read most of the PHP manual:
Always have a look at your current settings, by
php.ini
and/or.htaccess
and other parts;e.g. using
<?php phpinfo(); ?>
// but do not leave access to that info on a public/productive system!!For example my default with PHP 8.2.17 says ...
output_buffering = 4096
(spoiler: other versions of PHP may use integers instead of bools - always have a look at your version's manual - it's always good for a surprise)
output_buffering
to a value will turn user-level buffering ON like aob_start()
var_dump( ini_set('output_buffering', 0) );
- results infalse
indicating failure, can not be setob_end_flush()
to send the current content, and end-ing buffering - not the 'clean' (discard buffer) version?flush()
ob_implicit_flush()
(the default argument value isbool $enable = true
), which flushes (the System Buffer!) automatically on every bit of code blockflush()
Well, you are right, I should show something more:
Disclaimer: Using (standard) 'text/html' without s.th. like
<!DOCTYPE html>
will end up in "Quirks-Mode", what will provide another level of surprise - but do what you like ;)Works for me :) well, even not obvious, so wish you good luck and endurance!
Live long and prosper \\//-
BRs Klaus
我迟到了讨论,但我读到很多人都在说附加flush();每个代码的末尾看起来很脏,但它们是对的。
最佳解决方案是禁用 deflate、gzip 以及来自 Apache、中间处理程序和 PHP 的所有缓冲。然后在你的 php.ini 中你应该有:
临时解决方案 是在你的 php.ini 中包含这个如果你可以用flush()解决你的问题;但你觉得到处放它又脏又丑。
如果你只把它放在你的 php.ini 上面,你不需要把lush();不再在你的代码中。
I'm late to the discussion but I read that many people are saying appending flush(); at the end of each code looks dirty, and they are right.
Best solution is to disable deflate, gzip and all buffering from Apache, intermediate handlers and PHP. Then in your php.ini you should have:
Temporary solution is to have this in your php.ini IF you can solve your problem with flush(); but you think it is dirty and ugly to put it everywhere.
If you only put it above in your php.ini, you don't need to put flush(); in your code anymore.
这是我的代码:(适用于 PHP7)
This is my code: (work for PHP7)
请注意,如果您在某些共享托管网站(例如 Dreamhost)上,则在不通过不同路由的情况下根本无法禁用 PHP 输出缓冲:
https://help.dreamhost.com/hc/en- us/articles/214202188-PHP-概述
Note if you are on certain shared hosting sites like Dreamhost you can't disable PHP output buffering at all without going through different routes:
https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview
试试这个:
请注意,这样您实际上禁用了当前脚本的输出缓冲区。我想你可以用 ob_start() 重新启用它(我不确定)。
重要的是,通过像上面那样禁用输出缓冲区,您将无法再使用
header()
函数重定向 php 脚本,因为每次脚本执行 php 只能发送一次 http 标头。不过,您可以使用 JavaScript 进行重定向。只需让您的 php 脚本回显以下几行:
Try this:
Just notice that this way you're actually disabling the output buffer for your current script. I guess you can reenable it with ob_start() (i'm not sure).
Important thing is that by disabling your output buffer like above, you will not be able to redirect your php script anymore using the
header()
function, because php can sent only once per script execution http headers.You can however redirect using javascript. Just let your php script echo following lines when it comes to that:
有时,问题来自 Apache 设置。 Apache 可以设置为 gzip 输出。
在文件 .htaccess 中,您可以添加例如:
Sometimes, the problem come from Apache settings. Apache can be set to gzip the output.
In the file .htaccess you can add for instance :
防病毒软件也可能会干扰输出刷新。就我而言,卡巴斯基反病毒软件 2013 在将数据块发送到浏览器之前会保留数据块,即使我使用的是公认的解决方案。
Anti-virus software may also be interfering with output flushing. In my case, Kaspersky Anti-Virus 2013 was holding data chunks before sending it to the browser, even though I was using an accepted solution.
这对我来说效果很好(Apache 2.4/PHP 7.0):
This works fine for me (Apache 2.4/PHP 7.0):
正确使用的函数是
flush()
。请注意,IE 存在一个“问题”,它仅在至少 256 字节时输出刷新的内容,因此页面的第一部分至少需要 256 字节。
The correct function to use is
flush()
.Please note that there is a "problem" with IE, which only outputs the flushed content when it is at least 256 byte, so your first part of the page needs to be at least 256 byte.
我也有类似的事情要做。 在我的例子中,使用
确实使输出频繁刷新。
但我必须在特定点(在我运行的循环中)刷新输出,因此将两者
一起使用对我来说很有效。
I had a similar thing to do. Using
did make the output flushing frequent in my case.
But I had to flush the output right at a particular point(in a loop that I run), so using both
together worked for me.
不经常提及的一件事是 gzip 压缩,由于各种托管环境中的详细信息而保持打开状态。
这是一种现代方法,使用 PHP-FPM 作为快速 CGI,不需要 .htaccess 重写规则或环境变量:
在 php.ini 或 .user.ini 中:
在 PHP 脚本中:
请参阅 此评论官方 PHP 文档,用于 ob_end_flush() 需求。
One thing that is not often mentionned is gzip compression that keeps turned ON because of details in various hosting environments.
Here is a modern approach, working with PHP-FPM as Fast CGI, which does not need .htaccess rewrite rule or environment variable :
In php.ini or .user.ini :
In PHP script :
See this comment on official PHP doc for ob_end_flush() need.
为什么不创建一个回显函数,如下所示:
Why not make a function to echo, like this:
你想要的是 flush 方法。
例子:
what you want is the flush method.
example:
刷新看似不起作用是自动字符集检测的副作用。
浏览器在知道显示内容的字符集之前不会显示任何内容,如果您不指定字符集,它需要尝试猜测它。问题在于,如果没有足够的数据,它就无法做出好的猜测,这就是为什么浏览器似乎在显示任何内容之前需要填充这个 1024 字节(或类似)的缓冲区。
因此,解决方案是确保浏览器不必猜测字符集。
如果您要发送文本,请添加 '; charset=utf-8' 添加到其内容类型,如果是 HTML,则将字符集添加到适当的元标记。
Flushing seemingly failing to work is a side effect of automatic character set detection.
The browser will not display anything until it knows the character set to display it in, and if you don't specify the character set, it need tries to guess it. The problem being that it can't make a good guess without enough data, which is why browsers seem to have this 1024 byte (or similar) buffer they need filled before displaying anything.
The solution is therefore to make sure the browser doesn't have to guess the character set.
If you're sending text, add a '; charset=utf-8' to its content type, and if it's HTML, add the character set to the appropriate meta tag.
对于 2018 年即将到来的人:
唯一的解决方案对我有用:
保留“4096”部分非常重要,因为它似乎“填充”了缓冲区......
For those coming in 2018:
The ONLY Solution worked for me:
and its very important to keep de "4096" part because it seems that "fills" the buffer...
这就是我发现的。
Flush 在 Apache 的 mod_gzip 或 Nginx 的 gzip 下无法工作,因为从逻辑上讲,它正在对内容进行 gzip 压缩,并且要做到这一点,它必须缓冲内容以对其进行 gzip。任何类型的 Web 服务器 gzip 压缩都会影响这一点。简而言之,在服务器端我们需要禁用 gzip 并减小 fastcgi 缓冲区大小。所以:
在 php.ini 中:
在 nginx.conf 中:
手头还有这些行,特别是如果您无权访问 php.ini:
最后,如果您有,请注释下面的代码:
PHP test代码:
So here's what I found out.
Flush would not work under Apache's mod_gzip or Nginx's gzip because, logically, it is gzipping the content, and to do that it must buffer content to gzip it. Any sort of web server gzipping would affect this. In short, at the server side we need to disable gzip and decrease the fastcgi buffer size. So:
In php.ini:
In nginx.conf:
Also have these lines at hand, especially if you don't have access to php.ini:
Last, if you have it, comment the code bellow:
PHP test code:
编辑:
我正在阅读手册页上的评论,并发现一个 bug 表明
ob_implicit_flush
不起作用,以下是它的解决方法:如果这不起作用,那么甚至可能发生的情况是在服务器建立了足够的字符来发送它认为值得发送的数据包之前,客户端不会从服务器接收数据包。
旧答案:
您可以使用
ob_implicit_flush
这将告诉输出缓冲关闭缓冲一段时间:Edit:
I was reading the comments on the manual page and came across a bug that states that
ob_implicit_flush
does not work and the following is a workaround for it:If this does not work then what may even be happening is that the client does not receive the packet from the server until the server has built up enough characters to send what it considers a packet worth sending.
Old Answer:
You could use
ob_implicit_flush
which will tell output buffering to turn off buffering for a while:我遇到了同样的问题,并且手册中发布的示例之一有效。必须将字符集指定为此处已提到的海报之一。 http://www.php.net/manual/en/function .ob-flush.php#109314
I've gotten the same issue and one of the posted example in the manual worked. A character set must be specified as one of the posters here already mentioned. http://www.php.net/manual/en/function.ob-flush.php#109314