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

PHP实现动态文件下载时速度大幅变慢的问题求助

问题原因排查及解决方案

核心原因(按概率从高到低排序)

  • PHP输出缓冲未正确关闭
    默认PHP的输出缓冲(output_buffering)是开启状态,调用readfile时文件内容会先写入PHP缓冲区,填满后才会推送至Web服务器再返回给客户端,小包频繁发送直接拉低传输效率。
  • zlib输出压缩被意外开启
    如果php.ini中zlib.output_compression = On,PHP会对所有输出内容自动做压缩处理,你传输的zip本身已经是高压缩率文件,重复压缩只会无谓消耗CPU,拉长传输时间。
  • readfile读取块大小默认值过小
    未自定义读取块大小时,PHP每次读取的文件片段很小,磁盘IO次数过多也会拖慢速度。
  • (次要影响)PHP-FPM进程重载异常
    你提供的日志中多次出现Another FPM instance seems to already listen on /tmp/php-cgi-73.sock错误,说明重载配置时旧进程未正常退出,残留进程占用socket资源,高并发时会导致请求排队,也可能间接影响下载速度。

对应解决方法

1. 调整下载脚本,关闭缓冲并优化输出

修改你的下载脚本如下:

<?php
$file = './French-Stories-Martine.zip';
if (headers_sent()) {
    echo 'HTTP header already sent';
} else {
    if (!is_file($file)) {
        header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
        echo 'File not found';
    } else if (!is_readable($file)) {
        header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
        echo 'File not readable';
    } else {
        // 关闭所有层级的输出缓冲
        while (ob_get_level()) ob_end_clean();
        // 临时禁用输出压缩
        if (ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off');
        
        header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
        header("Content-Type: application/zip");
        header("Content-Transfer-Encoding: Binary");
        header("Content-Length: ".filesize($file));
        header("Content-Disposition: attachment; filename=\"".basename($file)."\"");
        readfile($file);
        exit;
    }
}
?>

2. 调整PHP配置优化传输

编辑对应版本的php.ini文件:

  • 若全局业务没有依赖输出缓冲的场景,可直接将output_buffering设置为Off,否则仅在下载类脚本中临时关闭即可
  • 确认zlib.output_compression默认设置为Off,如果全局需要开启,必须在下载类脚本中临时关闭
  • 保持output_handler为空,避免额外的输出处理逻辑拖慢速度

3. 修复PHP-FPM重载异常问题

执行以下操作清理残留进程:

  1. 停止PHP-FPM服务:systemctl stop php-fpm73(根据你实际的服务名调整)
  2. 手动删除残留的sock文件:rm -f /tmp/php-cgi-73.sock
  3. 检查是否有残留PHP-FPM进程:ps aux | grep php-fpm,如有残留进程直接kill即可
  4. 重新启动PHP-FPM:systemctl start php-fpm73
    之后再重载配置就不会出现socket占用的错误。

4. 进阶优化方案(大文件下载场景)

如果下载的文件普遍超过100M,可以使用X-Sendfile功能(Apache、OpenLiteSpeed均原生支持),PHP只做权限校验,文件传输完全交给Web服务器处理,性能和静态下载完全一致:

// 权限校验通过后添加以下头即可,不需要手动调用readfile输出
header("X-Sendfile: " . realpath($file));
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=\"".basename($file)."\"");
exit;

注意需要提前在Web服务器配置中开启X-Sendfile支持。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:15:03