Bypass PHP Output Buffering When Using Apache Mod_deflate

Updated about 2 yrs, 3 mths ago (April 20, 2015). Know a better answer? Let me know!

Bypass PHP output buffering when using Apache mod_deflate

Please note: This technique does not work on my current hosting. It may well work on yours so feel free to try, but the demonstration below will not function as expected.

How to output content immediately to the browser by bypassing PHP’s output buffering using flush() & ob_flush() while still using Apache mod_deflate to compress page contents.

If you’re not already compressing your site content, you probably should be. This assumes you are, and that you’re using Apache, and that you’re compressing stuff using Apache’s mod_deflate (there’s a slight performance benefit to using Apache’s mod_deflate rather than PHP’s output compression, and an obvious advantage in having Apache compress content other than just your PHP files (for example, your CSS, JavaScript, etc. files…) but that you still want to be able to serve partial page contents via PHP, using flush(), ob_flush(), etc.

As you’ve probably found, this won’t work if you’re using mod_deflate, because Apache will cache your page’s content and serve it all at once.

After much fighting, I discovered the simple fix. Add this to the PHP file you want to prevent being compressed. It disables mod_deflate for this specific file. Once you’ve done this, you can again serve partial contents.

apache_setenv('no-gzip', '1');

To enable mod_deflate to start with, you would put something similar to the below in your apache.conf file:

<Location />
# Insert filter
SetOutputFilter DEFLATE

# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip

# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

# Don't compress images
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</Location>

You would then want to make sure PHP’s output compression is disabled—now that Apache is doing that job for us. To do this, you would set this in your php.ini file:

zlib.output_compression = Off

Now your contents will be appropriately compressed, with the exception of the file you’ve set to not be compressed, and you again use flush() and ob_flush() and so on.

Here’s a small piece of sample code to demonstrate why you might want to do this:

// disable mod_deflate
apache_setenv('no-gzip', 1);

// immediately flush content to the browser
function print_right_now($text)
{
	ob_end_flush();
	print($text);
	ob_flush();
	flush();
	ob_start();
}

print_right_now("Start\n");
for($ii = 0; $ii < 100; $ii++)
{
	print_right_now("█");
	usleep(100000);
}
print_right_now("\nEnd");

Please note: This technique does not work on my current hosting. It may well work on yours so feel free to try, but the demonstration below will not function as expected.

Refresh the page to see the code (below) run again.

Start
████████████████████████████████████████████████████████████████████████████████████████████████████
End

More Information

For more information on:

 

Updated about 2 yrs, 3 mths ago (April 20, 2015). Know a better answer? Let me know!

Related categories [coloured].

User submitted comments:

Nick, about 4 yrs, 4 mths ago
Sunday March 31, 2013 1:20 AM

Thank you so much. This buffering is ridiculously annoying if you're trying to do server-side events.

Fabrizio Bartolomucci, about 3 yrs, 5 mths ago
Tuesday February 18, 2014 6:03 PM

I entered your code at:
http://www.taxiprofessional.net/iPhone/inarrivo/php/testNoBuffer.php
and you may check yourself the output, not exactly what we would expect.
What is the solution?

Comment on this article (no HTML, max 1200 characters):