Mar*_* C. 3 php amazon-s3 amazon-web-services
我正在接收文件(最大 4 GB):文件内容通过 POST 请求正文传输给我。我想将此流直接上传到 s3 存储桶,而不先在本地保存。已经尝试了不同的方法,但由于不同的原因而失败了。
我目前的做法:
use GuzzleHttp\Psr7\Stream;
use Aws\S3\S3Client;
$s3 = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => 'eu-west-1',
'credentials' => [
'key' => 'abc',
'secret' => '123'
]
]);
$stream = new \GuzzleHttp\Psr7\Stream(fopen('php://input', 'r'));
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'ContentLength' => (int)$_SERVER['CONTENT_LENGTH'],
'Body' => $stream->getContents(),
'ACL' => 'private',
'StorageClass' => 'STANDARD_IA',
));
Run Code Online (Sandbox Code Playgroud)
尝试流式传输 80 MB 文件时出现以下错误:
PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 78847383 bytes) in /var/www/slimapi/vendor/slim/slim/Slim/Http/Stream.php on line 403
Run Code Online (Sandbox Code Playgroud)
Stream.php的第403行是:
if (!$this->isReadable() || ($contents = stream_get_contents($this->stream)) === false) {
Run Code Online (Sandbox Code Playgroud)
因此,该错误可能是由于尝试将流的全部内容加载到字符串中而导致的,这超出了内存限制。(令人恼火的是为什么错误发生在 Slim/Stream 中,因为我正在尝试使用 guzzle\Stream。)
所以我的问题是:如何将传入的 POST 数据直接流式传输到 s3 存储桶,而不会出现导致内存问题的缓冲问题?
我已经尝试过:
我知道这是老话题,但它没有标记为已解决,所以......
PHP SDK确实支持流源,正如您在SDK规范中看到的那样(https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject ) - 请参阅参数语法:
$result = $client->putObject([
// ...
'Body' => <string || resource || Psr\Http\Message\StreamInterface>,
// ...
]);
Run Code Online (Sandbox Code Playgroud)
这意味着您的代码几乎没问题,唯一的是您应该通过$stream而不是$stream->getContents():
$stream = new \GuzzleHttp\Psr7\Stream(fopen('php://input', 'r'));
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'ContentLength' => (int)$_SERVER['CONTENT_LENGTH'],
'Body' => $stream,
'ACL' => 'private',
'StorageClass' => 'STANDARD_IA',
));
Run Code Online (Sandbox Code Playgroud)
就如此容易。