The output of your application should only contain one output encoding. If you have multiple chunks that are encoded differently, then the browser will get a result that it is impossible to work with. Hence the encoding error.
Kohana itself makes already use of the output buffer. If you want to combine that with your ob_gzhandler output buffer, you need to start your buffer before kohana initialized it's own. That's because output buffer are stackable. When kohana has finished it's output buffering, yours will apply:
ob_start('ob_gzhandler'); # your buffer:
ob_starts and ends by kohana
So whenever kohana has done some output, these chunks will get passed on into your output callback (ob_gzhandler()
) and will be gz-encoded.
The browser should then only get gz-encoded data as it was the output buffer at the topmost level.
Using ob_gzhandler and manually echo'ing the buffer
If you make use of ob_start('ob_gzhandler')
to let PHP deal with the compression and you then echo ob_get_clean()
, you will create an unreliable output. That's related to how the compression togther with output buffering works:
PHP will buffer chunks of output. That means, PHP starts to compress the output but keeps some bytes to continue compressing. So ob_get_clean() returns the so-far compressed part of the buffer. Often that result is not complete.
To deal with that, flush the buffer first:
ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
ob_flush();
$gz = ob_get_clean();
echo $gz;
And ensure you don't have any more output after that.
If you would have PHP reached the end of your script, it would have taken care of that: Flushing and outputting.
Now you need to manually call ob_flush()
to explicitly make PHP push the buffer through the callbacks.
Inspecting HTTP Compression Problems with Curl
As firefox will return an error, another tool to inspect what's causing the encoding error is needed. You can use curl
to track what's going on:
curl --compress -i URL
Will request the URL with compression enabled while displaying all response headers and the body unencoded. This is necessary as PHP transparently enables / disables compression of the ob_gzhandler
callback based on request headers.
A response also shows that PHP will set the needed response headers as well. So no need to specify them manually. That would be even dangerously, because only by calling ob_start('ob_gzhandler')
you can not say if compression is enabled or not.
In case the compression is broken, curl
will give an error description but would not display the body.
Following is such a curl error message provoked with an incompletely generated output by a faulty php script:
HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.6
Content-Encoding: gzip
...
curl: (23) Error while processing content unencoding: invalid code lengths set
By adding the --raw
switch, you can even peak into the raw response body:
curl --compress --raw -i URL
That can give an impression what's going wrong, like uncompressed parts within the body.
Content-Encoding
header manually, no, but Firebug shows that it is set correctly anyway, I have now tried manually setting it too, but no difference. I'm aware that"eh?"
isn't gzipped in my example - as I mention in the question, I just used that to show that the error occurs whether I return the gzipped content or not. I'll make that a bit clearer I think. Thanks. – Maccarthy