All Products
Search
Document Center

Object Storage Service:Copy objects

Last Updated:Mar 11, 2024

This topic describes how to copy an object in a versioning-enabled bucket in Object Storage Service (OSS). You can use CopyObject to copy an object that is up to 1 GB in size and use UploadPartCopy to copy an object larger than 1 GB in size.

Usage notes

  • In this topic, the public endpoint of the China (Hangzhou) region is used. If you want to access OSS from other Alibaba Cloud services in the same region as OSS, use an internal endpoint. For more information about OSS regions and endpoints, see Regions and endpoints.

  • In this topic, an OSSClient instance is created by using an OSS endpoint. If you want to create an OSSClient instance by using custom domain names or Security Token Service (STS), see Create an OSSClient instance.

  • To copy an object, you must have the oss:GetObject and oss:PutObject permissions. For more information, see Attach a custom policy to a RAM user.

Copy a small object

You can call CopyObject to copy an object that is up to 1 GB in size from a source bucket to a destination bucket in the same region.

  • If you do not specify a version ID in the x-oss-copy-source header of the CopyObject request, the current version of the object is copied. If the current version of the object is a delete marker, OSS returns HTTP status code 404, which indicates that the object does not exist. You can specify a version ID in the x-oss-copy-source header to copy a specific object version. Delete markers cannot be copied.

  • You can copy a previous version of an object to the same bucket. The copied previous version becomes the current version of the object. This way, the previous version of the object is recovered as the latest version.

  • If versioning is enabled for the destination bucket, OSS generates a unique version ID for the destination object and returns the x-oss-version-id header in the response to indicate the version ID of the destination object. If the versioning state of the destination bucket is unversioned or suspended, OSS generates a version whose version ID is null for the destination object and overwrites the original version whose version ID is null.

  • Appendable objects in a bucket for which versioning is enabled or suspended cannot be copied.

The following sample code provides an example on how to copy a small 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;

// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
$provider = new EnvironmentVariableCredentialsProvider();
// In this example, the China (Hangzhou) region is used as the endpoint. Specify your actual endpoint. 
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// Specify the full path of the object. Do not include the bucket name in the full path. Example: example/test.txt. 
$object = "<yourObjectName>";
$versionId = "<yourObjectVersionId>";
$to_bucket = $bucket;
$to_object = $object . '.copy';

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);

try{
    // Copy the specified version of the 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");    
            

For more information about how to copy a small object, see CopyObject.

Copy a large object

To copy an object that is larger than 1 GB in size, you must split the object into parts and copy the parts by calling UploadPartCopy.

By default, the UploadPartCopy operation uploads a part by copying data from the current version of the specified object. You can add a version ID to the x-oss-copy-source request header as the condition to upload an object by copying data from the specified version of the object. Example: x-oss-copy-source: /SourceBucketName/SourceObjectName?versionId=111111.

Note

The value of the SourceObjectName parameter must be URL-encoded. The version ID of the copied object is returned in the x-oss-copy-source-version-id response header.

If no version ID is specified in the request and the current version of the source object is a delete marker, OSS returns 404 Not Found. If versionId is specified in the request and the specified version of the source object is a delete marker, OSS returns 400 Bad Request.

The following code provides an example on how to copy a large object by part:

<?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;

// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
$provider = new EnvironmentVariableCredentialsProvider();
// In this example, the China (Hangzhou) region is used as the endpoint. Specify your actual endpoint. 
$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,
    );
    $ossClient = new OssClient($config);

/**
 * Step 1: Initiate a Multipart upload task and obtain the upload ID. 
 */
try {
    // Obtain the upload ID. The upload ID is the unique identifier for a multipart upload task. You can perform related operations, such as canceling or querying the multipart upload task based on the upload ID. 
    $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");

/*
 * Step 2: Upload parts. 
 */
$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(
        // Specify the position of the source object from which the multipart copy task starts. 
        'start' => $fromPos,
        // Specify the position of the source object at which the multipart copy task ends. 
        'end' => $toPos,
        // Specify the version ID of the source object that you want to copy. 
        OssClient::OSS_VERSION_ID => $versionId
    );
    try {
        // Upload the parts. 
        $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");
}
// The $uploadParts parameter is an array that consists of the ETag and PartNumber parameters of each part. 
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
    $uploadParts[] = array(
        'PartNumber' => ($i + 1),
        'ETag' => $eTag,
    );
}

/**
 /* Step 3: Complete the multipart upload task. 
 */
try {
    // All valid values of the $uploadParts parameter are required for the CompleteMultipartUpload operation. After OSS receives the values of the $uploadParts parameter, OSS verifies all parts one by one. After all the parts are verified, OSS combines the parts into a complete object. 
    $ret = $ossClient->completeMultipartUpload($to_bucket, $to_object, $uploadId, $uploadParts);
    // Display the version ID of the 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");     

For more information about multipart copy, see UploadPartCopy.