This is the script I have written for gzipping content on my site, which is located in 'gzip.php'. The way I use it is that on pages where I want to enable gzipping I include the file at the top and at the bottom I call the output function like this:
print_gzipped_page('javascript')
If the file is a css-file I use 'css' as the $type-argument and if its a php file I call the function without declaring any arguments. The script works fine in all browsers except Opera which gives an error saying it could not decode the page due to damaged data. Can anyone tell me what I have done wrong?
<?php
function print_gzipped_page($type = false) {
if(headers_sent()){
$encoding = false;
}
elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false ){
$encoding = 'x-gzip';
}
elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false ){
$encoding = 'gzip';
}
else{
$encoding = false;
}
if ($type!=false) {
$type_header_array = array("css" => "Content-Type: text/css", "javascript" => "Content-Type: application/x-javascript");
$type_header = $type_header_array[$type];
}
$contents = ob_get_contents();
ob_end_clean();
$etag = '"' . md5($contents) . '"';
$etag_header = 'Etag: ' . $etag;
header($etag_header);
if ($type!=false) {
header($type_header);
}
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and $_SERVER['HTTP_IF_NONE_MATCH']==$etag) {
header("HTTP/1.1 304 Not Modified");
exit();
}
if($encoding){
header('Content-Encoding: '.$encoding);
print("\x1f\x8b\x08\x00\x00\x00\x00\x00");
$size = strlen($contents);
$contents = gzcompress($contents, 9);
$contents = substr($contents, 0, $size);
}
echo $contents;
exit();
}
ob_start();
ob_implicit_flush(0);
?>
Additional info: The script works if the length of the document being compressed is only 10-15 characters.
Thanks for the help, corrected version:
<?php
function print_gzipped_page($type = false) {
if(headers_sent()){
$encoding = false;
}
elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false ){
$encoding = 'x-gzip';
}
开发者_如何转开发 elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false ){
$encoding = 'gzip';
}
else{
$encoding = false;
}
if ($type!=false) {
$type_header_array = array("css" => "Content-Type: text/css", "javascript" => "Content-Type: application/x-javascript");
$type_header = $type_header_array[$type];
header($type_header);
}
$contents = ob_get_contents();
ob_end_clean();
$etag = '"' . md5($contents) . '"';
$etag_header = 'Etag: ' . $etag;
header($etag_header);
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and $_SERVER['HTTP_IF_NONE_MATCH']==$etag) {
header("HTTP/1.1 304 Not Modified");
exit();
}
if($encoding){
header('Content-Encoding: ' . $encoding);
$contents = gzencode($contents, 9);
}
$length = strlen($contents);
header('Content-Length: ' . $length);
echo $contents;
exit();
}
ob_start();
ob_implicit_flush(0);
?>
This approach is a bit too clumsy. Rather make use of ob_gzhandler
. It will automatically GZIP the content which the client supports it and set the necessary headers.
ob_start('ob_gzhandler');
readfile($path);
Two things stand out:
1) you don't seem to be setting the Content-Length header to the size of the compressed data. (Maybe I've overlooked it.) If you don't set this a browser might think you've finished sending data too early.
2) you are doing a substr of the compressed $content with the uncompressed $size. Some browsers will stop decompressing when the internal structure has an EOF marker but other browsers (Opera?) may attempt to decompress the entire downloaded buffer. That would definitely give you a 'damaged data' error. You might not be seeing this problem with small buffers because the amount of overhead and the amount of compression might exactly match.
精彩评论