这将每次显示一行,并暂停 2 秒。
(在 IEx 和 Firefox 下测试)
<?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();
?>
(PHP 4、PHP 5、PHP 7、PHP 8)
flush — 刷新系统输出缓冲区
刷新 PHP 及 PHP 使用的后端(例如:CGI、Web 服务器)的系统写入缓冲区。在命令行环境中,flush() 将尝试仅刷新缓冲区内容,而在 Web 上下文中,将刷新标头和缓冲区内容。
注意: flush() 可能无法覆盖 Web 服务器的缓冲方案,并且对浏览器中的任何客户端缓冲没有任何影响。
注意: 此函数对用户级输出处理程序(例如由 ob_start() 或 output_add_rewrite_var() 启动的处理程序)没有任何影响。
flush() 会干扰在 Web 上下文中设置和发送标头的输出处理程序(例如 ob_gzhandler()),因为它会在这些处理程序能够这样做之前发送标头。
此函数没有参数。
不返回值。
版本 | 描述 |
---|---|
8.4.0 | 现在可以在 FastCGI 中成功刷新标头而无需正文。 |
这将每次显示一行,并暂停 2 秒。
(在 IEx 和 Firefox 下测试)
<?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();
?>
这就是我用来关闭几乎所有可能导致意外输出缓冲并打开隐式刷新的内容。
<?php
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
?>
如果仍然失败,请记住 Internet Explorer 和 Safari 在增量渲染开始之前有一个 1k 的缓冲区,因此您还需要输出一些填充。
如果您希望在使用 Apache httpd 带有 mod_proxy_fcgi 的 php-fpm 时使 flush 工作,则从 2.4.31 开始,您可以附加 flushpackets=on 以启用刷新(默认情况下是即时的),以及 flushwait=n,其中 n 以毫秒为单位延迟刷新时间以提高性能。
这些值可以附加到 <Proxy> 指令,例如 <Proxy "fcgi://127.0.0.1/" flushpackets=on flushwait=500> 或在 ProxyPass 和 ProxyPassMatch 行中。
2.4 的 mod_proxy_fcgi 文档没有记录这一点,但它在 2.5 或 trunk 文档中可用。
我想指出,有一个函数可以替换 ob_flush 和 flush。如果您在页面的顶部设置 ob_implicit_flush(true);,它将自动刷新您在脚本其余部分执行的任何 echo 或 print。
请注意,您仍然需要最少的数据才能通过浏览器过滤器。我建议使用 str_pad($text,4096);,因为它会自动用空格将文本长度扩展到 4 KB,这是使用 FireFox 和 Linux 时的最小限制。
希望这对大家有所帮助。
关于浏览器的缓冲,您可以使用
$out=str_pad($yourMessage.'<br/>',1024);
print($out);
ob_flush();
flush();
在我的 Firefox 60 ESR 中有效。
对于使用 IIS 的 Windows 系统,ResponseBufferLimit 优先于 PHP 的 output_buffering 设置。因此,您还必须将 ResponseBufferLimit 设置为低于其默认值。
对于低于 7 的 IIS 版本,可以在 %windir%\System32\inetsrv\fcgiext.ini 文件(FastCGI 配置文件)中找到该设置。您可以将相应的行设置为
ResponseBufferLimit=0
对于 IIS 7+,设置存储在 %windir%\System32\inetsrv\config 中。编辑 applicationHost.config 文件并搜索 PHP_via_FastCGI(假设您已按照安装说明将 PHP 安装为 FastCGI 模块,名称为 PHP_via_FastCGI)。在 add 标记内,在末尾放置以下设置
responseBufferLimit="0"
因此,整行将如下所示
<add name="PHP_via_FastCGI" path="*.php" verb="*" modules="FastCgiModule" scriptProcessor="C:\PHP\php-cgi.exe" resourceType="Either" responseBufferLimit="0" />
或者,您可以使用以下命令插入设置
%windir%\system32\inetsrv\appcmd.exe set config /section:handlers "/[name='PHP_via_FastCGI'].ResponseBufferLimit:0"
当使用PHP的CGI/FastCGI模式时,会创建一个新的缓冲区(由mod_fcgid初始化,默认大小为65536字节)。这会导致`flush()`和`ob_flush()`在使用implicit_flush(true)时无法按预期工作。
在mod_fcgid配置中设置“OutputBufferSize 0”可以解决此问题。
希望对您有所帮助!
大家好。
我一直对数据无法刷新到IE(6)感到困惑,即使我尝试了strpad 4096个字符,所有标头都正常,有TABLE和无TABLE,flush和ob_flush - 仍然是空白页面。尝试在刷新前添加一个sleep(1) - 并且一切正常。
/Mikael
在搜索了PHP网站、谷歌和各种论坛后,没有找到解决我的脚本在调用flush和ob_flush时不输出任何内容的方案,我想尝试告诉PHP调用
session_write_close();
在开始echo之前。它像魅力一样工作。我找不到任何对此的引用,所以希望这个笔记将来能帮助到某些人。
与IE类似,Safari需要相当数量的数据才会显示任何内容,实际上比Explorer更多。以下代码在我的Firefox和Safari中有效,并且也应该在IE中有效。
<?php
for($i = 0; $i < 40000; $i++)
{
echo ' '; // 额外的空格
}
// 保持数据流向浏览器?
flush();
// 50000微秒使数据在Safari、IE、Firefox等中保持流动
usleep(50000);
?>
此代码来自一篇讨论浏览器与flush();功能相关的博客文章中的评论。
如果flush()函数不起作用。您必须在php.ini中设置以下选项,例如
--[code]--
output_buffering = Off
;output_handler =
zlib.output_compression = Off
;zlib.output_handler =
--[^code^]--
如果问题仍然存在,您需要查看服务器的头部信息并检查`Server`字符串。
在我的例子中,前端是Nginx web服务器,Apache作为后端工作。
因此,必须在Nginx配置文件中禁用缓冲。
要停止缓冲,您必须在配置文件中添加以下字符串
--[code]--
proxy_buffering off;
--[^code^]--
并重启Nginx守护进程。有关配置的更多信息,请参阅nginx网站上的文档。
结合了一些想法,我终于能够让一个长时间运行的脚本实时反馈它正在做什么。这是一个WAMP设置,PHP以CGI方式运行。我非常确定Apache没有发送任何缓冲的输出,因为它试图提供帮助。同样,为了提供帮助,我希望这个示例解决方案对某些人有所帮助。
<?php
// 感谢mandor at mandor
ini_set('max_execution_time', 0);
ini_set('implicit_flush', 1);
ob_implicit_flush(1);
echo '正在执行某些操作'; my_flush();
sleep(5);
echo '正在执行其他操作'; my_flush();
sleep(5);
echo '最终完成 - 万岁';
function my_flush() {
// 遵循matt at hevanet的思路
for ($i=0;$i<10000;$i++) echo ' ';
ob_flush();
flush();
}
我在尝试让flush在我的Windows机器上工作时遇到了一堆问题,在阅读了这里每个人的建议并且都不起作用后,我终于找到了一个解决方案。
1) 设置output_buffering = 0
2) 设置zlib.output_compression = 0
然后我使用Wireshark监控网络数据包,服务器确实在推送数据,但浏览器没有显示它。所以这是一个浏览器缓冲区问题(我使用的是Firefox 13)
对我来说,我需要发送大约1k的数据才能显示数据。为此,我添加了更多标头信息。
在php.ini中,我设置了default_charset = "utf-8"
这足以解决缓冲区问题。
您也可以尝试执行
echo str_repeat(" ", 1024), "\n";
在脚本的开头。
希望这有帮助
这是对下面Rusty评论的扩展
在坐在这里几个小时试图让IE6在页面中间刷新数据(在Firefox中完美工作)之后,我终于找到了问题所在。IE不会显示已刷新数据(即使它已拥有数据),除非包含它的表格完整。
您希望IE显示的每个新元素都绝对不能位于任何类型的表格中。您必须结束所有表格。
使用flush()函数有点复杂,您需要对其进行一些实验。
因此,如果您设计一个网站,该网站在末尾有一个时间循环,通过表单数据输入(数据提交)调用另一个网站,则您需要
向缓冲区输出一些内容才能快速加载新网站。
例如
<?php
$instant=gettimeofday();
$timenow=$instant["sec"];// 开始时间
// 时间循环(例如,30分钟后进行安全保存)
while (1) { echo "<b></b>";// 无用(仅用于快速加载下一个
// 或在切换时加载相同的站点)
flush(); // 输出缓冲区
$instant=gettimeofday();
$timeactual=$instant["sec"]; // 获取当前时间(秒)
$flag=(($timeactual>$timenow+$diff)? 1:0);//$diff=切换时间
if ($flag) { what_do_at_switch_Time();// 安全保存等
$timenow=$timeactual; } // 设置新的开始时间
sleep(5); // 或其他操作(重要)
} // 结束while循环
?>
因此,您可以为您的网站编写安全保存或其他功能,并且如果您进行切换,新网站或相同网站(被调用的网站)的加载将正常工作。
我花了几天时间试图找出为什么flush突然停止工作,而它以前一直完美地工作。显然,是McAfee Spamkiller导致了问题。禁用它不起作用,我不得不完全删除它。希望这能帮到某些人。
如果您没有明确使用缓冲功能,则只有在php.ini文件中启用了输出缓冲时,才需要ob_flush()。
只有在php.ini文件中关闭了implicit_flush时,才需要flush()。将implicit_flush设置为on将消除所有这些flush()调用的需要,但它通常仅适用于极受控制的环境。在生产环境中启用implicit_flush可能会很糟糕。
这帮助我让刷新工作起来。
使用带有deflate的apache。
关闭此脚本的压缩功能:(将其添加到脚本顶部的某个位置)
apache_setenv('no-gzip', '1');
但是,这仅在 php 作为模块而不是 cgi 扩展运行时有效,并且必须禁用安全模式。
您还可以通过创建 .htaccess 文件并添加以下条目来关闭目录的压缩功能
mod_gzip_on Off
但是,这会影响整个目录。
希望我能帮上忙。
在 php8.3-fpm 和 apache 2.4.57 上
为了使 flush 在浏览器中工作,您需要发送更多数据(至少 4096 字节/flush),并且需要为该站点在 apache2 配置的虚拟主机中添加一个设置
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://127.0.0.1"
</FilesMatch>
<Proxy fcgi://127.0.0.1/">
ProxySet enablereuse=on flushpackets=on
</Proxy>
您好,
我在发送 <body></body> 内容发送到浏览器后(脚本更新 iframe 的内容)的 javascript 时遇到了同样的问题。
两种解决方案对我有用
- 添加足够的数据(例如:额外的虚拟文本,如空格),或者,
- 在页面末尾回显 '</body>' 标签
请注意,要使后者起作用,应
- 在 php.ini 中关闭 output_buffering,并同时
* 在 php.ini 中打开 implicit_flush,或者,
* 在脚本开头调用 ob_implicit_flush();
我更喜欢在末尾回显 '</body>' 标签,因为它不需要发送任何额外的数据,并且是一种更简洁的编码技术。
注释
- 使用 perl 和 cgi 时不需要这些解决方法。
- 您可以将 php.ini 中的 zlib.output_compression 保持开启状态
此致,希望对您有所帮助。
Maurits
我想出了一个创建简单进度条的方法,该进度条在很大程度上是跨平台的。由于我从这个网站获得了想法,因此分享给社区是理所应当的。
注意:关于浏览器缓冲的一些有趣的事情……您必须拥有 <html><body> 才能使 Firefox 和某些其他浏览器通过 Javascript 识别项目的 id。因此,我建议在调用此函数之前使用某种标头函数。
<?php
function fn_progress_bar($intCurrentCount = 100, $intTotalCount = 100)
{
static $intNumberRuns = 0;
static $intDisplayedCurrentPercent = 0;
$strProgressBar = '';
$dblPercentIncrease = (100 / $intTotalCount);
$intCurrentPercent = intval($intCurrentCount * $dblPercentIncrease);
$intNumberRuns++;
if(1 == $intNumberRuns)
{
$strProgressBar = <<< BAR
<table width='50%' id='progress_bar' summary='progress_bar' align='center'><tbody><tr>
<td id='progress_bar_complete' width='0%' align='center' style='background:#CCFFCC;'> </td>
<td style='background:#FFCCCC;'> </td>
</tr></tbody></table>
<script type='text/javascript' language='javascript'>
function dhd_fn_progress_bar_update(intCurrentPercent)
{
document.getElementById('progress_bar_complete').style.width = intCurrentPercent+'%';
document.getElementById('progress_bar_complete').innerHTML = intCurrentPercent+'%';
}
</script>
BAR;
}
else if($intDisplayedCurrentPercent <> $intCurrentPercent)
{
$intDisplayedCurrentPercent = $intCurrentPercent;
$strProgressBar = <<< BAR
<script type='text/javascript' language='javascript'>
dhd_fn_progress_bar_update($intCurrentPercent);
</script>
BAR;
}
if(100 <= $intCurrentPercent)
{
$intNumberRuns = $intDisplayedCurrentPercent = 0;
$strProgressBar = <<< BAR
<script type='text/javascript' language='javascript'>
document.getElementById('progress_bar').style.visibility='hidden';
</script>
BAR;
}
echo $strProgressBar;
flush();
ob_flush();
}
?>