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

AWS EC2上PHP网站S3 SDK下载文件限64MB问题求助

解决S3大文件下载限制问题

问题根源

你当前的代码会把S3文件的完整内容加载到内存后再输出,哪怕memory_limit设为0,Apache的输出缓冲区、请求限制,或者PHP的内存管理机制都会导致大文件下载失败或截断到64MB。

解决方案一:流式输出(无需分块,直接优化内存使用)

利用AWS SDK的流式读取能力,边读边输出,避免一次性加载整个文件到内存:

try {
    set_time_limit(0);
    ob_end_flush(); // 关闭输出缓冲,直接输出内容

    $result = $s3->getObject([
        'Bucket' => $bucket,
        'Key'    => $keyname,
        '@http'  => [
            'stream' => true // 启用流式传输
        ]
    ]);

    // 获取流资源
    $stream = $result['Body']->detach();

    // 设置响应头
    header('Content-Description: File Transfer');
    header("Content-Type: {$result['ContentType']}; charset=utf-8");
    header("Content-Disposition: attachment; filename=".$filename);
    header('Content-Length: ' . $result['ContentLength']); // 告诉浏览器文件总大小

    // 分段读取并输出
    $chunkSize = 8192; // 8KB块大小,可根据需要调整
    while (!feof($stream)) {
        echo fread($stream, $chunkSize);
        flush(); // 强制输出缓冲区内容
    }

    fclose($stream);
} catch (S3Exception $e) {
    echo $e->getMessage() . PHP_EOL;
}

解决方案二:分块下载(支持断点续传)

如果需要支持断点续传(用户中断后可继续下载),可以处理HTTP的Range请求头,从S3分块获取文件内容:

try {
    set_time_limit(0);
    ob_end_flush();

    // 获取文件元信息(先拿到总大小)
    $headResult = $s3->headObject([
        'Bucket' => $bucket,
        'Key'    => $keyname
    ]);
    $fileSize = $headResult['ContentLength'];
    $contentType = $headResult['ContentType'];

    // 处理Range请求
    $range = $_SERVER['HTTP_RANGE'] ?? '';
    if (preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)) {
        $start = (int)$matches[1];
        $end = isset($matches[2]) ? (int)$matches[2] : $fileSize - 1;
        $end = min($end, $fileSize - 1);
    } else {
        $start = 0;
        $end = $fileSize - 1;
    }

    $chunkSize = $end - $start + 1;

    // 从S3获取指定范围的内容
    $result = $s3->getObject([
        'Bucket' => $bucket,
        'Key'    => $keyname,
        'Range'  => "bytes=$start-$end",
        '@http'  => [
            'stream' => true
        ]
    ]);

    // 设置响应头(支持断点续传)
    header('Content-Description: File Transfer');
    header("Content-Type: $contentType; charset=utf-8");
    header("Content-Disposition: attachment; filename=".$filename);
    header('Accept-Ranges: bytes');
    header("Content-Length: $chunkSize");
    header("Content-Range: bytes $start-$end/$fileSize");
    http_response_code(206); // 206 Partial Content

    // 输出流内容
    $stream = $result['Body']->detach();
    while (!feof($stream)) {
        echo fread($stream, 8192);
        flush();
    }

    fclose($stream);
} catch (S3Exception $e) {
    echo $e->getMessage() . PHP_EOL;
}

额外配置检查

  1. Apache配置:
    • 检查/etc/apache2/apache2.conf或虚拟主机配置中的LimitRequestBody,确保设为0(无限制)
    • 调整Timeout参数,比如设为300(5分钟),避免大文件下载超时:Timeout 300
  2. PHP配置:
    • 确保php.ini中output_buffering = Off,或者代码中用ob_end_flush()关闭缓冲
    • 确认max_execution_time = 0(或足够大的值),配合set_time_limit(0)使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 14:56:27