php 实现下载功能
使用 header 函数实现文件下载
在 PHP 中可以通过设置 HTTP 头部信息实现文件下载功能。核心是使用 header() 函数设置正确的 Content-Type 和 Content-Disposition。
$file_path = '/path/to/file.pdf';
$file_name = 'document.pdf';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header('Content-Length: ' . filesize($file_path));
readfile($file_path);
exit;
处理大文件下载
对于大文件下载,需要分块读取以避免内存问题。可以使用 fopen 和 fread 组合实现流式下载。

$file_path = '/path/to/large_file.iso';
$chunk_size = 1024 * 1024; // 1MB chunks
$handle = fopen($file_path, 'rb');
while (!feof($handle)) {
echo fread($handle, $chunk_size);
ob_flush();
flush();
}
fclose($handle);
安全下载控制
为防止未授权访问,应在下载前验证用户权限。可以结合会话验证或 token 机制。
session_start();
if (!isset($_SESSION['user_id'])) {
die('Access denied');
}
$allowed_files = ['report1.pdf', 'data.xlsx'];
$requested_file = $_GET['file'];
if (!in_array($requested_file, $allowed_files)) {
die('Invalid file request');
}
动态生成内容下载
对于动态生成的内容(如 CSV 导出),可以直接输出内容并设置下载头部。

header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');
$output = fopen('php://output', 'w');
fputcsv($output, ['Name', 'Email', 'Phone']);
// 添加数据行
foreach ($users as $user) {
fputcsv($output, [$user['name'], $user['email'], $user['phone']]);
}
fclose($output);
断点续传支持
实现断点续传功能需要处理 Range 头部,适用于大文件下载场景。
$file_path = '/path/to/large_file.zip';
$file_size = filesize($file_path);
if (isset($_SERVER['HTTP_RANGE'])) {
$range = $_SERVER['HTTP_RANGE'];
$range = str_replace('bytes=', '', $range);
list($start, $end) = explode('-', $range);
$start = max(0, (int)$start);
$end = min($file_size - 1, (int)$end);
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $start-$end/$file_size");
header('Content-Length: ' . ($end - $start + 1));
$fp = fopen($file_path, 'rb');
fseek($fp, $start);
$length = $end - $start + 1;
$buffer = 1024 * 8;
while ($length > 0) {
$read = ($length > $buffer) ? $buffer : $length;
echo fread($fp, $read);
$length -= $read;
flush();
}
fclose($fp);
} else {
// 普通下载处理
}
下载进度显示
通过输出缓冲和内容长度计算可以实现简单的进度显示。
ob_start();
$file_path = '/path/to/file';
$file_size = filesize($file_path);
$chunk_size = 1024 * 1024;
header('Content-Length: ' . $file_size);
// 其他头部设置...
$handle = fopen($file_path, 'rb');
$sent = 0;
while (!feof($handle) && $sent < $file_size) {
$buffer = fread($handle, $chunk_size);
echo $buffer;
$sent += strlen($buffer);
// 可以在此处记录进度到数据库或文件
$progress = round(($sent / $file_size) * 100);
file_put_contents('progress.txt', $progress);
ob_flush();
flush();
}
fclose($handle);
ob_end_flush();






