全部產品
Search
文件中心

Object Storage Service:PHP分區上傳

更新時間:Nov 02, 2024

OSS提供的分區上傳(Multipart Upload)功能,將要上傳的較大檔案(Object)分成多個分區(Part)來分別上傳,上傳完成後再調用CompleteMultipartUpload介面將這些Part組合成一個Object來達到斷點續傳的效果。

分區上傳流程

分區上傳(Multipart Upload)分為以下三個步驟:

  1. 初始化一個分區上傳事件。

    調用$ossClient->initiateMultipartUpload方法返回OSS建立的全域唯一的uploadId。

  2. 上傳分區。

    調用$ossClient->uploadPart方法上傳分區資料。

    說明
    • 對於同一個uploadId,分區號(PartNumber)標識了該分區在整個檔案內的相對位置。如果使用同一個分區號上傳了新的資料,則OSS上該分區已有的資料將會被覆蓋。

    • OSS將收到的分區資料的MD5值放在ETag頭內返回給使用者。

    • OSS計算上傳資料的MD5值,並與SDK計算的MD5值比較,如果不一致則返回InvalidDigest錯誤碼。

  3. 完成分區上傳。

    調用$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參數,則查詢結果中包含:

  • 檔案名稱的字典序大於key-marker參數值的所有檔案。

  • 檔案名稱等於key-marker參數值且uploadId比upload-id-marker參數值大的所有分區上傳事件。

相關文檔

  • 關於分區上傳的完整範例程式碼,請參見GitHub樣本

  • 分區上傳的完整實現涉及三個API介面,詳情如下:

  • 關於取消分區上傳事件的API介面說明,請參見AbortMultipartUpload

  • 關於列舉已上傳分區的API介面說明,請參見ListParts

  • 關於列舉所有執行中的分區上傳事件(即已初始化但尚未完成或已取消的分區上傳事件)的API介面說明,請參見ListMultipartUploads