使用PHP上传大于2M的文件到S3:是否需修改AWS SDK代码?
问题:AWS PHP SDK 上传大文件到S3时临时文件权限报错,是否必须修改SDK代码?
我使用AWS PHP SDK上传视频文件至S3,小于2M的文件能成功上传,但上传大于2M的文件时出现如下警告:
fwrite(): Unable to create temporary file, Check permissions in temporary files directory. in /aws/GuzzleHttp/Psr7/Utils.php on line 309
该警告指向SDK中的这段代码:
public static function streamFor($resource = '', array $options = []) { if (is_scalar($resource)) { $stream = self::tryFopen('php://temp', 'r+'); if ($resource !== '') { // 报错位置 fwrite($stream, $resource); fseek($stream, 0); } return new Stream($stream, $options); } }
我参考PHP文档后,将SDK代码修改为:
$stream = self::tryFopen("php://temp/maxmemory:$fiveMBs", 'r+');
修改后大文件可正常上传,但我想知道有没有无需修改AWS SDK源码的解决办法?
回答
完全不需要修改SDK源码,问题根源是你将大文件内容以字符串形式传递给SDK,导致Guzzle需要把字符串写入php://temp临时流,而服务器临时目录权限不足或空间不够,引发了报错。以下是两种更合理的解决方式:
方案1:直接传递文件资源流
避免将整个文件加载为字符串,直接传递文件的只读资源流给PutObject操作:
use Aws\S3\S3Client; use GuzzleHttp\Psr7\Utils; // 初始化S3客户端 $s3 = new S3Client([ 'version' => 'latest', 'region' => '你的存储桶区域', ]); // 打开本地大文件的只读流 $fileStream = fopen('/path/to/large-video.mp4', 'rb'); // 包装为PSR-7流对象 $stream = Utils::streamFor($fileStream); // 执行上传 $s3->putObject([ 'Bucket' => '你的存储桶名称', 'Key' => '存储到S3的文件名.mp4', 'Body' => $stream, ]);
方案2:手动创建带内存限制的临时流(无需修改SDK)
如果确实需要处理字符串形式的大内容,可以在调用SDK前自行创建指定maxmemory的临时流,再传递给SDK:
use Aws\S3\S3Client; use GuzzleHttp\Psr7\Utils; $s3 = new S3Client([ 'version' => 'latest', 'region' => '你的存储桶区域', ]); $fiveMBs = 5 * 1024 * 1024; // 自行创建带内存限制的临时流 $stream = Utils::tryFopen("php://temp/maxmemory:$fiveMBs", 'r+'); fwrite($stream, $largeContentString); fseek($stream, 0); // 上传 $s3->putObject([ 'Bucket' => '你的存储桶名称', 'Key' => '存储到S3的文件名.mp4', 'Body' => $stream, ]);
为什么这些方法有效?
- 方案1直接复用本地文件的资源流,Guzzle无需创建
php://temp临时文件,既绕过了临时目录权限问题,又大幅降低内存占用(大文件无需全部加载到内存)。 - 方案2保留了你的解决思路,但将临时流的创建逻辑移到了业务代码中,避免修改SDK核心文件,后续SDK升级时不会丢失自定义配置。
内容的提问来源于stack exchange,提问作者roni syneet
相关产品推荐
相关产品推荐

