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

PHP 強制下載 PDF 檔案:Header 控制與瀏覽器相容性完整指南

     編輯:PHP 綜合知識

核心原理

瀏覽器預設會內嵌顯示 PDF(Content-Type: application/pdf)。要觸發「另存為」下載對話框,需發送:

  • Content-Type: application/octet-stream 或 application/force-download
  • Content-Disposition: attachment; filename="xxx.pdf"

通用強制下載函數

<?php
/**
 * 強制下載檔案
 * @param string $filePath 檔案絕對路徑
 * @param string $fileName 下載顯示的檔名(可選,預設取原檔名)
 * @return bool 成功輸出 true
 */
function forceDownload($filePath, $fileName = '') {
    if (!is_file($filePath) || !is_readable($filePath)) {
        header('HTTP/1.1 404 Not Found');
        return false;
    }

    $fileName = $fileName ?: basename($filePath);
    $fileSize = filesize($filePath);

    // 1. 核心 Header
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"');
    header('Content-Length: ' . $fileSize);
    header('Content-Transfer-Encoding: binary');
    header('Accept-Ranges: bytes');

    // 2. 快取控制(避免 IE/Edge 緩存導致檔案損壞)
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public'); // HTTP/1.0 相容
    header('Expires: 0');

    // 3. 輸出檔案內容
    // 使用 readfile() 直接輸出,記憶體效率高,支援大檔
    readfile($filePath);
    return true;
}

// 使用範例
forceDownload('/data/reports/2024_Q1.pdf', '2024年第一季報表.pdf');
?>

關鍵細節解析

Header作用注意事項
Content-Disposition: attachment強制下載而非內嵌檔名需 rawurlencode() 處理中文,雙引號包裹
Content-Length讓瀏覽器顯示進度條、支援斷點續傳必須精確,壓縮輸出會導致長度不符
Cache-Control: must-revalidate要求瀏覽器每次重新驗證防止舊版緩存導致下載到過期檔案
readfile()直接輸出到 PHP 輸出緩衝區不佔用 PHP 記憶體,適合大檔(> 100MB)

常見坑點與解決

1. 輸出前有空白/換行導致 Header 失效

<?php // ← 前面不能有任何字元,含 BOM
// 正確:檔案以 <?php 開頭,結尾省略 ?>
?>

2. 已啟用 output_buffering / gzip 壓縮

// 在 forceDownload() 開頭關閉壓縮
@ini_set('zlib.output_compression', 'Off');
@ini_set('output_buffering', 'Off');
ob_end_clean(); // 清除已有緩衝

3. Nginx + PHP-FPM 下大檔下載中斷

# nginx.conf
proxy_buffering off;        # 關閉代理緩衝,直接串流
proxy_max_temp_file_size 0; # 禁用臨時檔
fastcgi_buffering off;      # PHP-FPM 端同步關閉

4. 中文檔名在舊版 IE/Edge 顯示亂碼

// 兼容寫法:ASCII fallback + RFC 5987 encoding
$encoded = rawurlencode($fileName);
$ascii   = preg_replace('/[^\x20-\x7E]/', '', $fileName) ?: 'download';
header("Content-Disposition: attachment; filename=\"$ascii\"; filename*=UTF-8''$encoded");

進階:支援斷點續傳

大檔(> 500MB)建議實現 Range / 206 Partial Content,或直接用 Nginx ngx_http_sendfile_module / X-Accel-Redirect 讓 Web Server 處理靜態檔傳輸,PHP 僅負責權限驗證。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved