Content-Disposition、Accept-Ranges、Content-Length。<?php
function downloadFile($FileName, $FilePath = '') {
header("Content-type: text/html; charset=utf-8");
if (strlen($FileName) <= 3) { exit("下載失敗:文件信息有誤"); }
// 文件名編碼轉換,防止中文亂碼
$FileName = iconv("utf-8", "gb2312", $FileName);
// 路徑標準化
if (!is_null($FilePath) && strlen($FilePath) > 1) {
if (substr($FilePath, 0, 1) === '/') { // 絕對路徑(相對網站根目錄)
$FilePath = $_SERVER['DOCUMENT_ROOT'] . $FilePath;
}
if (substr($FilePath, -1) !== '/') $FilePath .= '/';
if (strpos($FilePath, ':') !== false) $FilePath = str_replace('/', '\\', $FilePath); // Windows 絕對路徑
} elseif (strlen($FilePath) == 1 && $FilePath !== '/') {
$FilePath .= '/';
} else {
$FilePath = '';
}
$fullPath = $FilePath . $FileName;
if (!file_exists($fullPath)) { exit("下載失敗:文件未找到"); }
$FileSize = filesize($fullPath);
// 發送下載頭
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Content-Length: $FileSize");
header("Content-Disposition: attachment; filename=\"$FileName\"");
// 分塊輸出
$fp = fopen($fullPath, 'rb');
$buffer = 1024 * 512; // 512KB
while (!feof($fp) && $FileSize > 0) {
$read = min($buffer, $FileSize);
echo fread($fp, $read);
$FileSize -= $read;
@ob_flush(); @flush();
}
fclose($fp);
exit;
}
// 使用示例
// downloadFile('測試報告.pdf', '/uploads/2024/01/');
?>
fopen($path, 'rb') 確保跨平台正確讀取。ob_flush() + flush() 實時推送數據到瀏覽器,大文件不卡死。iconv('utf-8','gb2312') 兼容老版本 IE/Edge;現代瀏覽器支持 RFC 5987 編碼(filename*=UTF-8''...),可雙頭並發。Accept-Ranges: bytes,配合 $_SERVER['HTTP_RANGE'] 可實現斷點下載(本函數未實現,留作擴展)。memory_limit 或縮小緩衝區。該下載函數結構清晰、健壯性強,適合直接集成到項目中。生產環境建議添加權限校驗、日誌記錄、限速控制等增強功能。