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

PHP 實現強制文件下載:解決瀏覽器直接打開文件問題

     編輯:PHP 綜合知識

直接鏈接文件 URL 會導致瀏覽器直接打開圖片、HTML、PDF 等可識別類型,而非下載。通過 PHP 發送正確 Header 強制觸發下載對話框。

核心實現代碼

<?php
// 參數驗證
if (empty($_GET['FileName']) || empty($_GET['FileDir']) || empty($_GET['FileId'])) {
    exit('非法請求');
}

$file_name = basename($_GET['FileName']); // 防止目錄遍歷
$file_dir  = rtrim($_GET['FileDir'], '/') . '/';
$file_path = $file_dir . $file_name;

// 安全檢查:路徑必須在允許目錄內
$allowed_base = realpath('/var/www/downloads');
$real_path = realpath($file_path);
if (!$real_path || strpos($real_path, $allowed_base) !== 0 || !file_exists($real_path)) {
    exit('文件不存在或無權限');
}

// 發送下載 Header
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . rawurlencode($file_name) . '"');
header('Content-Length: ' . filesize($real_path));
header('Accept-Ranges: bytes');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache'); // HTTP/1.0 兼容

// 輸出文件內容
readfile($real_path); // 比 fopen/fread/fclose 更高效、內存友好
exit;
?>

關鍵 Header 詳解

Header作用關鍵點
Content-Type: application/octet-stream聲明二進制流,瀏覽器不嘗試解析核心觸發下載
Content-Disposition: attachment指示為附件下載而非內聯顯示filename 建議用 rawurlencode 編碼
Content-Length文件大小,支持進度條、斷點續傳必須準確
Accept-Ranges: bytes支持斷點續傳/多線程下載需配合 Range 請求處理
Cache-Control / Pragma防緩存干擾下載類通常不緩存

安全加固要點

  1. 路徑遍歷防護:basename() + realpath() + 基準目錄校驗
  2. 2. 輸入驗證:白名單允許字符,拒絕 ../、..\\、空字節 3. 權限控制:結合用戶身份、文件所有權、下載次數限制 4. 大文件支持:readfile() 流式輸出,不佔用 PHP 內存;超大文件考慮 X-Sendfile/X-Accel-Redirect 交給 Web 服務器 5. 斷點續傳:解析 $_SERVER['HTTP_RANGE'],發送 206 Partial Content + Content-Range

進階:Nginx X-Accel-Redirect 方案(高性能)

# PHP 僅驗證權限,返回內部重定向 Header
header('X-Accel-Redirect: /protected/files/' . $file_name);
header('Content-Disposition: attachment; filename="' . rawurlencode($file_name) . '"');
exit;

# Nginx 配置
location /protected/files/ {
    internal; # 僅內部訪問
    alias /var/www/downloads/;
}

優勢:PHP 進程瞬間釋放,Nginx 直接發送文件,支持極高併發與大文件。

常見問題

  • 文件名亂碼 → rawurlencode() 編碼,或 RFC 5987 格式 filename*=UTF-8''encoded_name
  • 下載損壞 → 檢查是否有 BOM/空白/錯誤輸出混入文件流
  • 內存耗盡 → 必須用 readfile() 或分塊輸出,禁用 file_get_contents()

掌握 Header 機制與安全實踐,構建健壯的文件下載服務。

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