本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
结合使用 Amazon S3 分段上传与 Amazon SDK for PHP 版本 3
单独的 PutObject
操作可上传的对象大小上限为 5 GB。但使用分段上传方法(例如,CreateMultipartUpload
、UploadPart
、CompleteMultipartUpload
、AbortMultipartUpload
),上传对象的大小范围可以在 5 MB 到 5 TB 之间。
以下示例演示如何:
-
使用将对象上传到 Amazon S3 ObjectUploader。
-
使用MultipartUploader为 Amazon S3 对象创建分段上传。
-
使用将对象从一个 Amazon S3 位置复制到另一个位置ObjectCopier。
的所有示例代码都可以在此Amazon SDK for PHP处找到 GitHub
凭证
运行示例代码之前,请配置您的 Amazon 凭证,如 凭证 中所述。然后导入 Amazon SDK for PHP,如 基本用法 中所述。
对象上传程序
如果您不确定是 PutObject
还是 MultipartUploader
最适合该任务,请使用 ObjectUploader
。ObjectUploader
是使用 PutObject
还是 MultipartUploader
将大型文件上传到 Amazon S3,取决于由负载大小确定哪个更适合。
require 'vendor/autoload.php'; use Aws\Exception\MultipartUploadException; use Aws\S3\MultipartUploader; use Aws\S3\ObjectUploader; use Aws\S3\S3Client;
示例代码
// Create an S3Client. $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-east-2', 'version' => '2006-03-01' ]); $bucket = 'your-bucket'; $key = 'my-file.zip'; // Use a stream instead of a file path. $source = fopen('/path/to/large/file.zip', 'rb'); $uploader = new ObjectUploader( $s3Client, $bucket, $key, $source ); do { try { $result = $uploader->upload(); if ($result["@metadata"]["statusCode"] == '200') { print('<p>File successfully uploaded to ' . $result["ObjectURL"] . '.</p>'); } print($result); // If the SDK chooses a multipart upload, try again if there is an exception. // Unlike PutObject calls, multipart upload calls are not automatically retried. } catch (MultipartUploadException $e) { rewind($source); $uploader = new MultipartUploader($s3Client, $source, [ 'state' => $e->getState(), ]); } } while (!isset($result)); fclose($source);
配置
ObjectUploader
对象构造函数接受以下参数:
$client
-
用于执行转移的
Aws\ClientInterface
对象。它应是Aws\S3\S3Client
的实例。 $bucket
-
(
string
,必需)对象要上传到的存储桶名称。 $key
-
(
string
,必需)上传对象使用的键。 $body
-
(
mixed
,必需)要上传的对象数据。可以是StreamInterface
、PHP 流资源或要上传的数据字符串。 $acl
-
(
string
) 上传对象设置的访问控制列表 (ACL)。默认情况下对象是私有的。 $options
-
用于分段上传的配置选项的关联数组。以下配置选项有效:
add_content_md5
-
(
bool
) 设置为 True,可自动计算上传的 MD5 校验和。 mup_threshold
-
(
int
,默认:int(16777216)
)文件大小的字节数。如果文件大小超过此限制,则使用分段上传。 before_complete
-
(
callable
) 在CompleteMultipartUpload
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 before_initiate
-
(
callable
) 在CreateMultipartUpload
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 before_upload
-
(
callable
) 在任何PutObject
或UploadPart
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 concurrency
-
(
int
,默认:int(3)
)在分段上传期间允许的并发UploadPart
操作数量上限。 part_size
-
(
int
,默认:int(5242880)
)进行分段上传时使用的分段大小(以字节为单位)。此值必须在 5 MB(含)和 5 GB(含)之间。 state
-
(
Aws\Multipart\UploadState
) 表示分段上传状态的对象,用于重新开始上次上传。如果提供了此选项,将忽略$bucket
和$key
参数以及part_size
选项。
MultipartUploader
分段上传可改善较大对象的上传体验。这种方法支持您将对象分成各自独立的部分,既可以按任何顺序上传,也可并行上传。
我们鼓励 Amazon S3 客户针对大于 100 MB 的对象使用分段上传。
MultipartUploader 对象
开发工具包中包含一个特殊的 MultipartUploader
对象,可简化分段上传过程。
导入
require 'vendor/autoload.php'; use Aws\Exception\MultipartUploadException; use Aws\S3\MultipartUploader; use Aws\S3\S3Client;
示例代码
$s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); // Use multipart upload $source = '/path/to/large/file.zip'; $uploader = new MultipartUploader($s3Client, $source, [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', ]); try { $result = $uploader->upload(); echo "Upload complete: {$result['ObjectURL']}\n"; } catch (MultipartUploadException $e) { echo $e->getMessage() . "\n"; }
这个上传工具可根据提供的源和配置创建分段数据的生成器,并尝试上传所有分段。如果某些分段上传失败,上传工具将继续上传后面的分段,直到所有源数据均被读取。然后,上传工具重新尝试上传失败的分段,或引发包含有关无法上传的分段的信息的异常。
自定义分段上传
您可以设置 CreateMultipartUpload
、UploadPart
和 CompleteMultipartUpload
操作的自定义选项,分段上传工具可通过传递给构造函数的回调执行这些操作。
导入
require 'vendor/autoload.php'; use Aws\S3\MultipartUploader; use Aws\S3\S3Client;
示例代码
// Create an S3Client $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); // Customizing a multipart upload $source = '/path/to/large/file.zip'; $uploader = new MultipartUploader($s3Client, $source, [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', 'before_initiate' => function (Command $command) { // $command is a CreateMultipartUpload operation $command['CacheControl'] = 'max-age=3600'; }, 'before_upload' => function (Command $command) { // $command is an UploadPart operation $command['RequestPayer'] = 'requester'; }, 'before_complete' => function (Command $command) { // $command is a CompleteMultipartUpload operation $command['RequestPayer'] = 'requester'; }, ]);
分段上传之间的手动垃圾回收
如果您达到大型上传的内存限制,这可能是由于在达到您的内存限制时开发工具包生成的、但尚未由 PHP 垃圾回收器
$uploader = new MultipartUploader($client, $source, [ 'bucket' => 'your-bucket', 'key' => 'your-key', 'before_upload' => function(\Aws\Command $command) { gc_collect_cycles(); } ]);
从错误中恢复
如果在分段上传过程中发生错误,将引发 MultipartUploadException
。可通过此异常访问 UploadState
对象,其中包含分段上传的进度信息。可使用 UploadState
重新开始未完成的上传。
导入
require 'vendor/autoload.php'; use Aws\Exception\MultipartUploadException; use Aws\S3\MultipartUploader; use Aws\S3\S3Client;
示例代码
// Create an S3Client $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); $source = '/path/to/large/file.zip'; $uploader = new MultipartUploader($s3Client, $source, [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', ]); //Recover from errors do { try { $result = $uploader->upload(); } catch (MultipartUploadException $e) { $uploader = new MultipartUploader($s3Client, $source, [ 'state' => $e->getState(), ]); } } while (!isset($result)); //Abort a multipart upload if failed try { $result = $uploader->upload(); } catch (MultipartUploadException $e) { // State contains the "Bucket", "Key", and "UploadId" $params = $e->getState()->getId(); $result = $s3Client->abortMultipartUpload($params); }
若通过 UploadState
继续上传,将尝试上传尚未上传的分段。状态对象会跟踪缺少的分段,即使这些分段是不连续的。上传工具会读取或搜寻提供的源文件,找到仍需上传的特定分段的字节范围。
UploadState
对象是序列化的,因此您也可以在另一进程中重新开始上传。即使不是在处理异常,您也可以通过调用 $uploader->getState()
获得 UploadState
对象。
重要
作为源传递到 MultipartUploader
的流在上传之前不会自动倒回。如果您在与上个示例类似的循环中使用流,而不是文件路径,请重置 catch
块中的 $source
变量。
导入
require 'vendor/autoload.php'; use Aws\Exception\MultipartUploadException; use Aws\S3\MultipartUploader; use Aws\S3\S3Client;
示例代码
// Create an S3Client $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); //Using stream instead of file path $source = fopen('/path/to/large/file.zip', 'rb'); $uploader = new MultipartUploader($s3Client, $source, [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', ]); do { try { $result = $uploader->upload(); } catch (MultipartUploadException $e) { rewind($source); $uploader = new MultipartUploader($s3Client, $source, [ 'state' => $e->getState(), ]); } } while (!isset($result)); fclose($source);
中止分段上传
通过检索 UploadState
对象中包含的 UploadId
并将其传递给 abortMultipartUpload
可以中止分段上传。
try { $result = $uploader->upload(); } catch (MultipartUploadException $e) { // State contains the "Bucket", "Key", and "UploadId" $params = $e->getState()->getId(); $result = $s3Client->abortMultipartUpload($params); }
异步分段上传
在 upload()
上调用 MultipartUploader
是一个阻止请求。如果在异步环境中工作,可获得分段上传的 Promise。
require 'vendor/autoload.php'; use Aws\S3\MultipartUploader; use Aws\S3\S3Client;
示例代码
// Create an S3Client $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); $source = '/path/to/large/file.zip'; $uploader = new MultipartUploader($s3Client, $source, [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', ]); $promise = $uploader->promise();
配置
MultipartUploader
对象构造函数接受以下参数:
-
$client
-
用于执行转移的
Aws\ClientInterface
对象。它应是Aws\S3\S3Client
的实例。 -
$source
-
上传的源数据。这可以是路径或 URL(例如,
/path/to/file.jpg
)、资源处理(例如,fopen('/path/to/file.jpg', 'r)
)或 PSR-7 流的实例。 -
$config
-
用于分段上传的配置选项的关联数组。
以下配置选项有效:
-
acl
-
(
string
) 上传对象设置的访问控制列表 (ACL)。默认情况下对象是私有的。 -
before_complete
-
(
callable
) 在CompleteMultipartUpload
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 -
before_initiate
-
(
callable
) 在CreateMultipartUpload
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 -
before_upload
-
(
callable
) 在任何UploadPart
操作之前调用的回调。此回调应具有类似function (Aws\Command $command) {...}
的函数签名。 -
bucket
-
(
string
,必需)对象要上传到的存储桶名称。 -
concurrency
-
(
int
,默认:int(5)
)在分段上传期间允许的并发UploadPart
操作数量上限。 -
key
-
(
string
,必需)上传对象使用的键。 -
part_size
-
(
int
,默认:int(5242880)
)进行分段上传时使用的分段大小(以字节为单位)。它必须在 5 MB(含)和 5 GB(含)之间。 -
state
-
(
Aws\Multipart\UploadState
) 表示分段上传状态的对象,用于重新开始上次上传。如果提供了此选项,将忽略bucket
、key
和part_size
选项。 add_content_md5
-
(
boolean
) 设置为 True,可自动计算上传的 MD5 校验和。
-
分段副本
Amazon SDK for PHP 还包含一个 MultipartCopy
对象,用途与 MultipartUploader
相似,但用于在 Amazon S3 内部复制 5 GB 到 5 TB 之间的对象。
require 'vendor/autoload.php'; use Aws\Exception\MultipartUploadException; use Aws\S3\MultipartCopy; use Aws\S3\S3Client;
示例代码
// Create an S3Client $s3Client = new S3Client([ 'profile' => 'default', 'region' => 'us-west-2', 'version' => '2006-03-01' ]); //Copy objects within S3 $copier = new MultipartCopy($s3Client, '/bucket/key?versionId=foo', [ 'bucket' => 'your-bucket', 'key' => 'my-file.zip', ]); try { $result = $copier->copy(); echo "Copy complete: {$result['ObjectURL']}\n"; } catch (MultipartUploadException $e) { echo $e->getMessage() . "\n"; }