I need some help with PHP's flush() method in IIS
April 9, 2013 8:29 PM   Subscribe

PHP Developer Filter: I need some help with PHP's flush() method in IIS.

I have a long running PHP code block (a while loop). Within the loop, I echo updates to the end user. As expected, the echos don't appear in the browser to the user until the ENTIRE loop is completed. Since I need the echos to appear in real-time, I've tried the following:

- Calling flush() after each echo.
- Setting output_buffering to Off and implicit_flush to On in my php.ini file
- Using some fancy PHP code I found online to get flushing to work: http://screencast.com/t/aFyqMd8xlI5
- Messing around in IIS's administration.config file to explicitly set output buffering to 0 for php-cgi.exe

Alas, nothing works. I've Googled this all I can. Any help would be much appreciated.
posted by JPowers to Computers & Internet (16 answers total)
 
The docs say (emphasis added):
flush() may not be able to override the buffering scheme of your web server and it has no effect on any client-side buffering in the browser. It also doesn't affect PHP's userspace output buffering mechanism. This means you will have to call both ob_flush() and flush() to flush the ob output buffers if you are using those.
Based on that, I'd try playing with the combination of ob_flush and flush as suggested.
posted by colin_l at 8:47 PM on April 9, 2013


That's probably not the optimal way to get the effect you're looking for. It depends too much on IIS' buffering policy and the behavior of umpteen different potential client browsers. Instead you probably want to have the client poll the server for state updates until your long-running process finishes. There are fancy ways to do this with AJAX, but you may just want to try refreshing the state page periodically as a first step.
posted by axiom at 9:26 PM on April 9, 2013 [1 favorite]


I second axiom's recommendation.
posted by Kwine at 9:52 PM on April 9, 2013


I think it is unlikely to have anything to do with ob_*, unless you are working in some context where your code is wrapped by something that starts an output buffer. Not that that's impossible.

I would concur with axiom that this isn't the optimal way to handle status updates on a long-running process, but of course that may be easier said than rectified.
posted by brennen at 9:56 PM on April 9, 2013


Response by poster: I hear what you guys are saying, and it makes sense.

I'm not super familiar with AJAX (in the least), but I know how to essentially use jQuery.post() to pass data to a separate .php script, process that data, and then return a result back to the original page and print it, all without ever refreshing the original page.

However, when I try this, I don't understand how to get data back from the separate .php page (the one doing the processing) in small and separate chunks. After trying this, the data is still being returned back to the original .php page (the one with the JavaScript) as one big chunk, versus once every time I echo data.

I hope that makes sense. Essentially, can someone point me in the right direction of triggering the processing and then checking in to get the outputted data that has been generated thus far?
posted by JPowers at 10:06 PM on April 9, 2013


You might be able to use chunked transfer encoding. It's a way to stream data from the server that predates AJAX and Comet. Check this StackOverflow post for a PHP implementation.
posted by zsazsa at 10:18 PM on April 9, 2013


Best answer: Honestly, trying to stream back to the browser from a while loop isn't going to be terribly reliable. IMHO, the best way to do this is to have your while() loop get triggered from AJAX Request #1 in the page. From the loop, dump your status update to a file, database table, or some other temporary storage. And then from the page poll using AJAX Request #2, #3, #4, etc to grab the status from this temporary storage.

This is the "A"synchronous part of AJAX. You can have #1 running in the background of the browser and trigger other requests too. Just use callbacks, etc.
posted by sbutler at 11:02 PM on April 9, 2013 [1 favorite]


Response by poster: @sbutler: That is an awesome idea, and one I actually understand. Thanks!
posted by JPowers at 11:07 PM on April 9, 2013


Complete requests via AJAX are the way to go. Trying to stream from a CGI script is asking for trouble.

Out of curiosity I tried to get it to stream anyways. This almost works on my local Apache test server:
<?php
header_remove("Content-Length");
header("Content-Type: text/plain");
$s = "";
while(true) {
    for($i=0; $i<10; $i++) {
        $f = strlen($s) . "; ";
        $s .= $f;
        echo $f;
        flush();
    }
    sleep(1);
}
?>
It seems that setting ini_set("output_buffering", 0); in the PHP code itself doesn't actually do anything. I had to go change the setting in my PHP.INI (where it was, by default, 4096 bytes), then restart Apache.

Even with this off, it still won't output anything until 1024 bytes. After the first 1KB is sent it works as expected. I have no idea if this is Apache's or PHP's fault.
posted by neckro23 at 8:47 AM on April 10, 2013


Response by poster: @neckro: Thanks for the info. I'm basically seeing the same behavior in IIS, and I can't tell if it is IIS or PHP's fault.
posted by JPowers at 9:31 AM on April 10, 2013


Check this: PHP flush stopped flushing in IIS7.5. Does this describe your issue to any extent? Look at all the answers - a number of interesting ideas to try, I particularly like the one with this function:
function flush_buffers(){
    ob_end_flush();
    ob_flush();
    flush();
    ob_start();
}

posted by artlung at 9:48 AM on April 10, 2013


Response by poster: @artlung: Using that approach still doesn't work for me. I'm guessing IIS is doing something funky that prevents PHP from being able to flush correctly.
posted by JPowers at 12:00 PM on April 10, 2013


neckro23: I bet it'll work if you use chunked encoding. Here's the example from the StackOverflow above running on my server.
posted by zsazsa at 12:34 PM on April 10, 2013


Response by poster: @neckro23: IIS or Apache? Could you share your code (including your method of setting chunked encoding)?
posted by JPowers at 12:37 PM on April 10, 2013


Best answer: I assume you're talking to me! It's with Apache. Here is the source. Hopefully it works with IIS as well. Strangely enough it doesn't explicitly set chunked encoding, but looking at the HTTP response header, it's set.
posted by zsazsa at 10:15 AM on April 11, 2013


Response by poster: @zsazsa: Whoops! Wrong name! But yeah, that was exactly what I was looking for. Thanks!
posted by JPowers at 10:50 PM on April 11, 2013


« Older Alternatives to Bookmooch?   |   Photography Law in Washington State Newer »
This thread is closed to new comments.