All Products
Search
Document Center

Object Storage Service:Copy objects

Last Updated:Oct 17, 2023

This topic describes how to copy an object within a bucket or across buckets in the same region.

Usage notes

  • In this topic, the public endpoint of the China (Hangzhou) region is used. If you want to access OSS by using other Alibaba Cloud services in the same region as OSS, use an internal endpoint. For more information about the regions and endpoints supported by OSS, 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.

  • If you copy an object by using a RAM user, the RAM user must have the oss:GetObject read permission on the source object and the oss:GetObject and oss:PutObject read and write permissions on the destination bucket. For more information about how to attach a custom policy to a RAM user, see Common examples of RAM policies.

  • Make sure that no retention policies are configured for the source bucket and the destination bucket. Otherwise, the error message The object you specified is immutable. is returned.

  • The source bucket and destination bucket must be in the same region. For example, objects cannot be copied from a bucket located in the China (Hangzhou) region to another bucket located in the China (Qingdao) region.

Copy a small object

The following code provides an example on how to use $ossClient->copyObject to copy an object that is smaller than 1 GB in size:

<?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\OssClient;
use OSS\Core\OssException;

// Obtain access credentials from environment variables. Before you run the sample code, make sure that you specified the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables.  
$accessKeyId = getenv("OSS_ACCESS_KEY_ID"); 
$accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
// In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// Specify the name of the source bucket. Example: srcexamplebucket. 
$from_bucket = "srcexamplebucket";
// Specify the full path of the source object. Do not include the bucket name in the full path. Example: srcdir/exampleobject.txt. 
$from_object = "srcdir/exampleobject.txt";
// Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. Example: destexamplebucket. 
// If you copy an object within a bucket, make sure that you specify the same bucket name for the source bucket and destination bucket. 
$to_bucket = "destexamplebucket";
// Specify the full path of the destination object. Do not include the bucket name in the full path. Example: destdir/exampleobject.txt. 
$to_object = "destdir/exampleobject.txt";

$options = array(
    'headers'=>array(
      // Specify whether the CopyObject operation overwrites an object that has the same name as the source bucket. In this example, this parameter is set to true. The value true indicates that the operation does not overwrite an object that has the same name as the source bucket. 
      // 'x-oss-forbid-overwrite' => 'true',
      // If the ETag value that you specify in the request is the same as the ETag value of the source object, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-match' => '5B3C1A2E053D763E1B002CC****',
      // If the ETag value that you specify in the request is different from the ETag value of the source object, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-none-match' => '5B3C1A2E053D763E1B002CC****',
      // If the time specified in the request is the same as or later than the modification time of the object, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-unmodified-since' => gmdate('2021-12-09T07:01:56.000Z'),
      // If the time that is specified in the request is earlier than the actual time when the object is modified, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-modified-since' => gmdate('2021-12-09T07:01:56.000Z'),
      // Specify the method that is used to configure the metadata of the destination object. If you set the method to COPY, the metadata of the source object is copied to the destination object. 
      // 'x-oss-metadata-directive' => 'COPY',
      // Specify the server-side encryption algorithm that is used to encrypt the destination object when OSS creates the object. 
      // 'x-oss-server-side-encryption' => 'KMS',
      // Specify the CMK that is managed by KMS. This parameter takes effect only when x-oss-server-side-encryption is set to KMS. 
      // 'x-oss-server-side-encryption-key-id' => '9468da86-3509-4f8d-a61e-6eab****',
      // Specify the ACL of the destination object when OSS creates the object. In this example, the ACL is set to Private, which indicates that only the owner of the object and authorized users have read and write permissions on the object. 
      // 'x-oss-object-acl' => 'private',
      // Specify the storage class of the destination object. In this example, the storage class is set to Standard. 
      // 'x-oss-storage-class' => 'Standard',
      // Specify tags for the object. You can specify multiple tags for the object at the same time. 
      // 'x-oss-tagging' => 'k1=v1&k2=v2&k3=v3',
      // Specify the method that is used to configure tags for the destination object. If you set the method to COPY, the tags of the source object are copied to the destination object. 
      // 'x-oss-tagging-directive' => 'COPY',
    ),
);

try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $ossClient->copyObject($from_bucket, $from_object, $to_bucket, $to_object);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": OK" . "\n");            

Copy a large object

To copy an object whose size is larger than 1 GB, you must split the object into parts and sequentially copy the parts by using UploadPartCopy. To implement multipart copy, perform the following steps:

  1. Use $ossClient->initiateMultipartUpload to initiate a multipart copy task.

  2. Use $ossClient->uploadPartCopy to perform multipart copy. All parts except for the last part must be larger than 100 KB. Each part must be larger than 100 KB in size, except the last part.

  3. Use $ossClient->completeMultipartUpload to complete the multipart copy task.

The following sample 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\OssClient;
use OSS\Core\OssException;

// Obtain access credentials from environment variables. Before you run the sample code, make sure that you specified the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables.  
$accessKeyId = getenv("OSS_ACCESS_KEY_ID"); 
$accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
// In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// Specify the name of the source bucket. 
$from_bucket = "yourSrcBucketName";
// Specify the full path of the source object. Do not include the bucket name in the full path. Example: srcdir/exampleobject.txt. 
$from_object = "yourSrcObjectName";
// Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. 
$to_bucket = "yourDestBucketName";
// Specify the full path of the destination object. Do not include the bucket name in the full path. Example: destdir/exampleobject.txt. 
$to_object = 'yourDestObjectName';

// Specify the part size. Unit: bytes. 
$part_size = 256*1024*1024;

try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $objectMeta = $ossClient->getObjectMeta($from_bucket, $from_object);

    $length = $objectMeta['content-length'] + 0;

    // Initiate a multipart copy task. 
    $upload_id = $ossClient->initiateMultipartUpload($to_bucket, $to_object);

    // Start the multipart copy task. 
    $pieces = $ossClient->generateMultiuploadParts($length, $part_size);
    $response_upload_part = array();
    $copyId = 1;
    $upload_position = 0;

    foreach ($pieces as $i => $piece) {
        $from_pos = $upload_position + (integer)$piece['seekTo'];
        $to_pos = (integer)$piece['length'] + $from_pos - 1;
        $up_options = array(
            'start' => $from_pos,
            'end' => $to_pos,
              'headers'=>array(
                // If the ETag value that you specify in the request is the same as the ETag value of the source object, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-match' => '5B3C1A2E053D763E1B002CC****',
                // If the ETag value that you specify in the request is different from the ETag value of the source object, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-none-match' => '5B3C1A2E053D763E1B002CC****',
                // If the time specified in the request is the same as or later than the modification time of the object, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-unmodified-since' => gmdate('2021-12-09T07:01:56.000Z'),
                // If the time that is specified in the request is earlier than the actual time when the object is modified, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-modified-since' => gmdate('2021-12-09T07:01:56.000Z'),
          ),
        );
        $response_upload_part[] = $ossClient->uploadPartCopy( $from_bucket, $from_object, $to_bucket, $to_object, $copyId, $upload_id, $up_options);
        $copyId = $copyId + 1;
    }

    // Complete the multipart copy task. 
    $upload_parts = array();
    foreach ($response_upload_part as $i => $etag) {
        $upload_parts[] = array(
            'PartNumber' => ($i + 1),
            'ETag' => $etag,
        );
    }
    $result = $ossClient->completeMultipartUpload($to_bucket, $to_object, $upload_id, $upload_parts);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": OK" . "\n");

References

  • Copy a small object

    • For the complete sample code that is used to copy a small object, visit GitHub.

    • For more information about the API operation that you can call to copy a small object, see CopyObject.

  • Copy a large object

    • For more information about the complete sample code that is used to copy a large object, visit GitHub.

    • For more information about the API operation that you can call to copy a large object, see UploadPartCopy.