php实现文件下载代码
实现文件下载的基本方法
使用PHP实现文件下载的核心是通过设置HTTP头部信息,强制浏览器触发下载行为而非直接显示文件内容。
$file_path = 'path/to/your/file.ext';
$file_name = basename($file_path);
if (file_exists($file_path)) {
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;
}
处理大文件下载
对于大文件下载,使用分块读取可以避免内存耗尽问题。

$file_path = 'large_file.zip';
$chunk_size = 1024 * 1024; // 1MB chunks
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file_path) . '"');
$handle = fopen($file_path, 'rb');
while (!feof($handle)) {
echo fread($handle, $chunk_size);
ob_flush();
flush();
}
fclose($handle);
exit;
安全下载实现
增加安全检查防止目录遍历攻击。

$base_dir = '/safe/download/directory/';
$requested_file = $_GET['file'] ?? '';
$file_path = realpath($base_dir . $requested_file);
// 验证文件是否在允许的目录内
if ($file_path && strpos($file_path, realpath($base_dir)) === 0 && is_file($file_path)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file_path) . '"');
readfile($file_path);
} else {
header('HTTP/1.0 404 Not Found');
echo 'File not found';
}
exit;
进度显示实现
通过输出缓冲和JavaScript配合实现前端进度显示。
// PHP部分
$file_path = 'large_file.iso';
$file_size = filesize($file_path);
header('Content-Length: ' . $file_size);
// ...其他头部设置...
$handle = fopen($file_path, 'rb');
while (!feof($handle)) {
echo fread($handle, 8192);
ob_flush();
flush();
}
// 前端JavaScript
xhr.onprogress = function(e) {
if (e.lengthComputable) {
var percent = (e.loaded / e.total) * 100;
progressBar.style.width = percent + '%';
}
};
断点续传支持
实现Range请求支持,允许断点续传。
$file_path = 'resumable_file.mp4';
$file_size = filesize($file_path);
$start = 0;
$end = $file_size - 1;
if (isset($_SERVER['HTTP_RANGE'])) {
$range = $_SERVER['HTTP_RANGE'];
if (preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)) {
$start = intval($matches[1]);
$end = isset($matches[2]) ? intval($matches[2]) : $file_size - 1;
}
}
header('Accept-Ranges: bytes');
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $file_size);
header('Content-Length: ' . ($end - $start + 1));
$handle = fopen($file_path, 'rb');
fseek($handle, $start);
while (!feof($handle) && ($p = ftell($handle)) <= $end) {
echo fread($handle, min(8192, $end - $p + 1));
ob_flush();
flush();
}
fclose($handle);






