How to Flush Data to Browser But Continue Executing

How to flush data to browser but continue executing

ob_flush writes the buffer. In other words, ob_flush tells PHP to give Apache (or nginx/lighttpd/whatever) the output and then for PHP to forget about it. Once Apache has the output, it does whatever it wants with it. (In other words, after ob_flush it's out of your control whether or not it gets immediately written to the browser).

So, short answer: There's no guaranteed way to do that.

Just a guess, you're likely looking for AJAX. Whenever people are trying to manipulate when page content loads as you're doing, AJAX is almost always the correct path.

If you want to continue a task in the background, you can use ignore_user_abort, as detailed here, however, that is often not the optimal approach. You essentially lose control over that thread, and in my opinion, a web server thread is not where heavy processing belongs.

I would try to extract it out of the web facing stuff. This could mean a cron entry or just spawning a background process from inside of PHP (a process that though started from inside of script execution will not die with the script, and the script will not wait for it to finish before dying).

If you do go that route, it will mean that you can even make some kind of status system if necessary. Then you could monitor the execution and give the user periodic updates on the progress. (Technically you could make a status system with a ignore_user_abort-ed script too, but it doesn't seem as clean to me.)

Continue processing after closing connection

I finally found a solution (thanks to Google, I just had to keep trying different combinations of search terms). Thanks to the comment from arr1 on this page (it's about two thirds of the way down the page).

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true);
ob_start();
echo 'Text the user will see';
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // All output buffers must be flushed here
flush(); // Force output to client
// Do processing here
sleep(30);
echo('Text user will never see');

I have yet to actually test this but, in short, you send two headers: one that tells the browser exactly how much data to expect then one to tell the browser to close the connection (which it will only do after receiving the expected amount of content). I haven't tested this yet.

How to flush output after each `echo` call?

Edit:

I was reading the comments on the manual page and came across a bug that states that ob_implicit_flush does not work and the following is a workaround for it:

ob_end_flush();

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_start();

If this does not work then what may even be happening is that the client does not receive the packet from the server until the server has built up enough characters to send what it considers a packet worth sending.


Old Answer:

You could use ob_implicit_flush which will tell output buffering to turn off buffering for a while:

ob_implicit_flush(true);

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_implicit_flush(false);

Show results while script is still executing

You can use output buffering like this:

ob_start();

echo('doing something...');

// send to browser
ob_flush();

// ... do long running stuff
echo('still going...');

ob_flush();

echo('done.');
ob_end_flush();

Periodically output to browser on long operation

Check out flush() (http://php.net/manual/en/function.flush.php) or ob_flush() (http://www.php.net/manual/en/function.ob-flush.php).

Basically you generate your output (current status in this case) normally then force the server to output what is currently in the buffer.

If your operation is taking 10 minutes you will likely need to use set_time_limit($seconds) (http://php.net/manual/en/function.set-time-limit.php), be careful you don't just set it to some big amount in case the page does hang.

If you want to output status every 10% (1 minute) you could reset the timeout for 2 minutes after each update has been flushed. This way your script will timeout if it goes beyond expected time running.

How do you run a long PHP script and keep sending updates to the browser via HTTP?

Output Buffering is thinking in the right direction, you start output buffering with ob_start() just like you would with sessions (session_start) somewhere in the top of your script, before any output is sent.

Then, you can use ob_flush and flush to keep flushing the output. For example, if you are in a foreach loop and at the end of each loop you want to output the new row and wait 1 second you would can do that.

But also look at set_time_limit, because otherwise people might experience a timeout after 30 seconds or so.

Another quick note, some browsers require a minimum number of bytes of output before they actually start showing it. I'm not sure what amound of bytes it was, I think it was around the 4000. Also, some browsers won't render certain elements (like tables) until they are closed. So flushing won't work there either.

Send response and continue executing script - PHP

You can try something like this.

ignore_user_abort(true);
set_time_limit(0);

ob_start();
// do initial processing here
echo $response; // send the response
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();

// now the request is sent to the browser, but the script is still running
// so, you can continue...

Continue PHP execution after sending HTTP response

Have the script that handles the initial request create an entry in a processing queue, and then immediately return. Then, create a separate process (via cron maybe) that regularly runs whatever jobs are pending in the queue.



Related Topics



Leave a reply



Submit