全部產品
Search
文件中心

Object Storage Service:拷貝檔案(PHP SDK V1)

更新時間:Nov 29, 2025

本文介紹如何在受版本控制的儲存空間(Bucket)中拷貝檔案(Object)。您可以通過CopyObject的方法拷貝小於1 GB的檔案,通過分區拷貝(UploadPartCopy)的方法拷貝大於1 GB的檔案。

注意事項

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

  • 本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見建立OssClient

  • 要拷貝檔案,您必須有oss:GetObjectoss:PutObject許可權。具體操作,請參見為RAM使用者授予自訂的權限原則

拷貝小檔案

對於小於1 GB的檔案,您可以通過CopyObject方法將檔案從源Bucket複製到同一地區的目標Bucket。

  • x-oss-copy-source預設拷貝Object的目前的版本。如果目前的版本是刪除標記,則返回404表示該Object不存在。您可以在x-oss-copy-source中加入versionId來拷貝指定版本的Object,刪除標記不能被拷貝。

  • 您可以將Object的早期版本拷貝到同一個Bucket中,拷貝Object的歷史版本將會成為一個新的目前的版本,達到恢複Object早期版本的目的。

  • 如果目標Bucket已開啟版本控制,OSS將會為新拷貝的Object自動產生唯一的版本ID,此版本ID將會在響應Header的x-oss-version-id中返回。如果目標Bucket未曾開啟或者暫停了版本控制,OSS將會為新拷貝的Object自動產生version ID為”null“的版本,且會覆蓋原versionId為”null“的版本。

  • 目標Bucket在開啟或暫停版本控制狀態下,不支援對Appendable類型Object執行拷貝操作。

以下代碼用於拷貝小檔案:

<?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以杭州為例,其它Region請按實際情況填寫。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填寫不包含Bucket名稱在內的Object的完整路徑,例如example/test.txt。
$object = "<yourObjectName>";
$versionId = "<yourObjectVersionId>";
$to_bucket = $bucket;
$to_object = $object . '.copy';

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

try{
    // 拷貝指定版本的Object。
    $ret = $ossClient->copyObject($bucket, $object, $to_bucket, $to_object, array(OssClient::OSS_VERSION_ID => $versionId));
    print("versionId:" .$ret['x-oss-version-id']);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");    
            

拷貝小檔案的詳細說明請參見CopyObject

拷貝大檔案

對於大於1 GB的檔案,需要使用分區拷貝(UploadPartCopy)。

UploadPartCopy預設從一個已存在的Object的目前的版本中拷貝資料來上傳一個Part。允許通過在x-oss-copy-source的請求Header中附帶versionId的子條件,實現從Object的指定版本進行拷貝,例如x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=111111

說明

SourceObjectName要進行URL編碼。響應中將會返回被拷貝的Object版本ID:x-oss-copy-source-version-id。

如果未指定versionId且拷貝Object的目前的版本為刪除標記,OSS將返回404 Not Found。通過指定versionId來拷貝刪除標記時,OSS將返回400 Bad Request。

以下代碼用於分區拷貝:

<?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以杭州為例,其它Region請按實際情況填寫。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
$object = "<yourObjectName>";
$versionId = "<yourObjectVersionId>";
$to_bucket = $bucket;
$to_object = $object . '.copy';

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

/**
 *  步驟1:初始化一個分區上傳事件,擷取uploadId。
 */
try {
    // 返回uploadId。uploadId是分區上傳事件的唯一標識,您可以根據uploadId發起相關的操作,如取消分區上傳、查詢分區上傳等。
    $uploadId = $ossClient->initiateMultipartUpload($to_bucket, $to_object);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");

/*
 * 步驟2:上傳分區。
 */
$partSize = 10 * 1024 * 1024;
try {
    $meta = $ossClient->getSimplifiedObjectMeta($bucket, $object);
    $uploadSize = $meta[strtolower('Content-Length')];
} catch(OssException $e) {
    printf(__FUNCTION__ . ": getSimplifiedObjectMeta FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
$pieces = $ossClient->generateMultiuploadParts($uploadSize, $partSize);
$responseUploadPart = array();
$uploadPosition = 0;
foreach ($pieces as $i => $piece) {
    $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
    $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
    $upOptions = array(
        // 指定源Object的起始位置。
        'start' => $fromPos,
        // 指定源Object的結束位置。
        'end' => $toPos,
        // 指定源Object的版本ID。
        OssClient::OSS_VERSION_ID => $versionId
    );
    try {
        // 上傳分區。
        $responseUploadPart[] = $ossClient->uploadPartCopy($bucket, $object, $to_bucket, $to_object, ($i + 1), $uploadId, $upOptions);
    } catch(OssException $e) {
        printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPartCopy - part#{$i} FAILED\n");
        printf($e->getMessage() . "\n");
        return;
    }
    printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPartCopy - part#{$i} OK\n");
}
// $uploadParts是由每個分區的ETag和分區號(PartNumber)組成的數組。
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
    $uploadParts[] = array(
        'PartNumber' => ($i + 1),
        'ETag' => $eTag,
    );
}

/**
 * 步驟3:完成分區上傳。
 */
try {
    // 執行completeMultipartUpload操作時,需要提供所有有效$uploadParts。OSS收到提交的$uploadParts後,會逐一驗證每個分區的有效性。當所有的資料分區驗證通過後,OSS將把這些分區組合成一個完整的檔案。
    $ret = $ossClient->completeMultipartUpload($to_bucket, $to_object, $uploadId, $uploadParts);
    // 查看Object的版本資訊。
    print("versionId:" .$ret[OssClient::OSS_HEADER_VERSION_ID]);
}  catch(OssException $e) {
    printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
printf(__FUNCTION__ . ": completeMultipartUpload OK\n");     

分區拷貝的詳細資料請參見UploadPartCopy