将二进制数据传递给S3 PutObject

时间:2013-02-27 09:23:16

标签: php amazon-s3

我正在尝试将许多图像上传到S3存储桶。考虑到速度,我希望通过将数据保存在内存中来减少磁盘读写次数。为此,我提出了以下方案:

//fetch binary image data from remote URL
$contents = file_get_contents("http://somesite.com/image.jpg");
//trim the image as per: http://stackoverflow.com/a/15104071/568884
$out = shell_exec('echo ' . base64_encode($contents) . " | base64 -d | convert - -fuzz 10% -trim jpeg:-");
//create a temporary resource to pass to S3's inputResource() method.
$resource = fopen('php://temp', 'r+');
//write the binary data into the empty resource.
fwrite($resource, $out);
//pass the resource and length of binary data into inputResource()
$ir = $this->s3->inputResource($resource, strlen($out));
//finally transfer the resource from machine to S3.
$this->s3->putObject($ir, $bucket, $s3_path, S3::ACL_PUBLIC_READ);

错误是: S3 :: putObject():[RequestTimeout]在超时期限内未读取或写入与服务器的套接字连接。空闲连接将关闭,数据不会写入S3。

如果我将$ out的赋值替换为空字符串:$out = "";然后,库按预期成功将0字节文件写入S3。

我正在使用CodeIgniter S3库...这只是AWS S3 API afaik的包装。

2 个答案:

答案 0 :(得分:1)

您正在将文件句柄$resource传递给库,但是,您首先写入它,以便文件指针位于文件的末尾。

该库可能无法处理该边缘情况(它的源代码表明)。

您可以在写入文件后尝试rewind($resource)文件,但在将文件传递到S3库之前。

如果你想加快这一点,你可以通过将php://temp切换到php://memory来让PHP使用内存来处理较小的文件。有关详细信息和选项,请参阅the php:// wrapper docs

S3库btw。不是官方的。如果启用通知和警告,您可能会看到报告的一些问题,因为它仍然包含PHP 4代码。

答案 1 :(得分:0)

RequestTimeout错误的一个可能来源可能是您对putObject的调用指定的内容长度与发送的实际数据不同。根据{{​​3}}中的亚马逊代表:

  

触发RequestTimeout错误的一种方法是发送PUT   请求指定Content-Length为2但仅包含1个字节   请求正文中的对象数据。等了20秒之后   剩下的字节到达,Amazon S3将使用RequestTimeour进行响应   错误。

因此,当您使用strlen()函数时,您的临时文件可能会报告错误的长度,并且此错误值导致S3响应异常。

根据对the AWS forums的评论,该函数可以报告文件中错误的字节数,因为它假设字符串总是ASCII:

  

如果是这种情况,它可能会将二进制数据视为unocode字符串和   返回错误的值

尝试用php documentation for strlen()调用替换strlen(),它应该始终报告正确的字节数。