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; }
额外配置检查
- Apache配置:
- 检查
/etc/apache2/apache2.conf或虚拟主机配置中的LimitRequestBody,确保设为0(无限制) - 调整
Timeout参数,比如设为300(5分钟),避免大文件下载超时:Timeout 300
- 检查
- PHP配置:
- 确保
php.ini中output_buffering = Off,或者代码中用ob_end_flush()关闭缓冲 - 确认
max_execution_time = 0(或足够大的值),配合set_time_limit(0)使用
- 确保
内容的提问来源于stack exchange,提问作者FroddeB
相关产品推荐
相关产品推荐

