這是我之前處理壓縮檔在IE下載與解壓縮的過程中,所遇到的問題。
在PHP中,常用壓縮函式代表的實際壓縮格式如下:
1 2 3 | gzencode() == gzip gzcompress() == zlib (aka. HTTP deflate) gzdeflate() == *raw* deflate encoding |
格式差異如下:
deflate(RFC1951):一種壓縮算法,使用LZ77 & haffman編碼;
zlib(RFC1950):一種格式,對deflate進行了簡單的封裝;
gzip(RFC1952):一種格式,也是對deflate進行的封裝.
因此要注意的是,gzdeflate跟HTTP deflate(zlib)是不一樣的!要用gzcompress才對。
IE或其它瀏覽器支援gzip壓縮是沒啥問題的,有無標頭尾都可正常開啟;
但IE6, 7, 8一遇到deflate就不正常了,必須將zlib去頭(2 bytes)去尾(4 bytes),這樣IE才看得懂,
而且還得送出必要的header給IE才能force download,真的是問題多多。
總而言之,
解HTTP的content-encoding如下:
deflate: gzinflate( substr($HTTP_RAW_DATA,2,-4) ) 或 gzuncompress($HTTP_RAW_DATA)
gzip: gzinflate( substr($HTTP_RAW_DATA,10,-8) ) 或 gzdecode($HTTP_RAW_DATA)
壓縮HTTP的content-encoding如下:
deflate: gzcompress($DATA) (但IE6~8傳送壓縮檔內容要去頭2尾4)
gzip: gzencode($DATA)
IE讀deflate解法(去頭尾轉成raw deflate):
1) 加header:
1 2 3 4 5 6 7 8 9 10 | header( 'Content-Description: File Transfer' ); header( 'Content-Type: application/octet-stream' ); //別用force-download,也無須指定mime-type header( "Content-Encoding: deflate" ); //表示壓縮 header( "Content-Length: " . filesize ( $file_path )-6); //去掉zlib頭尾(6 bytes)後的size header( "Content-Disposition: attachment; filename=" . $true_filename ); //以下三行修正IE header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); header( "Pragma: public" ); header( 'Expires: 0' ); |
2)讀檔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //防止再次壓縮 if ( ini_get ( 'zlib.output_compression' )) ini_set ( 'zlib.output_compression' , 'Off' ); set_time_limit(0);ob_flush(); ob_end_clean(); //修正IE,chunk download可支援大檔下載 if ( $fp = fopen ( $file_path , 'rb' )){ fseek ( $fp , 2); //去掉zlib頭(2 bytes), 尾可不去 while (! feof ( $fp )){ print ( fread ( $fp , 1024*8)); ob_flush(); flush (); ob_end_flush(); } fclose( $fp ); } @ob_flush();@ flush ();@ob_end_flush();@ob_end_clean(); |
沒有留言:
張貼留言