Consider a long running php script that does many tasks and after each task it outputs the status.
echo 'Task 1 complete'; .... some delay ... echo 'Task 2 complete'; .... more delay and more tasks ...
Now for such scripts it may be important to load the contents in browser as quickly as they are generated so that the user can understand the progress of the script. If the entire output were to appear at once when its fully loaded, then the user would have to wait for long without any clue of what happened on the server. Sometimes when the internet connection suddenly goes down and comes back the connection actually breaks off, but the browser keeps loading for ever. So for such cases its very important for the script output to become visible as soon as its available.
Now ofcourse as soon as echo is called the output is supposed to reach the client/browser but there are factors that can cause side effects. The most common is buffering. Buffering can happen at the level of php, as well as the underlying server like apache for example. So each has to be dealt with to prevent them from holding the output for whatever reasons and send the output to the browser the instant it is generated.
Program Output ==> Php ==> Apache/web server ==> Browser
Now buffering can happen at any level. Php might be buffering the output due to some settings or something similar. Then it needs to be told not to do that. Next comes the apache or any other web server which might buffer the output if for example it is configured to compress the output. Last one is the browser and it too might buffer the output before actually rendering it on the screen.
Couple of lines need to be added to the code, to ensure that the output is instantly pushed and displayed to the user end. The code looks like this
// Turn off output buffering ini_set('output_buffering', 'off'); // Turn off PHP output compression ini_set('zlib.output_compression', false); //Flush (send) the output buffer and turn off output buffering //ob_end_flush(); while (@ob_end_flush()); // Implicitly flush the buffer(s) ini_set('implicit_flush', true); ob_implicit_flush(true); //prevent apache from buffering it for deflate/gzip header("Content-type: text/plain"); header('Cache-Control: no-cache'); // recommended to prevent caching of event data. for($i = 0; $i < 1000; $i++) { echo ' '; } ob_flush(); flush(); /// Now start the program output echo "Program Output"; ob_flush(); flush();
The code has 4 parts :
1. Disable output buffering. This is done turning off the php.ini settings called 'output_buffer' and 'zlib.output_compression'. Along with that implicit flush should be turned on.
2. Send out special headers to tell apache to handle the content accordingly. The content type for html content is text/html by default, but in this case it has been set to text/plain. Apache is often configured to compress html/xml/js/css content to save bandwidth of the server and user. This compression leads to buffering of the output inside apache.
Marking the content with a different content type prevents such compression.
3. Echo around 1000 white spaces. Some browser wait for a minimum number of characters to arrive from the server before starting the actual rendering. The white spaces make up for those characters and when the real output starts coming in it is displayed instantly.
4. After each chunk of output the program generates, it should call ob_flush and flush to further ensure that php pushes output the output to the web server instantly.
Hello,
The code still not working, it’s got stuck because of Suphp, is there any way to stop the buffering by suphp.
You big man. This is thing that I searched. Thanks.
It has worked perfectly for me. Thanks for sharing the code
How can you call ob_flush() if ob_start() is never called to create the buffer?
ob_implicit_flush(true);
set_time_limit(0);
$results=1200;
for($i=0;$i<1200;$i++)
{
ob_start();
echo $i."”;
sleep(1);
ob_end_flush();
ob_flush();
}
use this code to accomplish the tasks.
<?php
ob_implicit_flush(true);
set_time_limit(0);
$results=1200;
for($i=0;$i<1200;$i++)
{
ob_start();
echo $i."”;
sleep(1);
ob_end_flush();
ob_flush();
}
?>
I’ve been trying to do this for long time and this is it. I really appreciate this code.
If you wan to output in html then rem out this line:
// header(“Content-type: text/plain”);
Hi
ini_set(‘output_buffering’, ‘off’); according to http://php.net/manual/en/ini.list.php, setting this at runtime is not going to work, to be sure I have made a test, and indeed, in_get returns the value which is set in php.ini.
I recently discovered that many Anti-Virus programs buffer the browser display, and all my ob_flush’ing didn’t help until I disabled the AV web protection for my server… :-/
No way even with those suggestions. Bufferings stucks, is there some way to better know where?
nice, this is what i was looking for for my crawler project.
awesome!!! you are the best!!!