全部產品
Search
文件中心

Object Storage Service:PHP分區上傳

更新時間:Jul 04, 2025

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

注意事項

  • 本文範例程式碼以華東1(杭州)的地區IDcn-hangzhou為例,預設使用外網Endpoint,如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見OSS地區和訪問網域名稱

  • 要分區上傳,您必須有oss:PutObject許可權。具體操作,請參見為RAM使用者授予自訂的權限原則

  • 本文以從環境變數讀取存取憑證為例。更多配置訪問憑證的樣本,請參見PHP配置訪問憑證

分區上傳流程

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

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

    調用InitiateMultipartUpload方法返回OSS建立的全域唯一的uploadID。

  2. 上傳分區。

    調用UploadPart方法上傳分區資料。

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

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

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

  3. 完成分區上傳。

    所有分區上傳完成後,調用CompleteMultipartUpload方法將所有分區合并成完整的檔案。

範例程式碼

以下代碼展示如何將本地的大檔案分割成多個分區檔案上傳到儲存空間,然後合并成完整的檔案對象。

<?php

// 引入自動負載檔案,確保依賴庫能夠正確載入
require_once __DIR__ . '/../vendor/autoload.php';

use AlibabaCloud\Oss\V2 as Oss;

// 定義命令列參數的描述資訊
$optsdesc = [
    "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // Bucket所在的地區(必填)
    "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // 訪問網域名稱(可選)
    "bucket" => ['help' => 'The name of the bucket', 'required' => True], // Bucket名稱(必填)
    "key" => ['help' => 'The name of the object', 'required' => True], // 對象名稱(必填)
];

// 將參數描述轉換為getopt所需的長選項格式
// 每個參數後面加上":"表示該參數需要值
$longopts = \array_map(function ($key) {
    return "$key:";
}, array_keys($optsdesc));

// 解析命令列參數
$options = getopt("", $longopts);

// 驗證必填參數是否存在
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === True && empty($options[$key])) {
        $help = $value['help']; // 擷取參數的協助資訊
        echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
        exit(1); // 如果必填參數缺失,則退出程式
    }
}

// 從解析的參數中提取值
$region = $options["region"]; // Bucket所在的地區
$bucket = $options["bucket"]; // Bucket名稱
$key = $options["key"];       // 對象名稱

// 載入環境變數中的憑證資訊
// 使用EnvironmentVariableCredentialsProvider從環境變數中讀取Access Key ID和Access Key Secret
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// 使用SDK的預設配置
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider); // 設定憑證提供者
$cfg->setRegion($region); // 設定Bucket所在的地區
$cfg->setEndpoint('http://oss-cn-hangzhou.aliyuncs.com'); // 設定訪問網域名稱

// 建立OSS用戶端執行個體
$client = new Oss\Client($cfg);

// 初始化分區上傳任務
$initResult = $client->initiateMultipartUpload(
    new Oss\Models\InitiateMultipartUploadRequest(
        bucket: $bucket,
        key: $key
    )
);

// 定義大檔案路徑和分區大小
$bigFileName = "/Users/yourLocalPath/yourFileName"; // 填寫大檔案路徑
$partSize = 5 * 1024 * 1024; // 設定分區大小,單位為位元組(此處設定為1MB)
$fileSize = filesize($bigFileName); // 擷取檔案大小
$partsNum = intdiv($fileSize, $partSize) + intval(1); // 計算分區數量
$parts = []; // 用於儲存每個分區的上傳結果

$i = 1; // 分區編號從1開始
$file = new \GuzzleHttp\Psr7\LazyOpenStream($bigFileName, 'rb'); // 開啟檔案流
while ($i <= $partsNum) {
    // 上傳單個分區
    $partResult = $client->uploadPart(
        new Oss\Models\UploadPartRequest(
            bucket: $bucket,
            key: $key,
            partNumber: $i, // 當前分區編號
            uploadId: $initResult->uploadId, // 初始上傳任務返回的uploadId
            contentLength: null, // 可選:分區內容長度
            contentMd5: null, // 可選:分區內容的MD5校正值
            trafficLimit: null, // 可選:流量限制
            requestPayer: null, // 可選:請求支付方
            body: new \GuzzleHttp\Psr7\LimitStream($file, $partSize, ($i - 1) * $partSize) // 讀取當前分區的資料
        )
    );

    // 儲存分區上傳結果
    $part = new Oss\Models\UploadPart(
        partNumber: $i, // 分區編號
        etag: $partResult->etag // 分區上傳後返回的ETag值
    );

    array_push($parts, $part); // 將當前分區的上傳結果儲存到分區列表中
    $i++; // 遞增分區編號,準備處理下一個分區
}

// 完成分區上傳任務
$comResult = $client->completeMultipartUpload(
    new Oss\Models\CompleteMultipartUploadRequest(
        bucket: $bucket,
        key: $key,
        uploadId: $initResult->uploadId, // 初始上傳任務返回的uploadId
        acl: null, // 可選:設定對象的存取控制清單(ACL)
        completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
            parts: $parts // 提交所有分區的上傳結果
        )
    )
);

// 列印完成分區上傳的結果
printf(
    'status code:' . $comResult->statusCode . PHP_EOL . // HTTP狀態代碼,例如200表示成功
    'request id:' . $comResult->requestId . PHP_EOL .   // 請求ID,用於調試或追蹤請求
    'complete multipart upload result:' . var_export($comResult, true) . PHP_EOL // 完成分區上傳後的詳細結果
);

常見使用情境

分區上傳並設定上傳回調

如果您希望在檔案分區上傳後通知應用伺服器,可參考以下程式碼範例。

<?php

// 引入自動負載檔案,確保依賴庫能夠正確載入
require_once __DIR__ . '/../vendor/autoload.php';

use AlibabaCloud\Oss\V2 as Oss;

// 定義命令列參數的描述資訊
$optsdesc = [
    "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // Bucket所在的地區(必填)
    "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // 訪問網域名稱(可選)
    "bucket" => ['help' => 'The name of the bucket', 'required' => True], // Bucket名稱(必填)
    "key" => ['help' => 'The name of the object', 'required' => True], // 對象名稱(必填)
];

// 將參數描述轉換為getopt所需的長選項格式
// 每個參數後面加上":"表示該參數需要值
$longopts = \array_map(function ($key) {
    return "$key:";
}, array_keys($optsdesc));

// 解析命令列參數
$options = getopt("", $longopts);

// 驗證必填參數是否存在
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === True && empty($options[$key])) {
        $help = $value['help']; // 擷取參數的協助資訊
        echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
        exit(1); // 如果必填參數缺失,則退出程式
    }
}

// 從解析的參數中提取值
$region = $options["region"]; // Bucket所在的地區
$bucket = $options["bucket"]; // Bucket名稱
$key = $options["key"];       // 對象名稱

// 載入環境變數中的憑證資訊
// 使用EnvironmentVariableCredentialsProvider從環境變數中讀取Access Key ID和Access Key Secret
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// 使用SDK的預設配置
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider); // 設定憑證提供者
$cfg->setRegion($region); // 設定Bucket所在的地區
$cfg->setEndpoint('http://oss-cn-hangzhou.aliyuncs.com'); // 設定訪問網域名稱

// 建立OSS用戶端執行個體
$client = new Oss\Client($cfg);

// 初始化分區上傳任務
$initResult = $client->initiateMultipartUpload(
    new Oss\Models\InitiateMultipartUploadRequest(
        bucket: $bucket,
        key: $key
    )
);

// 定義大檔案路徑和分區大小
$bigFileName = "/Users/yourLocalPath/yourFileName"; // 填寫大檔案路徑
$partSize = 5 * 1024 * 1024; // 設定分區大小,單位為位元組(此處設定為1MB)
$fileSize = filesize($bigFileName); // 擷取檔案大小
$partsNum = intdiv($fileSize, $partSize) + intval(1); // 計算分區數量
$parts = []; // 用於儲存每個分區的上傳結果

$i = 1; // 分區編號從1開始
$file = new \GuzzleHttp\Psr7\LazyOpenStream($bigFileName, 'rb'); // 開啟檔案流
while ($i <= $partsNum) {
    // 上傳單個分區
    $partResult = $client->uploadPart(
        new Oss\Models\UploadPartRequest(
            bucket: $bucket,
            key: $key,
            partNumber: $i, // 當前分區編號
            uploadId: $initResult->uploadId, // 初始上傳任務返回的uploadId
            contentLength: null, // 可選:分區內容長度
            contentMd5: null, // 可選:分區內容的MD5校正值
            trafficLimit: null, // 可選:流量限制
            requestPayer: null, // 可選:請求支付方
            body: new \GuzzleHttp\Psr7\LimitStream($file, $partSize, ($i - 1) * $partSize) // 讀取當前分區的資料
        )
    );

    // 儲存分區上傳結果
    $part = new Oss\Models\UploadPart(
        partNumber: $i, // 分區編號
        etag: $partResult->etag // 分區上傳後返回的ETag值
    );

    array_push($parts, $part); // 將當前分區的上傳結果儲存到分區列表中
    $i++; // 遞增分區編號,準備處理下一個分區
}


// 添加x-oss-callback和x-oss-callback-var頭部資訊
// 定義回調地址
$call_back_url = "http://www.example.com/callback";

// 構造回調參數(callback):指定回調地址和回調請求體,使用 Base 64 編碼
// 使用預留位置 {var1} 和 {var2} 替代 ${x:var1} 和 ${x:var2}
$callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}";
$callback_body_replaced = str_replace(
    ['{bucket}', '{object}', '{var1}', '{var2}'],
    [$bucket, $key, 'value1', 'value2'],
    $callback_body_template
);
$callback = base64_encode(json_encode([
    "callbackUrl" => $call_back_url,
    "callbackBody" => $callback_body_replaced
]));

// 構造自訂變數(callback-var),使用 Base 64 編碼
$callback_var = base64_encode(json_encode([
    "x:var1" => "value1",
    "x:var2" => "value2"
]));

// 完成分區上傳任務
$comResult = $client->completeMultipartUpload(
    new Oss\Models\CompleteMultipartUploadRequest(
        bucket: $bucket,
        key: $key,
        uploadId: $initResult->uploadId, // 初始上傳任務返回的uploadId
        acl: null, // 可選:設定對象的存取控制清單(ACL)
        completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
            parts: $parts // 提交所有分區的上傳結果
        ),
        callback: $callback,
        callbackVar: $callback_var,
    )
);

// 列印完成分區上傳的結果
printf(
    'status code:' . $comResult->statusCode . PHP_EOL . // HTTP狀態代碼,例如200表示成功
    'request id:' . $comResult->requestId . PHP_EOL .   // 請求ID,用於調試或追蹤請求
    'complete multipart upload result:' . var_export($comResult, true) . PHP_EOL // 完成分區上傳後的詳細結果
);

相關文檔

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