PHP Output buffering, Content Encoding Error caused by ob_gzhandler? - php

Can anyone explain why I am receiving the following error?
In the code, if the echo $gz; is commented out I receive no error (but also no output!), if it isn't I get (from Firefox),
Content Encoding Error
The page you
are trying to view cannot be shown
because it uses an invalid or
unsupported form of compression.
Thanks for your help, here's the code:
ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
$gz = ob_get_clean();
echo $gz;

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.

This is what phpharo does:
/** output buffring */
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false)
{
ob_start('ob_gzhandler'); ob_start();
}
else
{
ob_start();
}

Related

php readfile() terminology

When we say that a function's result is sent to output buffer, it means that the result is not visible until echoed. And for functions that output directly, we use ob_start to direct the result to the output buffer (before it hits the browser as plain html) so that we may manipulate it, and then if desired, echo it.
The result of the function readfile() is directly visible, which is the contents of a certain text file, for example. then my question is:
Why it is mentioned in php documentation that readfile() sends the contents to the output buffer ?! (while in fact it is displayed directly).
Am I missing something?
When we say that a function's result is sent to output buffer, it means that the result is not visible until echoed. No it doesn't mean that!
Because it is sent to the output buffer, which (unless you've explicitly executed an ob_start() to buffer the output before sending it to the browser) is sent directly to the browser (or whatever).
All output is sent to the output buffer, but unless you've set the buffer to hold output before sending it, it gets sent.
EDIT
Of course, a webserver may be configured to cache output until a certain volume of data has been sent, but that isn't the same as PHP output buffering
Well, when the readfile() is executed, the output goes directly to stdout.
it is useful to know this behavior when php is used as a bash script:
#!/usr/bin/php
<?php
readfile("cool.txt");
// Output cool.txt whole content
It behave differently to file_get_contents from this view.
#!/usr/bin/php
<?php
file_get_contents("js.txt");
// No output!
$cool = file_get_contents("js.txt");
echo $cool;
// Output cool.txt

reducing ajax download time of a php generating a json string

I'm using an ajax call to download a php file producing a json string out of an sql query.
So as common, The request is for this .php and in the .php I'll do the query and echo the results as json-encoded string.
The file is about 850Kb (2500 records..), so it take a while to get it. I was searching for a way to reduce the download time. I was thinking of activating some kind of apache compression, just like css or js, but:
don't know if it's a good idea in this case
don't know exactly the htaccess syntax and mime type. And have I to compress a json mime or a php one?
Anyone has already solved this kind of issues?
:)
You should try using ob start with ob_gzhandler before outputting the result in your ajax script. This will compress your output and reduce render time.
ob_start("ob_gzhandler");
Read manual entry here: http://php.net/manual/en/function.ob-gzhandler.php
So my php code would be
<?php
//get all processing done.assuming $json_result holds output.
ob_start("ob_gzhandler");
echo $json_result;
ob_end_flush();
exit;
?>
Make sure that nothing is output to buffer in your script before hand like custom headers or any other prints.

PHP output buffer issue when using ob_gzhandler and ob_clean together

I'm having a hard time figuring out the problem in the following code, I really need a solution to this.
Consider the following code :
<?php
//starting a new output buffer, with a GZIP compression
ob_start("ob_gzhandler");
//this goes into the buffer
echo "Hi";
//grabbing the buffer's content
$content = ob_get_contents();
//cleaning the buffer
ob_clean();
//we're still inside the buffer, show the content again
echo $content;
This code fails to output "Hi", instead I see "‹óÈM", what have done that broke correct buffering? Knowing that once I remove "ob_gzhandler", the buffering is correct and everything is fine. I don't want to create another buffer and destroy the current one. I just want to clean the current one using ob_clean.
Any ideas? Thanks in advance.
Thank you for your answer, I figured out why, GZIP is insalled on my machine by the way, it's that when setting ob_gzhandler, the buffer is compressed chunk by chunk, so when using ob_get_contents(), parts of the last chunck are missing, and I end up getting weird output.
To correct that behaviour (or at least to bypass it), open a second output buffer, and leave the one with gzhandler() alone.
Like this
ob_start("ob_gzhandler");
ob_start();
Now the second one isn't compressed, I can do whatever I want with it (hence get its content, clean it etc). The content will be compressed anyway given that a higher level output buffer with gzhandler is opened.
Maybe you don't have gzip compression enabled/installed on your machine.
Tried your code and got something like that. I don't have gzip installed on my machine, try this:
It's your code but with a condition, if gzip doesn't start, the buffer starts.
//starting a new output buffer, with a GZIP compression
if (!ob_start("ob_gzhandler")) ob_start();
//this goes into the buffer
echo "Hi";
//grabbing the buffer's content
$content = ob_get_contents();
//cleaning the buffer
ob_clean();
//we're still inside the buffer, show the content again
echo "<pre>"; echo $content; echo "</pre>";
ob_end_flush();
If you get "Hi", maybe gzip is not installed.

What do ob_start and ob_gzhandler functions really do

I know that ob_start turns on output buffering, but I don't fully understand what it means. To me it means that it just stops outputting the script data.
Is this true? How does the browser output data in this case, do I have to use ob_end_flush() to turn it off in the end?
Since ob_gzhandler compresses web pages, how do browsers handle these pages?
I have seen ob_start("gzhandler") in code, since ob_gzhandler compresses web pages, what does ob_start("gzhandler") mean and how does it apply to both functions?
All help appreciated!
Output buffering means that instead of writing your output directly to the stdout stream, it is instead written to a buffer.
Then when the script finishes (or when you call ob_end_flush()), the contents of that buffer are written to stdout.
Using ob_gzhandler transforms the contents of the buffer before writing it to stdout, such that it is gzip compressed. (Browsers which support gzip compression reverse this on the opposite end, decompressing the content.)
Ok, let me explain it like this,
It is only one of the uses of the buffer system but I think it's kinda cool.
first I want you to look to this animation.
Operating System Start
When you have a php script that has a level based structure like this, for example you may write:
Connection established to database server..
Database selected : my_database
Data query started
Data query ended (found:200 rows)
...
etc. but if you don't use output buffering and flushing, you will see these lines when all of your script execution ends. But, when the thought is "I want to see what my script is doing when!", you first need to..
Sorry you first need to set implicit_flush to "on" at your php.ini file and restart your apache server to see all of this.
second, you need to open the output buffering (shorthand "ob") by "ob_start();", and then,
place anywhere on your code "echo" statements and after that "ob_flush();" commands to see your script running on realtime.
Later, it is also used for file based static content buffering like this:
place ob_start() at the start of your page (or the start of content you want to capture)
place ob_end_flush() at the end of your page (or the end of content you want to capture);
then $my_var = ob_get_contents(); to get all the HTML output that server creates and sends to the client into my_var variable and then use it as you want. Mostly it's saved to a file and by checking the file's last modification date, it's used as a static buffering.
I hope I could light some bulbs on your mind.

Get self web content

I have a php that makes some maintenance operations in my web and I need that the last operation it'll do is to save into a file the content of the screen. I mean, self content.
If the screen shows: "OP1 - OK ..." it has to save into a file this: "OP1 - OK ...".
Saving all the results of my operations into a variable will very hard for me. That's why I need to get the content of the self screen.
Is there any way to do this?
I think you can use an output buffer.
The following is from ob_start's php manual page:
This function will turn output buffering on. While output buffering is active no output is sent from the script (other than headers), instead the output is stored in an internal buffer.
The contents of this internal buffer may be copied into a string variable using ob_get_contents(). To output what is stored in the internal buffer, use ob_end_flush(). Alternatively, ob_end_clean() will silently discard the buffer contents.

Categories