Question

I have quite a long data mining script, and in parts of it I echo some information to the page (during a foreach loop, actually.)

However I am noticing that the information is being sent to the browse not immediately as I had hoped, but in 'segments'.

Is there some function I can use after my echo to send all the data to the browser immediately?

Thanks.

Was it helpful?

Solution

You probably want flush(). However, PHP may be using output buffering. There are a few ways that this can change things, but in a nutshell, you can flush(), then ob_flush().

OTHER TIPS

You can try using flush() after each echo, but even that won't guarantee a write to the client depending on the web server you're running.

Yes, padding your output to 1024 bytes will cause most browsers to start displaying the content.

But we also learn from @nobody's answer to question "How to flush output after each `echo` call?" that the 1024 bytes browser buffering effect only happens when the browser has to guess the character encoding of the page, which can be prevented by sending the proper Content-Type header (eg. "Content-Type: text/html; charset=utf-8"), or by specifying the content charset through appropriate html meta tags. And it worked as well for me in all browsers.

So basically, all one need to do is:

header('Content-Type: text/html; charset=utf-8');
ob_implicit_flush(true);

With no requirement for extra padding or flushing, which is of great cosmetic benefit for the code! Of course, headers have to be sent before any content, and one also has to make sure no output buffering is going on.

Problem definitely solved for me! Please (+1) @nobody's answer on the other question as well if it works for you. If, although, one still encounters problems, I suggest checking out the answers to that other question for other specific situations that might presumely prevent implicit flushing from working correctly.

Note also that some browsers won't start displaying anything until the body of the response contains a certain amount of data - like 256 or 1024 bytes. I have seen applications before that pad data with a 1024 character long comment near the top of the page, before they do a flush. It's a bit of a hack, but necessary.

This applies to Internet Explorer and Safari IIRC.

So,

  • If it is the first flush, make sure you have output at least 1024 bytes sofar (not including HTTP headers).
  • Call flush()
  • If you can determine that there is output buffering in place, issue ob_flush()

I like to just use

while (ob_get_level()) ob_end_flush();

near the start of my script somewhere, and then just

flush();

whenever I want to flush. This assumes that you don't want any output buffering at all, even if it was set up before your script (such as in a PHP.ini or htaccess configuration).

You should be able to use something like this to force output to be sent immeadiately. Put it at the part of the code you want the output to be sent.

flush();
ob_flush();

Phew! I finally found the answer to Google Chrome's buffer issue! Thanks to boysmakesh for the push in the right direction. Here's the function I use:

function buffer_flush(){

    echo str_pad('', 512);
    echo '<!-- -->';

    if(ob_get_length()){

        @ob_flush();
        @flush();
        @ob_end_flush();

    }

    @ob_start();

}

And this is how I call it:

show_view('global', 'header'); // Echos the <html><head>... tags and
                               // includes JS and CSS.

show_view('global', 'splash_screen'); // Shows a loading image telling
                                      // the user that everything's okay.

buffer_flush(); // Pretty obvious. At this point the loading view shows
                // up on every browser i've tested (chrome, firefox,
                // IE 7 & 8)

show_view('global', 'main'); // Has a loop that echos "Test $i<br>" 5
                             // times and calls buffer_flush() each time.

show_view('global', 'footer'); // End the html page and use JQuery to
                               // fade out the loading view.

To perfectly work this out in Google chrome, try this:

$i = 0;
$padstr = str_pad("",512," ");
echo $padstr;

while ($i <= 4){
    $padstr = str_pad("",512," ");
    echo $padstr;
    echo "boysmakesh <BR> ";
     flush();
    sleep(2);
    $i = $i + 1;
}

Ee are sending 512 bytes before sending EACH echo. Don't forget to put <BR> at the end of content before you flush. Else it won't work in Chrome but works in IE.

The data we padding is browser dependent. For some browsers it's enough to have 256 bytes but some need 1024 bytes. For chrome it is 512.

ignore_user_abort(TRUE); // run script in background
set_time_limit(0); // run script forever
$interval=150000;
$i = 0;

if(
  strpos($_SERVER["HTTP_USER_AGENT"], "Gecko") or
  strpos($_SERVER["HTTP_USER_AGENT"], "WebKit")
){
  # important to change browser into quirks mode
  echo '<?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
}

function buffer_flush(){
    echo "\n\n<!-- Deal with browser-related buffering by sending some incompressible strings -->\n\n";
    for ( $i = 0; $i < 5; $i++ )
        echo "<!-- abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono -->\n\n";

    while ( ob_get_level() )
        ob_end_flush();

    if(ob_get_length()){
        @ob_flush();
        @flush();
        @ob_end_flush();
    }
    @ob_start();
}

ob_start(); 

do{

  if($i<10){
    buffer_flush(); 
    echo ". ";    
    buffer_flush(); 
    usleep($interval);

  } else {
    echo sprintf("<pre>%s</pre>", print_r($_SERVER,true));
    break;
  }

  $i++;

}while(true);

Running php 5.5 on IIS 7, IE 11 (win server) I found this worked as the opening lines of the file. Note putting the while statement before the header caused a header already written error.

header('Content-Type: text/html; charset=utf-8');
while (ob_get_level()) ob_end_flush();
ob_implicit_flush(true);

Further references to ob_flush() in the script caused a buffer does not exist error.

This worked fine when I was processing a file and sending sql statements to the browser, however when I hooked up the db (ms server 2008) I had no input returned till the script had completed.

this combination finally worked for me, based on thomasrutter's answer

while (ob_get_level()) ob_end_flush();
ob_implicit_flush(true);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top