AWS PHP SDK:在预签名网址

时间:2016-02-02 01:21:17

标签: php amazon-web-services file-upload amazon-s3

我正在处理一个项目,该项目涉及生成其他人可以用来将文件上传到我的S3存储桶的S3 URL。这是一个最小的工作示例:

<?php

    require('aws.phar');
    use Aws\S3\S3Client;

    $s3client = new S3Client(...); // credentials go here

    $id = uniqid(); // generate some kind of key

    $command = $s3client->getCommand('PutObject', [
        'ACL' => 'private',
        'Body' => '',
        'Bucket' => 'mybucket',
        'Key' => 'tmp/' . $id]);

    echo (string) $s3client->createPresignedRequest($command, '+5 minutes')->getURI();

?>

现在,如果我将该文件放在互联网可访问的位置,我的网络服务器可用于获取新签名的上传网址:

$ curl http://my.domain.com/some/page.php
https://s3.amazonaws.com/mybucket/tmp/someID?x-amz-acl=private&lots-of-aws-params...
$ curl -X PUT -d "@someFile" https://s3.amazonaws.com/mybucket/tmp/someID?x-amz-acl=private&lots-of-aws-params...
$

这会成功将本地文件上传到我的存储桶,因此我可以在S3中使用它。

我们假设我并不太担心人们会在很短的时间内生成许多网址并将很多文件上传到我的存储桶,但我想限制上传文件的大小。许多资源建议将策略附加到签名URL:

<?php

    require('aws.phar');
    use Aws\S3\S3Client;

    $s3client = new S3Client(...); // credentials go here

    $id = uniqid(); // generate some kind of key

    $policy = [
        'conditions' => [
            ['acl' => 'private'],
            ['bucket' => 'mybucket'],
            ['content-length-range', 0, 8*1024], // 8 KiB
            ['starts-with', '$key', 'tmp/']
        ], 'expiration' =>
            (new DateTime())->modify('+5 minutes')->format(DateTime::ATOM)];

    $command = $s3client->getCommand('PutObject', [
        'ACL' => 'private',
        'Body' => '',
        'Bucket' => 'mybucket',
        'Key' => 'tmp/' . $id,
        'Policy' => $policy]);

    echo (string) $s3client->createPresignedRequest($command, '+5 minutes')->getURI();

?>

此版本生成可以相同方式使用的URL(无任何错误指示)。我不确定我是否需要政策中的某些条件(aclbucketstarts-with),但我不认为包含它们会破坏政策。

理论上,尝试使用此签名URL上传大于8 KiB的文件应导致S3中止上传。但是,使用较大的文件对此进行测试表明,curl仍然可以愉快地上传文件:

$ ls -lh file.txt
-rw-rw-r-- 1 millinon millinon 210K Jan  2 00:41 file.txt
$ curl http://my.domain.com/some/page.php
https://s3.amazonaws.com/mybucket/tmp/someOtherID?x-amz-acl=private&lots-of-aws-params...
$ curl -X PUT -d "@file.txt" https://s3.amazonaws.com/mybucket/tmp/someOtherID?x-amz-acl=private&lots-of-aws-params...
$

检查存储桶显示确实已上传大文件,并且文件的大小大于所谓的策略。

由于各个页面显示了附加策略的不同方式,我还尝试了以下版本:

'Policy' => json_encode($policy)
'Policy' => base64_encode(json_encode($policy))

但是,使用这些版本生成的URL允许上载大于指定大小的文件。

我是否错误地附加了该政策,或者是否存在以这种方式限制上传到S3的基本限制?

对于我的网络服务器,我使用HHVM 3.11.1和AWS SDK for PHP版本3.14.1。

2 个答案:

答案 0 :(得分:3)

S3上传政策不能与预先签名的网址一起使用。

政策文件可与browser uploads to S3 using HTML POST Forms一起使用。

预签名网址 HTML POST表单是上传到S3的两种不同方法。前者可以说比后者更简单,但更不灵活。

<强>更新

如果您必须在不使用浏览器的情况下上传文件,可以使用PHP的curl函数,Guzzle等库或使用命令行重现HTML POST表单的请求,如下所示:

curl 'https://s3-bucket.s3.amazonaws.com/' \
    -F 'key=uploads/${filename}' \
    -F 'AWSAccessKeyId=YOUR_AWS_ACCESS_KEY' \
    -F 'acl=private' \
    -F 'success_action_redirect=http://localhost/' \
    -F 'policy=YOUR_POLICY_DOCUMENT_BASE64_ENCODED' \
    -F 'signature=YOUR_CALCULATED_SIGNATURE' \
    -F 'Content-Type=image/jpeg' \
    -F 'file=@file.jpg'

答案 1 :(得分:2)

您可以尝试将特定政策添加到您的存储区

$s3client->putBucketPolicy(array(
    'Bucket' => $bucket,
    'Policy' => json_encode(array(
        'conditions' => array(
            array(
                'content-length-range', 0, 8*1024,
                'starts-with', '$key', 'tmp/'
                ...

之后,只需使用普通的putObject命令

即可
$command = $s3client->getCommand('PutObject', [
    'ACL' => 'private',
    'Body' => '',
    'Bucket' => 'mybucket',
    'Key' => 'tmp/' . $id]);