结合使用 Amazon S3 分段上传与 Amazon SDK for PHP 版本 3 - Amazon SDK for PHP
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

结合使用 Amazon S3 分段上传与 Amazon SDK for PHP 版本 3

单独的 PutObject 操作可上传的对象大小上限为 5 GB。但使用分段上传方法(例如,CreateMultipartUploadUploadPartCompleteMultipartUploadAbortMultipartUpload),上传对象的大小范围可以在 5 MB 到 5 TB 之间。

以下示例演示如何:

的所有示例代码都可以在此Amazon SDK for PHP处找到 GitHub

凭证

运行示例代码之前,请配置您的 Amazon 凭证,如 凭证 中所述。然后导入 Amazon SDK for PHP,如 基本用法 中所述。

对象上传程序

如果您不确定是 PutObject 还是 MultipartUploader 最适合该任务,请使用 ObjectUploaderObjectUploader 是使用 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) 在任何 PutObjectUploadPart 操作之前调用的回调。此回调应具有类似 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"; }

这个上传工具可根据提供的源和配置创建分段数据的生成器,并尝试上传所有分段。如果某些分段上传失败,上传工具将继续上传后面的分段,直到所有源数据均被读取。然后,上传工具重新尝试上传失败的分段,或引发包含有关无法上传的分段的信息的异常。

自定义分段上传

您可以设置 CreateMultipartUploadUploadPartCompleteMultipartUpload 操作的自定义选项,分段上传工具可通过传递给构造函数的回调执行这些操作。

导入

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) 表示分段上传状态的对象,用于重新开始上次上传。如果提供了此选项,将忽略 bucketkeypart_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"; }