©
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
(PHP 4, PHP 5)
flush — 刷新输出缓冲
刷新PHP程序的缓冲,而不论PHP执行在何种情况下(CGI ,web服务器等等)。该函数将当前为止程序的所有输出发送到用户的浏览器。
flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此,必须同时使用 ob_flush() 和 flush() 函数来刷新输出缓冲。
个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。
有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致 flush() 函数产生的结果不会立即被发送到客户端浏览器。
甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 </table> 标记之前,不会显示出整个表格。
一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。
[#1] php nospace juju ta ggooggle mail [2015-10-06 22:53:13]
combining some ideas i was finally able to get a long running script to give me real time feedback on what it was doing. this was a wamp setup with php running as cgi. i'm pretty sure that apache just wasn't sending any of the buffered output because it was trying to be helpful. also trying to be helpful, i hope this example solution helps someone.
<?php
// thx mandor at mandor
ini_set('max_execution_time', 0);
ini_set('implicit_flush', 1);
ob_implicit_flush(1);
echo 'doing something'; my_flush();
sleep(5);
echo 'doing something else'; my_flush();
sleep(5);
echo 'finally done - hooray';
function my_flush() {
// following matt at hevanet's lead
for ($i=0;$i<10000;$i++) echo ' ';
ob_flush();
flush();
}
[#2] ohcc at 163 dot com [2015-01-10 19:04:18]
Try to add more white spaces if your ob_flush() and flush() don't work, especially under NGINX.
However, too many white spaces can be a challenge to your web browser.
<?php
ob_clean();
while(true){
echo str_repeat(' ',1024*1024*4);
echo 'hello, world ...<br />';
ob_flush();
flush();
usleep(1000);
}
[#3] php at stelio dot net [2013-10-01 11:26:19]
For a Windows system using IIS, the ResponseBufferLimit takes precedence over PHP's output_buffering settings. So you must also set the ResponseBufferLimit to be something lower than its default value.
For IIS versions older than 7, the setting can be found in the %windir%\System32\inetsrv\fcgiext.ini file (the FastCGI config file). You can set the appropriate line to:
ResponseBufferLimit=0
For IIS 7+, the settings are stored in %windir%\System32\inetsrv\config. Edit the applicationHost.config file and search for PHP_via_FastCGI (assuming that you have installed PHP as a FastCGI module, as per the installation instructions, with the name PHP_via_FastCGI). Within the add tag, place the following setting at the end:
responseBufferLimit="0"
So the entire line will look something like:
<add name="PHP_via_FastCGI" path="*.php" verb="*" modules="FastCgiModule" scriptProcessor="C:\PHP\php-cgi.exe" resourceType="Either" responseBufferLimit="0" />
Alternatively you can insert the setting using the following command:
%windir%\system32\inetsrv\appcmd.exe set config /section:handlers "/[name='PHP_via_FastCGI'].ResponseBufferLimit:0"
[#4] Kris [2012-06-29 01:19:11]
I had a bunch of problems trying to get flush working on my windows box, I finally found a solution after reading everyones here and it not working.
1) Set output_buffering = 0
2) Set zlib.output_compression = 0
I then used Wireshark to monitor network packets, and indeed the server was pusing the data, but the browser was not displaying it.. So it was a browser buffer issue (I am on Firefox 13)
For me I needed to send about 1k of data before it would display the data. To do this I added more header information..
In php.ini I set default_charset = "utf-8"
And that was enough to give me enough for the buffer issue.
You can also try doing
echo str_repeat(" ", 1024), "\n";
at the start of the script.
hope this helps
[#5] seb dot field at gmail dot com [2010-09-18 03:52:22]
If flush() function does not work. You must set next options in php.ini like:
--[code]--
output_buffering = Off
;output_handler =
zlib.output_compression = Off
;zlib.output_handler =
--[^code^]--
If things does not work you must view headers from the server and check `Server` string.
In my case, as the frontend was Nginx webserver and Apache work as backend.
Accordingly, buffering must be disabled in Nginx config file.
To stop buffering you must add next string to config file:
--[code]--
proxy_buffering off;
--[^code^]--
and restart Nginx daemon. More information about configuration you find in documentation on the nginx website.
[#6] jason@jasonbaumgartner@info [2009-06-16 17:18:18]
Many of the suggestions below are very helpful but I would just like to clarify something.
If you are making calls to a .php script with AJAX (xmlHttpReq) and use flush, this will send data to your script HOWEVER it will not set the xmlHttpReq.readyState to 4 -- which is a requirement to use the information sent (Firefox does however allow you to use the responseText property with a readyState == 3 but IE will throw an error).
To get around this, you will need to make sure of a couple things:
In your Apache php.ini config file, check to make sure that output buffering is disabled:
output_buffering = off
Next, disable gzip compression for the .php script that is called from your AJAX script by using the excellent suggestion from Mandor by placing the following at the top of your script:
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
What causes this problem is that while the php child process is running under apache, apache is waiting for the script to complete before completely closing the connection. Scripts that send information directly to the browser with echos and prints will get away with using flush followed by a sleep command and then clean up procedures. However, if you notice in the status bar of your browser window, the connection is still held open by apache until the script completed ("Transferring" ... yadda yadda).
By turning off the Apache compression, the connection is terminated directly after a flush while still giving the user the ability to run a sleep command followed by clean up code.
This bit me because the AJAX was returning <img> tags to newly created images by php. The cleanup script would then remove those images after completion.
Since Apache held the connection open, the readyState only changed to 4 AFTER my php cleanup fired -- thereby erasing the links referred to my the <img> tags.
With this solution, the readyState will change to 4 BEFORE the sleep command begins.
I hope this saves someone a lot of time and frustration. AJAX requests are an entirely different beast compared with simple outputting to a browser window.
[#7] mandor at mandor dot net [2008-12-22 19:20:14]
This is what I use to turn off pretty much anything that could cause unwanted output buffering and turn on implicit 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);
?>
If it still fails though, keep in mind that Internet Explorer and Safari have a 1k buffer before incremental rendering kicks in, so you'll want to output some padding as well.
[#8] Arerano [2008-11-16 06:58:56]
This helped me getting flushing to work.
Using apache with deflate.
Turning compression off for this script: (add it somewhere at the top of the script)
apache_setenv('no-gzip', '1');
However, this only works if php is running as a module rather than a cgi-extension and safe mode must be disabled.
You can also turn the compression off for a directory by making a .htaccess file and adding the following entry:
mod_gzip_on Off
However that affects the whole directory.
Hope I could help.
[#9] Mr.KTO [2008-10-12 06:14:47]
IE 7, Opera 9.6, any. All is quite simple. Today I just fogot what i do every night, :)
<?php
// All you need is 256 spaces first
echo str_repeat(" ", 256)."<pre>"; flush();
// and ANY TAG before \r\n
echo "working...<br/>\r\n"; flush(); sleep(1); // this in cycle
?>
[#10] Lucas [2008-08-27 15:12:01]
I just had some problems with flush() and ob_flush(). What I did to resolve this problem took me some time to figure out so I'd like to share what I came up with.
The main problem is the php setting "output_buffering" which can be set too large and will prevent your text from outputting. To change this value you can either set it in php.ini or you can add the line
php_value output_buffering "0"
to your .htaccess file. It will not work with ini_set() since it is PHP_INI_PERDIR.
Next thing is to begin with ob_start();
Then you need
ob_flush();
flush();
before any echo or print.
Your code might look like this:
<?php
ob_start();
for($i=0;$i<70;$i++)
{
echo 'printing...<br />';
ob_flush();
flush();
usleep(300000);
}
?>
Hope this helps anyone with the same problems.
[#11] David [2008-05-07 14:32:11]
mod_security 2.x core rules will also prevent flush() from working.
[#12] chuck at artistan dot org [2007-06-27 06:57:27]
had problems flushing tables to screen.
this worked for me
<?php
if (ob_get_level() == 0) ob_start();
loop{
tables and stuff
echo str_pad("<br>\n",8);
}
ob_flush();
flush(); // needed ob_flush
usleep(50000);// delay minimum of .05 seconds to allow ie to flush to screen
?>
[#13] mbilliet at gmail dot com [2007-05-13 03:13:22]
Hello,
I had the same problems with sending a javascript after the <body></body> content has been sent to the browser (the script updates the content of an iframe).
Two solutions work for me:
- add enough data (i.e.: extra dummy text like spaces) or,
- echo the '</body>' tag at the end of the page
Note, that for the latter to work one should:
- turn of output_buffering in php.ini and either:
* turn on implicit_flush in its php.ini or,
* call ob_implicit_flush(); at the beginning of a script
I preferr echoing the '</body>' tag at the end as it doesn't require any extra data to be sent over the wire and its much a neater coding technique.
Notes:
- these worakarounds aren't needed when using perl and cgi,... .
- you can leave the zlib.output_compression in your php.ini switched on
Kind regards and hoped this is of any help.
Maurits
[#14] macott[D0T]daiato[4T]gmail[D0T]com [2007-04-24 00:17:07]
If flush() don't work remember to check if you have any antivirus caching the data sent to the browser.
[#15] Leon [2007-03-30 04:14:13]
I've spent days trying to figure out why flush didn't work all of a sudden, while it used to work perfectly. Apparently, it was McAfee Spamkiller that caused problems. Disabling it didn't work, I had to completely remove it. Hope this helps someone.
[#16] Kirk [2007-02-06 12:25:43]
If you're not explictly using the buffering functions, then ob_flush() is only necessary if output buffering is turned on in your php.ini file.
flush() is only necessary if implicit_flush is turned off in your php.ini file. Setting implicit_flush to on will remove the need for all these flush() calls, but it's generally only good in an extremely controlled environment. Turning on implicit_flush in a production environment can be bad.
[#17] no at spam dot com [2006-08-03 11:51:25]
ob_flush();flush();
Not the other way around, because it wont work.
[#18] vlad at modomail dot com [2006-04-05 06:46:43]
Sorry if this is off topic, but it's the closest place I could find :) I had an issue with essentially running a CPU intensive task while updating the browser with a progress bar via javascript and flushing the buffer a lot.
When the script was running, it effectively blocked other pages from running. I had a few extra httpd_preforks processes just waiting to be used, but they just sat there. I wasn't reading a file, locking database tables or anything that I would suspect an exclusive lock on, just outputting a bunch of text to the browser. I even tried throttling my loops to see if it was processor related but still had problems.
Finally, I found this in the php.ini file and changed the On to Off and it worked.
[Sockets]
; Use the system read() function instead of the php_read() wrapper.
sockets.use_system_read = Off
Posting in case someone else has the same issue (or if someone knows why this would make a difference :) ).
[#19] mega023 at gmail dot com [2005-11-25 03:54:01]
If flush is not working probably mod_gzip is enabled.
To disable it just add following lines to .htaccess
<IfModule mod_gzip.c>
mod_gzip_on no
</IfModule>
[#20] mikael at oebb dot net [2005-10-03 01:47:21]
Hi all.
Been scratching my head over data NOT flushed to IE (6) even though I tried strpad 4096 chars, all headers OK, TABLE and no TABLE, flush and ob_flush - still a blank page. Tried adding a sleep(1) before flushing - and everything worked as a charm.
/Mikael
[#21] [2005-09-20 00:37:08]
In my testing, Internet Explorer 6.0 wouldn't flush anything nested in <table> or <td> tags, regardless of padding. But at the <body> level everything flushed with no fuss -- no padding or tags required.
Both Firefox 1.0 and Safari 2.0 could flush within tables, and both required a tag after the text (like <br>). Safari could flush only after the first 1024 characters where received. Firefox needed at least 8 characters per flush (but it could flush anything at the <body> level).
So the only thing that worked on all those browsers was this:
<html>
<body>
<?php // not in table tags for IE
echo str_pad('',1024); // minimum start for Safari
for ($i=10; $i>0; $i--) {
echo str_pad("$i<br>\n",8);
// tag after text for Safari & Firefox
// 8 char minimum for Firefox
flush(); // worked without ob_flush() for me
sleep(1);
}
?>
</body>
</html>
[#22] js at jeansebastien dot com [2005-07-16 23:41:46]
This will show each line at a time with a pause of 2 seconds.
(Tested under IEx and 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();
?>
[#23] MOELZE ?T GMX DOt DE (Michael) [2005-05-15 16:38:17]
It is a bit complicated to work with the funktion flush() and you have to experiment with it a bit.
So if you design a site which has a timeloop at the end that calls a other site via a form data input (Data Submit) you have
to give something out to the buffer to get that new site loaden quick.
For example:
<?php
$instant=gettimeofday();
$timenow=$instant["sec"];//Start Time
//timeloop(e.g. for security_save after 30 min)
while (1) { echo "<b></b>";//Useless (only to quickload next
//or same Site when do a switch)
flush(); //giveout buffer
$instant=gettimeofday();
$timeactual=$instant["sec"]; //get Actual Time in Secs
$flag=(($timeactual>$timenow+$diff)? 1:0);//$diff=switchTime
if ($flag) { what_do_at_switch_Time();//Sec.Save etc.etc.
$timenow=$timeactual; } //Set new Start Time
sleep(5); //Or so...(Important)
} //End of while-Loop
?>
So you can programm a security save or other function in your site and if you do a switch the upload of the new or same site (the called site) works...
[#24] Alex [2005-04-22 02:35:19]
Modified progress bar.. Works in IE, Mozilla+FF.
<html>
<head>
<style type="text/css"><!--
div {
margin: 1px;
height: 20px;
padding: 1px;
border: 1px solid #000;
width: 275px;
background: #fff;
color: #000;
float: left;
clear: right;
top: 38px;
z-index: 9
}
.percents {
background: #FFF;
border: 1px solid #CCC;
margin: 1px;
height: 20px;
position:absolute;
width:275px;
z-index:10;
left: 10px;
top: 38px;
text-align: center;
}
.blocks {
background: #EEE;
border: 1px solid #CCC;
margin: 1px;
height: 20px;
width: 10px;
position: absolute;
z-index:11;
left: 12px;
top: 38px;
filter: alpha(opacity=50);
-moz-opacity: 0.5;
opacity: 0.5;
-khtml-opacity: .5
}
-->
</style>
</head>
<body>
<?php
if (ob_get_level() == 0) {
ob_start();
}
echo str_pad('Loading... ',4096)."<br />\n";
for ($i = 0; $i < 25; $i++) {
$d = $d + 11;
$m=$d+10;
//This div will show loading percents
echo '<div class="percents">' . $i*4 . '% complete</div>';
//This div will show progress bar
echo '<div class="blocks" style="left: '.$d.'px"> </div>';
flush();
ob_flush();
sleep(1);
}
ob_end_flush();
?>
<div class="percents" style="z-index:12">Done.</div>
</body>
</html>
[#25] Marty [2005-04-14 20:33:52]
This is an extention of Rusty's comment below:
After sitting here for hours trying to make IE6 flush data out in the middle of a page (with it working perfectly in Firefox), I finally figured out the problem. IE will not display flushed data (even if it has it) unless the table that contains it is complete.
Every new element you want IE to display must not be in ANY kind of table at all. You must end all your tables.
[#26] Ghostshaw at spymac dot com [2005-04-07 04:45:08]
I would like to point out that there is a function to replace ob_flush and flush. If you set ob_implicit_flush(true); at the top of the page it will automatically flush any echo or print you do in the rest of the script.
Note that you still need a minimum amount of data to come through the browser filter. I would advice using str_pad($text,4096); since this automatically lenghtens the text with spaces to 4 KB which is the minimum limit when using FireFox and linux.
I hope this helps you all out a bit.
[#27] matt at nospamplease dot hevanet dot com [2005-03-21 10:42:03]
Like IE, Safari needs a fair amount of data before it'll display anything, actually more than explorer. The following code works for me in Firefox and Safari, and should work in IE as well.
<?php
for($i = 0; $i < 40000; $i++)
{
echo ' '; // extra spaces
}
// keeps it flowing to the browser?
flush();
// 50000 microseconds keeps things flowing in safari, IE, firefox, etc
usleep(50000);
?>
This code came from a comment on a blog discussing browser functionality with flush();
[#28] crmacd at yahoo dot com [2005-03-04 15:28:29]
I figured out a way to create a simple progress bar that is for the most part cross platform. Seeing as I got my ideas from this site it's only share to give back to the community.
Note: Something interesting about browser buffering... you have to have the <html><body> for Firefox and some other browsers to recognize items by their id in Javascript. So I recommend using some sort of header function before calling this function.
<?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();
}
?>
[#29] siggi AT june systems DOT com [2005-03-04 07:54:29]
After searching through the PHP site, google and various forums, not finding a solution to my script not outputting anything while calling flush and ob_flush, I thought of trying to tell PHP to call:
session_write_close();
before starting echo'ing. It worked like a charm. I couldn't find any references to this, so I hope this note will help someone in the future.
[#30] Squ1sher [2005-02-01 12:25:11]
On Windows xampp 1.3 with php 4.3.4 is use this functions
to force a flush.
<?php
function dummyErrorHandler ($errno, $errstr, $errfile, $errline) {
}
function forceFlush() {
ob_start();
ob_end_clean();
flush();
set_error_handler("dummyErrorHandler");
ob_end_flush();
restore_error_handler();
}
?>
ob_end_flush generates a warning, which is supressed, using the dummy-errorhander. You could also use @, but then nusphere will also print the warning.
[#31] Rusty [2004-02-24 09:25:26]
Netscape will flush the output as expected at the point it is called from within your script. IE, however, needs a boost.
IE seems to have a condition where it will flush data when it hits an end (</table>) tag AND has at least 256 chars of data.
So, pad your output with necessary spaces, wrap your progressing data around open (<table>) and end (</table>) tags, and then call flush() so that one script will work for Netscape as well.
TESTING ENVIRONMENT
IE: Ver/6.0.2800
Netscape: Ver/7.1
PHP: Ver/4.3.4
Apache: Ver/1.3.27
[#32] m@rco [2003-10-29 07:22:55]
in order to display in HTML pages something like a "progress bar" or if you want to force the web server to flush output to the browser, or the browser to flush as well, you can print a long enough "dummy" string to make the output buffer grow, as you probably know, like:
<?php
print "[";
for($i = 0; $i < 100; $i++){
$spaces.=" ";
} // for
//and then
for($i = 0; $i < 10; $i++){
for($ii = 0; $ii < 200000; $ii++){
//do something slow here
} // for
print "$spaces|";
flush();
} // for
print "]";
!', '', $buffer);
// remove tabs, spaces, newlines, etc.
$buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
return $buffer;
}
include('./template/main.css');
include('./template/classes.css');
<?php
ob_end_flush();
?>
Include in <head>:
<link rel="stylesheet" type="text/css" href="/design.php" media="all" />
[#2] anatoliy at miraline dot com [2011-04-11 09:06:15]
If you enable zlib.output_compression then level count will be increased by 1 and then this code:
<?php while (ob_get_level()) { ob_end_clean(); } ?>
will just freeze your script.
[#3] Mark [2010-06-24 13:49:41]
Wanted to speed things up and put some processing after the page has been delivered to the client. That drove me almost insane, but finally, I found a solution (php 5.2.5):
<?php
ob_start(); // outer buffer
ob_start(); // inner buffer to catch URL rewrites and other post processing
session_start(); // registers URL rewriter with inner buffer!
echo '...';
// log performance data to log files *after* delivering the page!
register_shutdown_function(array($benchmarkclass,'log_perf_data'));
// now flush output output to client
ob_end_flush();
// need to calculate content length *after* URL rewrite!
header("Content-length: ".ob_get_length());
ob_end_flush();
// now we close the session and do some arbitrary clean-up tasks
// registered using register_shutdown_function()
session_write_close();
?>
[#4] unxed [2010-03-06 06:50:03]
Remember that chromium browser (and maybe other webkit-based browsers) have some issues with ob_end_flush.
http://code.google.com/p/chromium/issues/detail?id=31410
You may use
header("Content-Type: text/plain");
to solve those issues if you do not need html.
[#5] shanep [2010-01-21 21:31:12]
It appears that ob_end_flush() is very important if you are looping. For instance if you are using a mass mailer that uses the output buffer for creating HTML content. Use ob_end_flush() to avoid server errors.
[#6] skippy at zuavra dot net [2005-07-01 02:10:53]
Apart from being mostly redundant, ob_end_flush() can be downright damaging in some weird cases.
Actual example: a particular page on an Intranet website which would appear blank on Internet Explorer 6 when ob_start('ob_gzhandler') was called in the beginning and ob_end_flush() at the end.
We couldn't figure out what made that page special no matter what we tried. The ob_ functions were placed in scripts which were include()'d by all pages just the same, but only that page did this.
Even stranger, the problem only appeared on direct browser/server connections. Whenever the connection passed through a proxy the problem dissapeared. I'm guessing some kind of HTTP encoding headers mumbo-jumbo.
Solution: unless you really need it in particular cases, remove the ob_end_flush() call and rely on the builtin, automatic buffer flush.
[#7] jhannus at 128kb dot com [2004-06-05 09:18:45]
A note on the above example...
with PHP 4 >= 4.2.0, PHP 5 you can use a combination of ob_get_level() and ob_end_flush() to avoid using the @ (error suppresion) which should probably be a little faaster.
<?php
while (ob_get_level() > 0) {
ob_end_flush();
}
?>
[#8] kriek at jonkriek dot com [2003-03-29 09:22:32]
ob_end_flush() isn't needed in MOST cases because it is called automatically at the end of script execution by PHP itself when output buffering is turned on either in the php.ini or by calling ob_start().
[#9] brett at realestate-school dot com [2002-09-26 13:01:16]
It appears that you can call ob_end_flush() regardless of whether or not output buffering was ever started using ob_start(). This can prove useful because it saves you from having to create conditional statements based on whether a particular function or include file has started output buffering. You can simply call the ob_end_flush() anyway and if there's output in the buffer, it will be sent, otherwise your script will just keep on keepin' on.