OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个分片(Part)来分别上传,上传完成后再调用CompleteMultipartUpload接口将这些Part组合成一个Object来达到断点续传的效果。
分片上传流程
分片上传(Multipart Upload)分为以下三个步骤:
初始化一个分片上传事件。
调用$ossClient->initiateMultipartUpload方法返回OSS创建的全局唯一的uploadId。
上传分片。
调用$ossClient->uploadPart方法上传分片数据。
说明对于同一个uploadId,分片号(PartNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,则OSS上该分片已有的数据将会被覆盖。
OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
完成分片上传。
调用$ossClient->completeMultipartUpload方法将所有分片合并成完整的文件。
分片上传完整示例
以下通过一个完整的示例对分片上传的流程进行逐步解析:
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
use OSS\Core\OssUtil;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
//填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。
$object = 'exampledir/exampleobject.txt';
// 填写本地文件的完整路径。
$uploadFile = 'D:\\localpath\\examplefile.txt';
$initOptions = array(
OssClient::OSS_HEADERS => array(
// 指定该Object被下载时的网页缓存行为。
// 'Cache-Control' => 'no-cache',
// 指定该Object被下载时的名称。
// 'Content-Disposition' => 'attachment;filename=oss_download.jpg',
// 指定该Object被下载时的内容编码格式。
// 'Content-Encoding' => 'utf-8',
// 指定过期时间,单位为毫秒。
// 'Expires' => 150,
// 指定初始化分片上传时是否覆盖同名Object。此处设置为true,表示禁止覆盖同名Object。
//'x-oss-forbid-overwrite' => 'true',
// 指定上传该Object的每个part时使用的服务器端加密方式。
// 'x-oss-server-side-encryption'=> 'KMS',
// 指定Object的加密算法。
// 'x-oss-server-side-data-encryption'=>'SM4',
// 指定KMS托管的用户主密钥。
//'x-oss-server-side-encryption-key-id' => '9468da86-3509-4f8d-a61e-6eab1eac****',
// 指定Object的存储类型。
// 'x-oss-storage-class' => 'Standard',
// 指定Object的对象标签,可同时设置多个标签。
// 'x-oss-tagging' => 'TagA=A&TagB=B',
),
);
/**
* 步骤1:初始化一个分片上传事件,并获取uploadId。
*/
try{
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
//返回uploadId。uploadId是分片上传事件的唯一标识,您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
$uploadId = $ossClient->initiateMultipartUpload($bucket, $object, $initOptions);
print("initiateMultipartUpload OK" . "\n");
// 根据uploadId执行取消分片上传事件或者列举已上传分片的操作。
// 如果您需要根据您需要uploadId执行取消分片上传事件的操作,您需要在调用InitiateMultipartUpload完成初始化分片之后获取uploadId。
// 如果您需要根据您需要uploadId执行列举已上传分片的操作,您需要在调用InitiateMultipartUpload完成初始化分片之后,且在调用CompleteMultipartUpload完成分片上传之前获取uploadId。
//print("UploadId: " . $uploadId . "\n");
} catch(OssException $e) {
printf($e->getMessage() . "\n");
return;
}
/*
* 步骤2:上传分片。
*/
$partSize = 10 * 1024 * 1024;
$uploadFileSize = sprintf('%u',filesize($uploadFile));
$pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
$responseUploadPart = array();
$uploadPosition = 0;
$isCheckMd5 = true;
foreach ($pieces as $i => $piece) {
$fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
$toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
$upOptions = array(
// 上传文件。
$ossClient::OSS_FILE_UPLOAD => $uploadFile,
// 设置分片号。
$ossClient::OSS_PART_NUM => ($i + 1),
// 指定分片上传起始位置。
$ossClient::OSS_SEEK_TO => $fromPos,
// 指定文件长度。
$ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
// 是否开启MD5校验,true为开启。
$ossClient::OSS_CHECK_MD5 => $isCheckMd5,
);
// 开启MD5校验。
if ($isCheckMd5) {
$contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
$upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
}
try {
// 上传分片。
$responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
printf("initiateMultipartUpload, uploadPart - part#{$i} OK\n");
} catch(OssException $e) {
printf("initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
printf($e->getMessage() . "\n");
return;
}
}
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
$uploadParts[] = array(
'PartNumber' => ($i + 1),
'ETag' => $eTag,
);
}
/**
* 步骤3:完成上传。
*/
$comOptions['headers'] = array(
// 指定完成分片上传时是否覆盖同名Object。此处设置为true,表示禁止覆盖同名Object。
// 'x-oss-forbid-overwrite' => 'true',
// 如果指定了x-oss-complete-all:yes,则OSS会列举当前uploadId已上传的所有Part,然后按照PartNumber的序号排序并执行CompleteMultipartUpload操作。
// 'x-oss-complete-all'=> 'yes'
);
try {
// 执行completeMultipartUpload操作时,需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
$ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts,$comOptions);
printf( "Complete Multipart Upload OK\n");
} catch(OssException $e) {
printf("Complete Multipart Upload FAILED\n");
printf($e->getMessage() . "\n");
return;
}
分片上传本地文件
以下代码用于分片上传本地文件到OSS。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
//填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。
$object = 'exampledir/exampleobject.txt';
// 填写本地文件的完整路径。
$file = 'D:\\localpath\\examplefile.txt';
$options = array(
OssClient::OSS_CHECK_MD5 => true,
OssClient::OSS_PART_SIZE => 1,
);
try{
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
$ossClient->multiuploadFile($bucket, $object, $file, $options);
} catch(OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": OK" . "\n");
分片上传目录
以下代码用于分片上传本地目录(包含此目录下的所有文件)到OSS。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
// 填写待上传的本地目录的完整路径。
$localDirectory = "D:\\localpath";
// 填写上传至OSS的目录前缀。
$prefix = "samples/codes/";
try {
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
$ossClient->uploadDir($bucket, $prefix, $localDirectory);
} catch(OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": OK" . "\n");
取消分片上传事件
您可以调用$ossClient->abortMultipartUpload方法来取消分片上传事件。当一个分片上传事件被取消后,无法再使用此uploadId做任何操作,已经上传的分片数据会被删除。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
//填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。
$object = 'exampledir/exampleobject.txt';
// 填写uploadId,例如0004B999EF518A1FE585B0C9360D****。uploadId来源于调用InitiateMultipartUpload完成初始化分片之后的返回结果。
$upload_id = '0004B999EF518A1FE585B0C9360D****';
try{
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
$ossClient->abortMultipartUpload($bucket, $object, $upload_id);
} catch(OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": OK" . "\n");
列举已上传的分片
调用listParts方法列举出指定uploadId下所有已经上传成功的分片。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
//填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。
$object = 'exampledir/exampleobject.txt';
// 填写uploadId,例如0004B999EF518A1FE585B0C9360D****。uploadId来源于调用InitiateMultipartUpload完成初始化分片之后,且在调用CompleteMultipartUpload完成分片上传之前的返回结果。
$upload_id = '0004B999EF518A1FE585B0C9360D****';
try{
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
$listPartsInfo = $ossClient->listParts($bucket, $object, $uploadId);
foreach ($listPartsInfo->getListPart() as $partInfo) {
print($partInfo->getPartNumber() . "\t" . $partInfo->getSize() . "\t" . $partInfo->getETag() . "\t" . $partInfo->getLastModified() . "\n");
}
} catch(OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": OK" . "\n");
列举分片上传事件
调用listMultipartUploads方法列举出所有执行中的分片上传事件,即已初始化但还未完成(Complete)或者还未中止(Abort)的分片上传事件。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
$endpoint = 'https://oss-cn-hangzhou.aliyuncs.com';
// 填写Bucket名称,例如examplebucket。
$bucket= 'examplebucket';
$options = array(
'delimiter' => '/',
'max-uploads' => 100,
'key-marker' => '',
'prefix' => '',
'upload-id-marker' => ''
);
try {
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
$listMultipartUploadInfo = $ossClient->listMultipartUploads($bucket, $options);
} catch(OssException $e) {
printf(__FUNCTION__ . ": listMultipartUploads FAILED\n");
printf($e->getMessage() . "\n");
return;
}
printf(__FUNCTION__ . ": listMultipartUploads OK\n");
$listUploadInfo = $listMultipartUploadInfo->getUploads();
var_dump($listUploadInfo);
$options的参数说明请参见下表。
参数 | 说明 |
delimiter | 用于对文件名称进行分组的一个字符。所有文件名称包含指定的前缀且第一次出现delimiter字符之间的文件作为一组元素。 |
key-marker | 所有文件名称的字典序大于key-marker参数值的分片上传事件。与upload-id-marker参数一同使用,用于指定返回结果的起始位置。 |
max-uploads | 限定此次返回分片上传事件的最大个数,默认值和最大值均为1000。 |
prefix | 限定返回的文件名称必须以指定的prefix作为前缀。 说明 使用prefix查询时,返回的文件名称中仍会包含prefix。 |
upload-id-marker | 与key-marker参数一同使用,用于指定返回结果的起始位置。 如果未设置key-marker参数,则此参数无效。如果设置了key-marker参数,则查询结果中包含:
|
相关文档
关于分片上传的完整示例代码,请参见GitHub示例。
分片上传的完整实现涉及三个API接口,详情如下:
关于初始化分片上传事件的API接口说明,请参见InitiateMultipartUpload。
关于分片上传Part的API接口说明,请参见UploadPart。
关于完成分片上传的API接口说明,请参见CompleteMultipartUpload。
关于取消分片上传事件的API接口说明,请参见AbortMultipartUpload。
关于列举已上传分片的API接口说明,请参见ListParts。
关于列举所有执行中的分片上传事件(即已初始化但尚未完成或已取消的分片上传事件)的API接口说明,请参见ListMultipartUploads。