PHP Flush/ob_flush not working
Asked Answered
R

8

14

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.

Respect answered 19/12, 2010 at 2:4 Comment(2)
The toilet probably break before that lolMorello
Here is a solution - https://mcmap.net/q/168825/-how-to-flush-output-after-each-echo-callScary
M
51

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.

Mcguire answered 19/12, 2010 at 4:28 Comment(10)
the above works perfectly for me. Been having the same issue. Thanks!Gull
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.Hyphenated
@timh: Chrome has a known issue of this not working properly.Mcguire
@netcoder: it happens even for opera. Still not working at all.Heterochromosome
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?Simmer
@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.Mcguire
Any suggestions for what else I can try?Simmer
This doesn't work for PHP FPM, I even disabled output_bufferingBiogen
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 - #7179014Deep
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.Yell
B
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.

Brill answered 25/1, 2016 at 15:44 Comment(1)
See the answer from Maxime Fafard, you have to disable gzip compression on your webserver for this to work.Erdah
L
6

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

It was my issue.

Long answered 24/9, 2016 at 21:25 Comment(0)
S
4
<?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>
Secrete answered 6/9, 2016 at 13:45 Comment(0)
P
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);
}   
Perimeter answered 5/9, 2014 at 2:43 Comment(1)
This results in: "ob_flush(): failed to flush buffer. No buffer to flush" in my Chrome browser.Banderole
M
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();
}
Mulligatawny answered 11/8, 2021 at 8:33 Comment(2)
Note that "text/octet-stream;" in the Header will start a file download with the output instead of printing it.Ratha
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).Amhara
S
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.

Schlemiel answered 30/5, 2012 at 11:32 Comment(0)
S
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

Sunwise answered 4/7, 2015 at 10:44 Comment(1)
No need for ob_flush()?Pannier

© 2022 - 2024 — McMap. All rights reserved.