【问题标题】:AWS PHP SDK: Limit S3 file upload size in presigned URLAWS PHP SDK:限制预签名 URL 中的 S3 文件上传大小
【发布时间】:2016-05-10 16:00:59
【问题描述】:

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

<?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();

?>

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

$ 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 并将许多文件上传到我的存储桶,但我想限制上传文件的大小。许多资源建议将策略附加到签名的 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 是否存在基本限制?

对于我的 Web 服务器,我使用 HHVM 3.11.1 和适用于 PHP 的 AWS 开发工具包 3.14.1 版本。

【问题讨论】:

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


    【解决方案1】:

    S3 上传策略不能与预签名 URL 一起使用。

    策略文档可以与browser uploads to S3 using HTML POST Forms 一起使用。

    预签名 URLHTML 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'
    

    【讨论】:

    • 我知道 HTML POST 表单是一种选择,但我并不专门针对浏览器,所以这不是我的解决方案。感谢您的建议!
    • POST 字段比我想要的要复杂一些——我真的只想生成一个可以复制/粘贴到任何支持 HTTP PUT 的客户端的 URL。不过我非常喜欢这个解决方案——支持 HTTP PUT 的客户端可能也会支持 POST 字段,所以我会努力提供这个作为上传的方法。
    【解决方案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]);
    

    【讨论】:

    • 我认为这是正确的方向 - 我需要将策略附加到存储桶本身,而不是 PutObject 请求本身。但是,看起来 content-length-range 仅支持作为浏览器上传策略条件,因此我不确定是否可以在预签名 URL 中包含文件大小限制或作为存储桶本身的属性。
    猜你喜欢
    • 1970-01-01
    • 2022-11-30
    • 2018-09-11
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 2020-10-23
    • 2014-11-17
    相关资源
    最近更新 更多