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

PHP 實現檔案強制下載的完整解決方案

     編輯:PHP 綜合知識

為什麼需要程式化下載?

在 Web 開發中,最直觀的下載方式是直接提供檔案連結(`下載`)。然而,當瀏覽器能識別並直接開啟特定檔案類型(如圖片、HTML、PDF、文字檔)時,點擊連結會導致瀏覽器在新分頁預覽,而非彈出「另存新檔」對話框。這對於需要受控下載(如權限驗證、下載統計、防盜鏈)的場景顯然不符合需求。

核心原理:HTTP 標頭控制

透過 PHP 發送特定的 HTTP Header,指示瀏覽器將回應內容視為附件處理,關鍵在於 Content-Disposition: attachment 標頭。搭配 Content-Type: application/octet-stream(通用二進制流)與 Content-Length,即可實現跨瀏覽器的強制下載行為。

完整程式碼範例(含安全防護)

<?php
// 1. 參數驗證:防止目錄遍歷與非法存取
$fileName = isset($_GET['file']) ? basename($_GET['file']) : '';
$fileDir  = '/var/www/downloads/'; // 固定儲存目錄,不可由用戶控制

if (empty($fileName) || !preg_match('/^[\w\-\.]+$/', $fileName)) {
    http_response_code(400);
    exit('非法檔案名稱');
}

$filePath = $fileDir . $fileName;

// 2. 檔案存在性與可讀性檢查
if (!is_file($filePath) || !is_readable($filePath)) {
    http_response_code(404);
    exit('檔案不存在或不可讀');
}

// 3. 發送下載標頭
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"');
header('Content-Length: ' . filesize($filePath));
header('Accept-Ranges: bytes'); // 支援斷點續傳
header('Cache-Control: private, must-revalidate'); // 避免 Proxy 快取干擾
header('Pragma: public'); // HTTP/1.0 相容

// 4. 分塊輸出:避免大檔案佔用過多記憶體
$handle = fopen($filePath, 'rb');
if ($handle) {
    while (!feof($handle)) {
        echo fread($handle, 8192); // 8KB 緩衝區
        @ob_flush();
        @flush();
    }
    fclose($handle);
}
exit;
?>

關鍵細節解析

  • basename() + 白名單正則:徹底阻擋 `../../etc/passwd` 類路徑遍歷攻擊。
  • rawurlencode():處理中文、空格等特殊字元檔名,確保 `Content-Disposition` 標頭合法。
  • 分塊讀取 (fread 8192):支援 GB 級大檔案,不會觸發 `memory_limit` 限制。
  • Accept-Ranges: bytes:啟用瀏覽器/下載工具的斷點續傳功能。
  • 權限控制邏輯:實際專案中應在輸出前加入用戶身份驗證、下載次數記錄、流量統計等業務邏輯。

進階應用:支援遠端 URL 下載

若檔案儲存於 CDN 或物件存儲(S3/OSS),可使用 `fopen($remoteUrl, 'rb')` 串流轉發,但需注意:

  1. 遠端伺服器需支援 `Range` 請求頭,否則無法斷點續傳。
  2. PHP 端需透過 `header('Content-Range: ...')` 透傳範圍回應。
  3. 大檔案建議採用「簽名 URL 直連」或「預簽名 URL」方案,減輕應用伺服器頻寬壓力。

總結

程式化下載不僅解決了「瀏覽器直接開啟」的問題,更是實現下載權限控管、防盜鏈、統計分析的基礎。掌握 HTTP 標頭機制與串流輸出技巧,是 PHP 後端工程師的必備技能。

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