在 PHP 開發中實作檔案下載功能時,常遇到下載後的圖片無法開啟、文字檔出現亂碼、檔案大小異常增加等問題。這通常是因為輸出緩衝區殘留內容,導致檔案資料被額外字元污染。
使用 readfile() 輸出檔案時,下載的圖片用編輯器開啟提示「檔案損壞」,但縮圖仍可顯示;文字檔頭尾多出不明字元;檔案大小比原始檔大約 1KB。經排查,確認為輸出前已有內容輸出(如空白字元、BOM、錯誤訊息等),導致 HTTP 回應標頭與檔案二進位資料混雜。
在輸出檔案前,必須清空輸出緩衝區並關閉緩衝,確保只輸出純檔案內容:
public function download() {
$upload = M('upload');
$data = $upload->find($_GET['id']);
if (empty($data)) {
header('HTTP/1.0 404 Not Found');
header('Location: .');
} else {
$path = './public/Uploads/' . $data['savename'];
// 設定正確的標頭
header("Content-Type: " . $data['type']);
header('Content-Disposition: attachment; filename="' . $data['name'] . '"');
header('Content-Length: ' . $data['size']);
// 關鍵步驟:清空緩衝區並關閉輸出緩衝
ob_clean();
flush();
// 輸出檔案
readfile($path);
}
}
readfile() 前有任何 echo、print、HTML 空白或 BOM。若專案使用框架(如 ThinkPHP、Laravel),建議使用框架內建的檔案下載回應類別(如 Response::download()),可自動處理緩衝、標頭、大檔案分塊傳輸等細節,更安全可靠。
掌握輸出緩衝控制,是解決 PHP 檔案下載損壞的關鍵。記得在輸出二進位檔案前,永遠先 ob_clean() 與 flush()。