Search code examples
phpgzipcontent-lengthcontent-encodingtransfer-encoding

PHP ob_gzhandler, setting Content-Length disables gzipped output


I read some articles about setting the content-length of a file that will be served. It has some benefits comparing to chunked downloads. The server serve chunks (don't know what the size of a chunk is anyway) when the content-length is unknown.

In PHP I use the ob_gzhandler to gzip html,js and css files and other text-based content. Setting the raw content-length before gzip output, results in strange side-effects because the length does not match the length of the gzipped output. I notice a delay or the browser reports an encoding error.

I saw a trick (also on stackoverflow) to set the content-length after gzip compression to be sure it reports the correct size. But when I do this, the content is no longer compressed.

The question is, is this behaviour correct? Is gzipped content always send chuncked? Is content-length only needed for files that are not gzipped?

Here some snippets of code:

1 Results in gzipped and chunked file transfer:

ob_start('ob_gzhandler');
echo $sResult;

2 Results in normal file transfer with content-length specified (but expect gzipped and content-length):

ob_start('ob_gzhandler');
echo $sResult;
header('Content-Length: '.ob_get_length()); 

Here some pictures of http header results: 1 Gzipped and Chuncked

2 Expect Gzipped but normal transfer when set content-length


Solution

  • Found the solution/trick here: How to determine the Content-Length of a gzipped file?

    Made into this:

    // clear output buffers
    while( ob_get_level() )
     { ob_end_clean(); }
    
    < send http headers here >
    
    ob_start();
    ob_start('ob_gzhandler');
    echo $sResult;
    if( !headers_sent() )
    {
       ob_end_flush(); // Flush the output from ob_gzhandler
       header('Content-Length: '.ob_get_length());
       ob_end_flush(); // Flush the outer ob_start()
    }
    

    To me is not clear why this works but seems to work perfectly. The content is now gzipped and has a content-length (not chunked).

    To prove it, here is a screenshot:

    gzipped and content-length

    Cheers! ;-)