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

PHP 實作檔案下載斷點續傳完整指南

     編輯:PHP 綜合知識

為什麼需要斷點續傳?

當網站提供檔案下載服務時,斷點續傳是提升用戶體驗的關鍵功能。它允許用戶暫停下載,稍後從中斷處繼續,而無需重新下載整個檔案。這對大型檔案或不穩定的網路環境尤為重要。

Web 伺服器的預設行為

大多數 Web 伺服器(如 Apache、Nginx)預設支援靜態檔案的斷點續傳。若直接透過 Web 伺服器提供公開靜態檔案下載,通常無需額外配置。然而,這種方式無法讓後端腳本控制下載過程,無法滿足私有檔案、動態生成內容或需權限驗證的場景。

核心原理:HTTP Range 請求

HTTP 協定定義了 Range 標頭,允許客戶端請求資源的特定位元組範圍。例如,對於 1000 位元組的檔案,瀏覽器可請求 bytes=0-299(前 300 位元組)或 bytes=500-999(後 500 位元組)。伺服器回應 206 Partial Content 狀態碼,並附上 Content-Range 標頭指示傳輸範圍。

PHP 實作關鍵步驟

1. 宣告支援範圍請求

header('Accept-Ranges: bytes');

告訴瀏覽器此資源支援以位元組為單位的部分傳輸。

2. 解析 Range 標頭

$range = "0-".($filesize - 1); // 預設完整檔案
if (isset($_SERVER['HTTP_RANGE'])) {
    $range = $_SERVER['HTTP_RANGE']; // 例如 "bytes=500-999"
}

3. 驗證並解析範圍值

Range 格式可能為:

  • 100-200:第 100 到 200 位元組
  • 500-:第 500 位元組到檔案結尾
  • -1000:最後 1000 位元組

需驗證:起始位置非負、結束位置大於起始、起始小於檔案長度、結束不超過檔案長度。無效範圍回應 416 Requested Range Not Satisfiable。

4. 發送正確的回應標頭

header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header("Content-Range: bytes $start-$end/$filesize");
$length = $end - $start + 1;
header("Content-Length: $length");

注意:Content-Length 是本次傳輸的長度,而非完整檔案大小;狀態碼必須為 206。

5. 輸出檔案指定部分

$fp = fopen($filepath, 'rb');
fseek($fp, $start);
while (!feof($fp) && $length > 0) {
    $buffer = fread($fp, min(8192, $length));
    echo $buffer;
    $length -= strlen($buffer);
    flush();
}
fclose($fp);

常見陷阱與最佳實踐

  • 記憶體管理:大檔案務必使用串流讀取,避免一次性載入記憶體。
  • 輸出緩衝:在輸出檔案前清除所有輸出緩衝(ob_clean()),防止輸出前的空白字元損壞檔案。
  • 安全性:驗證用戶權限、檔案路徑安全(防止目錄遍歷)、設定適當的 Content-Disposition。
  • 多線程下載支援:正確實作 Range 請求也能支援下載工具的多線程下載。

總結

斷點續傳本質上是利用 HTTP 協定的部分內容傳輸特性。在 PHP 中實作時,關鍵在於正確處理 Range/Content-Range 標頭、狀態碼 206 以及檔案指標定位。錯誤的標頭會導致下載檔案損壞,務必嚴格遵循 RFC 7233 規範。

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