2010-04-20 101 views
0

时,这是我为我的网站上,它位于“gzip.php” gzip压缩的内容写的剧本。我用它的方式是,在这里我想启用gzip压缩的网页我包括文件的顶部和底部我把这样的输出功能:损坏的数据使用gzip压缩

print_gzipped_page('javascript') 

如果该文件是一个CSS文件我使用'css'作为$ type-argument,如果它的php文件没有声明任何参数,则调用该函数。该脚本在除Opera以外的所有浏览器都能正常工作,因为数据受损会导致无法解码页面。谁能告诉我我做错了什么?

<?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); 
?> 

附加信息:如果被压缩文档的长度只有10-15个字符,则该脚本有效。

感谢您的帮助,修改后的版本:

<?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); 
?> 

回答

1

两件事情引人注目:

1)你似乎不是Content-Length头被设置为压缩数据的大小。 (也许我忽略了它。)如果你没有设置这个浏览器可能会认为你已经完成发送数据太早。

2)你正在做的压缩$内容与未压缩$大小的SUBSTR。当内部结构具有EOF标记时,某些浏览器将停止解压缩,但其他浏览器(Opera?)可能会尝试解压缩整个下载的缓冲区。这肯定会给你一个'数据损坏'的错误。您可能不会看到小缓冲区的问题,因为开销和压缩量可能完全匹配。

+0

谢谢你,问题就迎刃而解了。我删除了压缩数据上的substr(),并用压缩文档的长度设置了Content-Length头。 – RadiantHeart 2010-04-20 15:47:50

3

这种做法有点太笨拙。宁可使用ob_gzhandler。它会自动GZIP客户端支持的内容并设置必要的标题。

ob_start('ob_gzhandler'); 
readfile($path); 
+0

正是......为什么要重新发明轮子? – Powerlord 2010-04-28 21:07:36

+0

话虽如此,你最终需要'ob_end_flush()',还是自动调用它? – Powerlord 2010-04-28 21:08:25

+1

@OMG:PHP文档确实对此没有明确说明,但在我的情况下,它在所有情况下都会执行flush和close操作,所以我认为它会自动完成。 – BalusC 2010-04-28 21:18:07