我正在从事一个涉及生成 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();
?>
现在,如果我将该文件放在互联网可以访问的位置,我的 Web 服务器可用于获取新的签名上传 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(没有任何错误指示(。我不确定我是否需要策略中的一些条件(acl
,bucket
,starts-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。
S3 上传策略不能与预签名 URL 一起使用。
策略文档可用于使用 HTML POST 表单将浏览器上传到 S3。
预签名 URL 和 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'
您可以尝试将特定策略添加到存储桶吗
$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]);