這是我之前處理壓縮檔在IE下載與解壓縮的過程中,所遇到的問題。
在PHP中,常用壓縮函式代表的實際壓縮格式如下:
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:
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)讀檔
//防止再次壓縮 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();
沒有留言:
張貼留言