Reputation: 73808
headers_sent will tell me when output was sent to the browser. However, it can be that no body was sent, e.g. 302 redirect.
How do I tell in register_shutdown_function context what content has been sent to the browser, or at least what was Content-Length
.
Upvotes: 1
Views: 1941
Reputation: 157947
The content lenght header will no being set by apache if it is a PHP script. This is because the webserver can't know about this as the content is dynamically created. However the headers have to sent before the body. So the only way to get the length of the content is to generate it, obtain it's length, send the header and then send the content.
In PHP you can use ob_*
set of functions (output buffering) to achieve this. Like this:
ob_start();
echo 'hello world'; // all your application's code comes here
register_shutdown_function(function() {
header('Content-Length: ' . ob_get_length());
ob_end_flush();
});
Warning This will be unreliable if you are using gzip
encoded transfer. There has been posted a workaround on the PHP web site,
Also you might need to know that output buffers can be nested in PHP. If there is another ob_start()
call in my example above than you'll end up seeing nothing in the browser because just the inner buffer gets flushed (into the outer one)
The following example takes care on this. In order to ease the process it just overwrites the header multiple times, which shouldn't be a performance issue as header()
is basically a simple string operation. PHP sends the headers only before some output or at the end of the script.
Here comes the code which has been tested gzip safe and works reliable with nested unclosed buffers:
ob_start('ob_gzhandler');
echo 'hello world';
// another ob_start call. The programmer missed to close it.
ob_start();
register_shutdown_function(function() {
// loop through buffers and flush them. After the operation the
// Content-Lenght header will contain the total of them all
while(ob_get_level()) {
header('Content-Length: ' . ob_get_length(), TRUE);
ob_end_flush();
}
});
Upvotes: 1