php实现下载功能
实现文件下载的基本方法
使用PHP的header()函数设置HTTP头信息,配合readfile()函数实现文件下载。确保在发送文件内容前没有输出任何内容,避免头信息错误。
$file_path = 'path/to/your/file.pdf';
$file_name = 'custom_name.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_path));
readfile($file_path);
exit;
处理大文件下载
对于大文件下载,使用分块读取方式避免内存溢出。通过设置缓冲区大小,逐块读取文件内容。
$chunk_size = 1024 * 1024; // 1MB chunks
$handle = fopen($file_path, 'rb');
while (!feof($handle)) {
echo fread($handle, $chunk_size);
ob_flush();
flush();
}
fclose($handle);
安全下载注意事项
验证文件路径和用户权限,防止目录遍历攻击。使用realpath()和basename()确保路径安全。
$base_dir = '/safe/download/directory/';
$requested_file = $_GET['file'];
$absolute_path = realpath($base_dir . $requested_file);
if ($absolute_path === false || !is_file($absolute_path)) {
die('File not found');
}
if (strpos($absolute_path, realpath($base_dir)) !== 0) {
die('Invalid file path');
}
强制下载不同类型文件
根据文件类型设置正确的MIME类型。常见文件的MIME类型示例:
$mime_types = [
'pdf' => 'application/pdf',
'txt' => 'text/plain',
'jpg' => 'image/jpeg',
'zip' => 'application/zip'
];
$extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (array_key_exists($extension, $mime_types)) {
header('Content-Type: ' . $mime_types[$extension]);
} else {
header('Content-Type: application/octet-stream');
}
断点续传支持
实现HTTP范围请求(Range Requests),允许客户端恢复中断的下载。
$file_size = filesize($file_path);
$start = 0;
$end = $file_size - 1;
if (isset($_SERVER['HTTP_RANGE'])) {
if (preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches)) {
$start = intval($matches[1]);
if (!empty($matches[2])) {
$end = intval($matches[2]);
}
}
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $start-$end/$file_size");
}
header('Accept-Ranges: bytes');
header('Content-Length: ' . ($end - $start + 1));
$handle = fopen($file_path, 'rb');
fseek($handle, $start);
$remaining = $end - $start + 1;
while ($remaining > 0) {
$chunk = min($chunk_size, $remaining);
echo fread($handle, $chunk);
$remaining -= $chunk;
ob_flush();
flush();
}
fclose($handle);






