php output with sleep()
Asked Answered
S

3

7

I'm trying to run a loop every second for 25 seconds basically.

for($i = 0; $i <= 25; $i += 1){ 
    echo $i;
    sleep(1)
}

The thing is it doesn't output until it's fully done, so after the loop continues 25 times. Is there a way to do this so it will output before each sleep? and not wait until the full loop is complete?

Thanks!

Schram answered 10/8, 2010 at 0:42 Comment(3)
What is your browser and content? Some browsers won't render HTML until they encounter a closing tag. Plain text might be a better option if you want "live updating" content.Footrace
This seems like a problem better dealt with on the client side. You could fetch from the server using AJAX every second.Ethaethan
this is absolutely something that should NOT be done the way you are trying on the server .. use some ajax and a setTimeout or such in the browser instead ..Transudation
J
8

What you're trying to achieve is incremental output to the browser from PHP.

Whether this is achievable can depend on your server and how you're invoking PHP.

PHP under FastCGI

You're probably a bit more likely to run into this kind of problem when PHP is running under FastCGI rather than as an Apache module, because the coupling between the server and the PHP processes is not as tightly coupled. FastCGI communication uses output buffering once the data has left the PHP processes, with the output sent to the browser only once the request is fully complete, or this buffer has filled up. On top of this, the PHP processes tend to be terminated after a certain amount of time, to avoid letting any one run for too long.

That said, a combination of ob_end_flush() (or ob_flush()) and flush() should still cause PHP to request that the downstream buffers are cleared, so this may still work. You may need to also investigate whether you need to length the time limit for PHP scripts.

PHP under mod_php

If you're using mod_php, you can write incrementally out to the browser. Use the flush() command to ensure that the PHP module will flush it instantly. If you don't have output buffering, or some Apache module such as mod_gzip, then it should go out instantly to the user's browser. What's more, you can keep your PHP script running as long as you like (with set_time_limit() in PHP), under the default configurations, though of course it will consume some memory.

You may run into trouble with some browsers which don't start rendering the page until a certain amount of a page is downloaded. Some versions of IE may wait for 1KB. I've found that Chrome can wait for more. A lot of people get around this by adding padding, such as a long comment 1 or 2 KB long at the top of the document.

Jameljamerson answered 10/8, 2010 at 2:48 Comment(0)
G
8

I just hashed through this same problem from a beginner perspective and came up with this bare-bones script which will do what you want.

<?PHP
ob_start();
$buffer = str_repeat(" ", 4096)."\r\n<span></span>\r\n";

for ($i=0; $i<25; $i++) {
  echo $buffer.$i;
  ob_flush();
  flush();
  sleep(1);
}

ob_end_flush();
?>

Questions that you may ask could be here (about \r\n) and here (about ob_flush()). Hope that helps you out.

Giddings answered 16/11, 2010 at 7:50 Comment(1)
I've tried a ton of different suggestions for Output Buffering and this is the only to actually work! Surprised this is the first to reference padding the output length.Dryfoos
W
5

Call flush will force PHP to push all of the output buffer to the client before proceeding.

for($i = 0; $i <= 25; $i += 1){ 
    echo $i;
    flush();
    sleep(1);
}

EDIT:

After testing this on my lighttpd server I noticed that it buffered my outputs in blocks of 4096 characters, and I assume other browser might have similar buffering schemes. Also GZIP can prevent flush completely. Unfortunately there is no way to test that it's working due to the nature of HTTP.

Also another issue with this strategy is that it leaves that PHP proc blocked to other requests. This can cause requests to pile up.

Whitehorse answered 10/8, 2010 at 0:43 Comment(4)
Hmm.. Didn't seem to do the trick.. also tried w/ ob_start(), ob_flush() and flush()Schram
Usually the combo of ob_end_flush() (skip the ob_start()) and flush() does it. Do you have a proxy server between you and the server running PHP?Lobar
Worked for me running via command line, but not the browser...after I put a semicolon after the sleep(1)Carboloy
@Dave try using curl via commandline, it's possible your browser is buffering it. If that's the case, you can't fix it w/o switching browsers.Whitehorse

© 2022 - 2024 — McMap. All rights reserved.