首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP Header 實現檔案下載完整指南:避開輸出混雜、編碼亂碼與大檔案記憶體溢位

     編輯:PHP 綜合知識

標準三步驟

<?php
// 1. 宣告 MIME 類型
header('Content-Type: application/octet-stream');

// 2. 指定下載檔名 (RFC 5987 編碼支援中文)
$filename = '報表.xlsx';
header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"');
header("Content-Disposition: attachment; filename*=UTF-8''" . rawurlencode($filename));

// 3. 輸出檔案內容
readfile('/path/to/' . $filename);
exit; // 關鍵:阻止後續輸出混入
?>

常見坑與解法

大檔案分塊輸出範例

<?php
function downloadLargeFile($path, $filename)
{
    if (!is_file($path)) { http_response_code(404); exit; }

    $size = filesize($path);
    $fp = fopen($path, 'rb');

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"');
    header('Content-Length: ' . $size);
    header('Accept-Ranges: bytes');
    header('Cache-Control: no-cache, must-revalidate');
    header('Pragma: no-cache');

    // Range 支援
    if (isset($_SERVER['HTTP_RANGE'])) {
        // 解析 Range header,送 206...
    }

    while (!feof($fp) && connection_status() === CONNECTION_NORMAL) {
        echo fread($fp, 8192); // 8KB 分塊
        flush();
    }
    fclose($fp);
    exit;
}
?>

安全性檢查清單

  • ✅ 驗證路徑在允許目錄內 (realpath + 前綴比對)
  • ✅ 檢查權限 (登入狀態、擁有者、下載次數限制)
  • ✅ 記錄下載日誌 (審計追蹤)
  • ✅ 設定 X-Content-Type-Options: nosniff 防 MIME 嗅探
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因解決
下載檔案開頭有 HTML/空白/錯誤訊息腳本前有輸出 (BOM、echo、錯誤、空白行)腳本最開頭 <?php 無前綴字元;關閉錯誤顯示 ini_set('display_errors',0);或用 ob_clean() 清緩衝
中文檔名亂碼瀏覽器編碼解析不一雙重 header:filename (舊瀏覽器) + filename*=UTF-8'' (RFC 5987)
大檔案記憶體耗盡readfile 仍需載入內核緩衝分塊輸出:fopen + fread 迴圈 + flush()
斷點續傳支援無 Range 處理解析 $_SERVER['HTTP_RANGE'],回應 206 Partial Content