You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现800MB-1GB大体积zip压缩包分块下载到浏览器问题求助

问题原因排查

你现有代码的核心问题集中在以下几点:

  • 二进制文件读取模式错误:fopen使用"r"文本模式读取zip等二进制文件,会在Windows系统下自动处理换行符导致文件流损坏,大文件场景下极易触发传输中断
  • PHP执行超时未关闭:默认PHP配置的max_execution_time通常为30-60秒,大文件下载耗时远超阈值会被PHP主动终止进程
  • 输出缓冲未正确清空:仅调用flush()只能刷新Web服务器的输出缓冲,还需要配合ob_flush()清空PHP自身的输出缓冲,否则部分数据会堆积在内存中迟迟不发送到浏览器,导致浏览器判定连接超时
  • 不必要的速率限制逻辑:sleep(1)会强制每次分块发送后休眠1秒,1GB文件按你设置的5MB/s速率,仅休眠耗时就超过200秒,进一步放大了超时风险
  • Header配置不规范:Content-Disposition缺少attachment标识,部分浏览器会直接尝试打开文件而不是触发下载,同时filename未做编码处理特殊字符会出现乱码

修正后的分块下载实现

$filename = $_SERVER['DOCUMENT_ROOT'] . $filepath;
// 分块大小设置为2MB,可根据服务器配置调整
$chunk_size = 2 * 1024 * 1024;

if (!file_exists($filename) || !is_file($filename)) {
    http_response_code(404);
    echo 'File does not exist!';
    exit;
}

// 关闭PHP执行超时限制
set_time_limit(0);
// 关闭所有输出缓冲层
while (ob_get_level()) {
    ob_end_clean();
}

// 发送正确的下载头
header('Cache-Control: public, must-revalidate');
header('Pragma: public');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($filename));
header('Content-Disposition: attachment; filename="' . rawurlencode(basename($filename)) . '"');
header('Content-Transfer-Encoding: binary');

// 用二进制只读模式打开文件
$file = fopen($filename, 'rb');
while (!feof($file)) {
    // 读取分块内容输出
    echo fread($file, $chunk_size);
    // 依次清空PHP和Web服务器的输出缓冲
    ob_flush();
    flush();
}
fclose($file);
exit;

额外注意事项

  • 如果使用Nginx作为Web服务器,需要调整proxy_read_timeout、send_timeout配置,默认60秒的超时时间会中断长耗时的下载请求
  • 如果服务器开启了gzip压缩,需要对下载路径关闭压缩,否则会自动缓冲整个文件内容再发送,失去分块传输的意义
  • 不要在代码前后添加任何额外的输出,哪怕是空格、换行都会污染文件流,导致下载后的压缩包损坏无法解压

内容的提问来源于stack exchange,提问作者Thomas Nicholson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:24:02