無法開啟 PHP ZipArchive 下載的 zip 檔

PHP 內有一個用來操控壓縮檔的 ZipArchive 模組,今天收到問題回報說下載的 zip 檔沒辦法開啟,當下直覺認為是對方操作錯誤,給幾個同事測試之後,有一個同事同樣無法開啟,竟然是因為檔頭多了一些空白造成,這篇記錄此問題的解法。

PHP 壓縮檔案

這邊是留給自己的 ZipArchive 用法的 memo,確定載入此模組後,只要使用以下方法就可以輕鬆把檔案壓縮成 zip

// 建立 ZipArchive 物件
$zip = new ZipArchive();
// 在指定路徑中建立一個 zip 檔
$res = $zip->open('tmp_callback/123.zip', ZipArchive::CREATE);
// 把 tmp_callback/file1 新增至 zip 內,並改名為 00000001.txt
$zip->addFile('tmp_callback/file1', '00000001.txt');
// 關閉 zip 物件
$zip->close();

透過網頁下載 zip 檔

透過以下的語法可以讓瀏覽器直接下載 zip 檔,一方面在之前做權限控管以及避免洩漏檔案真實路徑

$path = "/var/www/html/uploads/";
$filename = '03082358.zip';
	
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($path . $filename));
@readfile($file);

無法開啟壓縮檔的原因

直到有使用者反應壓縮檔無法開啟,透過 unzip-online.com 線上解壓縮也失敗

AL9nZEUmC2qlg12i3weQMfhMjRT7Fs36NTNVuXgAmZ14RgARuzc f3A5P6 R6RVcbFWjuV5zg2buO7UDMNQzmuJq7Yjz6p6uhzi36eDw9VLmBYSYsFfAzZnhLX h94Sj4Ha 4Vu11rgEEmMHazPjEb01fLom=w940 h463 no?authuser=1 無法開啟 PHP ZipArchive 下載的 zip 檔

使用 notepad++ 開啟後才發現 zip 檔開頭有三行空白,可是有些電腦可以正常開啟有些電腦卻不行

AL9nZEVkfKvVTFLvsECju82DL81lA0cgTr9UbDAzMFQKa0EYoBTd7BkCwQVNsgf7pAeJbFT5wvfG7ovzLSIsHevoDTCTe6caIDyIJmvsoi6cgQzor9JIL0mvkwUAsczIPFE7Eq6i99yno QHzmq8WTTKaliH=w208 h119 no?authuser=1 無法開啟 PHP ZipArchive 下載的 zip 檔

只要把那三行空白刪除,就可以正常解壓縮了 …

無法開啟壓縮檔的解決方法

一開始以為是 ZipArchive 模組的問題,做了各種嘗試後發現,產出來的 zip 是正常的,並沒有上面那三行空白,那問題就是出在下載這段了。

試了很多方法發現只要有<?php include_once "xxx.php" ?>就會有三行空白的狀況,一開始笨笨的試著把所有用到的 include 都拔進來放,後來覺得這樣實在是又累又蠢,最後終於找到簡單解法 … 只要在readfile之前呼叫ob_clean();就可以避免這個問題 …

// 以上省略
ob_clean();
@readfile($file);

    發佈留言

    發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

    這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料