php怎么实现下载
实现文件下载的基本方法
使用PHP的header()函数设置HTTP头信息,结合readfile()函数输出文件内容。以下是一个简单示例:
$file_path = '/path/to/your/file.pdf';
$file_name = 'download.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($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);
安全下载控制
验证用户权限和文件路径,防止目录遍历攻击:
$base_dir = '/safe/directory/';
$requested_file = $_GET['file'];
$real_path = realpath($base_dir . $requested_file);
if (strpos($real_path, $base_dir) !== 0 || !file_exists($real_path)) {
die('Invalid file');
}
断点续传支持
实现HTTP Range请求支持:

$size = filesize($file_path);
$start = 0;
$end = $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/$size");
}
header("Accept-Ranges: bytes");
header("Content-Length: " . ($end - $start + 1));
强制下载特定MIME类型
设置特定的Content-Type强制浏览器下载:
$mime_types = [
'pdf' => 'application/pdf',
'zip' => 'application/zip',
// 添加更多MIME类型
];
$ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (array_key_exists($ext, $mime_types)) {
header('Content-Type: ' . $mime_types[$ext]);
}
下载进度监控
使用输出缓冲和回调函数监控下载进度:
function readfile_chunked($filename, $chunk_size = 1024, $callback = null) {
$handle = fopen($filename, 'rb');
$total = filesize($filename);
$sent = 0;
while (!feof($handle)) {
$buffer = fread($handle, $chunk_size);
echo $buffer;
$sent += strlen($buffer);
if (is_callable($callback)) {
call_user_func($callback, $sent, $total);
}
ob_flush();
flush();
}
fclose($handle);
}






