13

I've tried several attempts at getting my flush and ob_flush to work. I've tried setting the ini to allow buffering, I've tried using several different functions I found online for output buffering, and none of it at all is working. The script wants to wait until it is completly done until it echos output. Here is the script I have so far

 ob_start();

 //Login User
 echo 'Logging in to user<br>';
       ob_flush();
       flush();
      $ch = curl_init("http://www.mysite.com/login/");
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, "username=$user&pass=$pass");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_COOKIEJAR, "cookies/$cookie");
      curl_setopt($ch, CURLOPT_COOKIEFILE, "cookies/$cookie");
      $output = curl_exec($ch);
      curl_close($ch);
      ob_flush();
      flush();

       //Update Status
 echo 'Updating Status<br>';
       ob_flush();
       flush();
      $ch = curl_init("http://www.mysite.com/update/");
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, "status=$status");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_COOKIEJAR, "cookies/$cookie");
      curl_setopt($ch, CURLOPT_COOKIEFILE, "cookies/$cookie");
      $output = curl_exec($ch);
      curl_close($ch);
      ob_flush();
      flush();

I want it to echo what it is doing, then run the function, then echo something else, then do another function. I want all the buffers to be flushed and echoed in real time on the browser.

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
JakeSmith
  • 131
  • 1
  • 1
  • 3

8 Answers8

48

The idea here is to disable output buffering, not enable it. As its name says, output buffering will save the output to memory and display it at the end of the script, or when explicitly asked for it.

That being said, you don't have to flush explicitly for every output. Use the following, before displaying any output, and then you won't have to bother flushing every time you echo something:

ob_implicit_flush(true);
ob_end_flush();

Per example:

ob_implicit_flush(true);
ob_end_flush();

for ($i=0; $i<5; $i++) {
   echo $i.'<br>';
   sleep(1);
}

Will output, 0 to 4, with each being displayed every second.

netcoder
  • 66,435
  • 19
  • 125
  • 142
  • the above works perfectly for me. Been having the same issue. Thanks! – jrtashjian Dec 21 '10 at 00:00
  • 6
    anyone know why i cant get this working? I paste this in, and run it in chrome... no luck. it only outputs all of it at once. – timh Jun 07 '11 at 04:21
  • 1
    @timh: Chrome has [a known issue](http://code.google.com/p/chromium/issues/detail?id=31410) of this not working properly. – netcoder Jun 07 '11 at 11:57
  • @netcoder: it happens even for opera. Still not working at all. – Martin. Dec 11 '11 at 01:52
  • 2
    In every browser I try, the above code waits for 5 seconds, and then outputs everything at once. Might my hosting company be doing something to the buffering? – Dan Goodspeed Jan 08 '14 at 06:43
  • 1
    @DanGoodspeed: It's definitely possible. Some load balancers will buffer output, independently of how PHP is configured. Apache can too, using mod_buffer per example. – netcoder Jan 08 '14 at 13:20
  • Any suggestions for what else I can try? – Dan Goodspeed Jan 09 '14 at 11:13
  • 1
    This doesn't work for PHP FPM, I even disabled output_buffering – Adrian Aug 12 '17 at 06:31
  • Works. But that's only one side on the coin - you should also set up you webserver to do the trick. For my IIS solution was here - https://stackoverflow.com/questions/7178514/php-flush-stopped-flushing-in-iis7-5 – Anton Apr 24 '19 at 10:49
  • Still an issue for me using WAMP and a WordPress install... Everything outputs all at once when the function finishes... No onMessage event triggered until the end. – Andrew Schultz May 11 '22 at 00:43
10

I just wanted to write a quick note of what I've observed, now in 2016, of the different approached suggested:

The above codes offered by netcoder and David work for me in the following browsers:

  • Chrome
  • Opera

It does not seem to work in Firefox, Safari, or IE 10-11.

I've also tested the alternative code:

<?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();
?>

Which can be found here: http://php.net/manual/en/function.flush.php#54841

Which seems to have better current support through all browsers:

  • Chrome
  • Firefox
  • Opera
  • Safari
  • IE 10
  • IE 11

The working implementations seem to change year to year, so I wanted to offer an update of what I've found myself to work at the moment.

Prusprus
  • 7,987
  • 9
  • 42
  • 57
  • 1
    See the answer from Maxime Fafard, you have to disable gzip compression on your webserver for this to work. – ahofmann Nov 21 '20 at 09:41
6

Please note that you may need to disable gzip compression on your webserver (apache or nginx).

It was my issue.

Maxime Fafard
  • 370
  • 2
  • 8
3
<?php
    header('Content-Type: text/html; charset=utf-8');

    // I think maybe you can set output_buffering using ini_set here, but I'm not sure.
    // It didn't work for me the first time at least, but now it does sometimes...
    // So I set output_buffering to Off in my php.ini,
    // which normally, on Linux, you can find at the following location: /etc/php5/apache2/php.ini

    @ini_set('output_buffering','Off');
    @ini_set('zlib.output_compression',0);
    @ini_set('implicit_flush',1);
    @ob_end_clean();
    set_time_limit(0);
    ob_start();

    //echo str_repeat('        ',1024*8); //<-- For some reason it now even works without this, in Firefox at least?
?>
<!DOCTYPE html>
<html>
    <head>
        <title>PHP Flushing</title>
    </head>
    <body>
        <h1>Flushing the webpage in real-time using PHP.</h1>
<?php
    ob_flush();
    flush();

    //Note: ob_flush comes first, then you call flush. I did this wrong in one of my own scripts previously.
    for($i=0; $i<5; $i++) {
        echo $i.'<br>';
        ob_flush();
        flush();   
        sleep(1);
    }
?>
    </body>
</html>
2

This question seems to pop up a lot on a Google search, so I wanted to update it. It's September 2014.....

@Netcoder 's answer does work, but Chrome will sometimes still output everything all at once.

To fix this, simply added an ob_flush(), and flush() in the code, it will output after each second.

Example:

ob_implicit_flush(true);
ob_end_flush();

for ($i=0; $i<5; $i++) {
    echo $i.'<br>';
    ob_flush();
    flush();   
    sleep(1);
}   
David
  • 2,094
  • 3
  • 30
  • 47
  • This results in: "ob_flush(): failed to flush buffer. No buffer to flush" in my Chrome browser. – ESP32 Jul 10 '17 at 09:21
1

Updated for 2021

I had this same problem and I used basically the solution from Imanuel Habekotte

in my .htaccess file;

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI .*/my_file_name.php$ no-gzip dont-vary

Then in my php code file (my_file_name.php);

header('Content-Type: text/octet-stream; charset=utf-8');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.


    ini_set('max_execution_time', 0);
    @ini_set('output_buffering','Off');
    @ini_set('zlib.output_compression',0);
    @ini_set('implicit_flush',1);
    @ob_end_clean();
    set_time_limit(0);
    ob_start();
    ob_implicit_flush(true);


/**
    Send a partial message
*/
function send_message($id, $message, $progress) 
{
    $d = array('message' => $message , 'progress' => $progress);
    
    echo json_encode($d) . PHP_EOL;
    
    echo str_pad('',8192)."\n";
    
    //PUSH THE data out by all FORCE POSSIBLE
    ob_flush();
    flush();
}
Anthony
  • 168
  • 1
  • 10
  • 1
    Note that "text/octet-stream;" in the Header will start a file download with the output instead of printing it. – Lorien Brune Nov 10 '22 at 21:01
  • Yes, in my case the declaration as `text/octet-stream` alone is enough to circumvent the gzip compression of the (Apache) server of my web hoster, and make a successful flush. But as Lorien said, then the browser would not render the HTML response any more (but just show the source code). – bass-t Jan 27 '23 at 16:14
0

I have had the same problem but a user pointed me out in the right direction, I used a "for" loop to solve this browser specific issue:

for($i = 0; $i < 5000; $i++)
{
    echo ' ';
}

Relate to Outputting exec() ping result progressively for more details.

Community
  • 1
  • 1
ner0
  • 84
  • 1
  • 9
0

this works now (at least on php 5.5)

ob_end_flush();
while(stuff){
  ..stuff...
  echo('yo');
  flush();
}

no need to sleep or anything else

user151496
  • 1,849
  • 24
  • 38