本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用适用于 PHP 的 AWS 开发工具包版本 3 使用 Amazon S3 分段上传
单独的 PutObject 操作可上传的对象大小上限为 5 GB。但使用分段上传方法(例如,CreateMultipartUpload、UploadPart、CompleteMultipartUpload、AbortMultipartUpload),上传对象的大小范围可以在 5 MB 到 5 TB 之间。
以下示例演示如何:
版本 3 的所有示例代码在 AWS SDK for PHP 上的此处提供。GitHub
Credentials
对象上传工具
如果您不确定是 PutObject 还是 MultipartUploader 最适合该任务,请使用 ObjectUploader。ObjectUploader 使用 PutObject 还是 MultipartUploader 将大型文件上传到 Amazon S3,具体取决于根据负载大小哪个工具最适合。
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\ObjectUploader;
示例代码
$s3Client = new S3Client([
'profile' => 'default',
'region' => 'us-east-2',
'version' => '2006-03-01'
]);
$bucket = 'your-bucket';
$key = 'my-file.zip';
// Using stream instead of 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('
File successfully uploaded to ' . $result["ObjectURL"] . '.
');}
print($result);
} catch (MultipartUploadException $e) {
rewind($source);
$uploader = new MultipartUploader($s3Client, $source, [
'state' => $e->getState(),
]);
}
} while (!isset($result));
MultipartUploader
分段上传可改善较大对象的上传体验。这种方法支持您将对象分成各自独立的部分,既可以按任何顺序上传,也可并行上传。
我们鼓励 Amazon S3 客户针对大于 100 MB 的对象使用分段上传。
MultipartUploader 对象
开发工具包中包含一个特殊的 MultipartUploader 对象,可简化分段上传过程。
导入
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
示例代码
$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\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
示例代码
// 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 (\Aws\Command $command) {
// $command is a CreateMultipartUpload operation
$command['CacheControl'] = 'max-age=3600';
},
'before_upload' => function (\Aws\Command $command) {
// $command is an UploadPart operation
$command['RequestPayer'] = 'requester';
},
'before_complete' => function (\Aws\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\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
示例代码
// 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\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
示例代码
// 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));
中止分段上传
通过检索 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\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
示例代码
// 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();
Configuration
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) {...} 的函数签名。
存储桶
(string,必需) 对象要上传到的存储桶名称。
concurrency
(int,默认:int(5)) 在分段上传期间允许的并发 UploadPart 操作数量上限。
密钥
(string,必需) 上传对象使用的键。
part_size
(int,默认:int(5242880)) 进行分段上传时使用的分段大小 (以字节为单位)。它必须在 5 MB (含) 和 5 GB (含) 之间。
state
(Aws\Multipart\UploadState) 表示分段上传状态的对象,用于重新开始上次上传。如果提供了此选项,将忽略 bucket、key 和 part_size 选项。
分段复制
AWS SDK for PHP还包含一个 MultipartCopy 对象,用途与 MultipartUploader 相似,但用于在 Amazon S3 内部复制 5 GB 到 5 TB 之间的对象。
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\S3\MultipartCopy;
use Aws\Exception\MultipartUploadException;
示例代码
// 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";
}