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

Precautions

  • 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.
  • The source bucket and the destination bucket must have no retention policies configured. Otherwise, the error message The object you specified is immutable. is returned.
  • The source bucket and the 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;

// Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// In this example, the endpoint of the China (Hangzhou) region is used. Specify the endpoint based on your business requirements. 
$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. The full path of the object cannot contain the bucket name. 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 and destination buckets. 
$to_bucket = "destexamplebucket";
// Specify the full path of the destination object. The full path of the object cannot contain the bucket name. Example: destdir/exampleobject.txt. 
$to_object = "destdir/exampleobject.txt";

$options = array(
    'headers'=>array(
      // Specify whether the CopyObject operation overwrites the object with the same name. In this example, this parameter is set to true, which indicates that the object with the same name cannot be overwritten. 
      // 'x-oss-forbid-overwrite' => 'true',
      // If the ETag value of the source object is the same as the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-match' => '5B3C1A2E053D763E1B002CC****',
      // If the ETag value of the source object is different from the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
      // 'x-oss-copy-source-if-none-match' => '5B3C1A2E053D763E1B002CC****',
      // If the time that is specified in the request is later than or equal to the actual modified time of the source 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 modified time of the source object, 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. In this example, the method is set to COPY, which indicates that 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 you set x-oss-server-side-encryption to KMS. 
      // 'x-oss-server-side-encryption-key-id' => '9468da86-3509-4f8d-a61e-6eab****',
      // Specify the access control list (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 destination object. You can specify multiple tags for the destination 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. In this example, the method is set to COPY, which indicates that 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 that is larger than 1 GB in size, 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.
  3. Use $ossClient->completeMultipartUpload to complete the multipart copy task.

The following code provides an example on how to use multipart copy to copy a large 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\OssClient;
use OSS\Core\OssException;

// Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// In this example, the endpoint of the China (Hangzhou) region is used. Specify the endpoint based on your business requirements. 
$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. The full path of the object cannot contain the bucket name. 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. The full path of the object cannot contain the bucket name. 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 of the source object is the same as the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-match' => '5B3C1A2E053D763E1B002CC****',
                // If the ETag value of the source object is different from the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
                // 'x-oss-copy-source-if-none-match' => '5B3C1A2E053D763E1B002CC****',
                // If the time that is specified in the request is later than or equal to the actual modified time of the source 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 modified time of the source object, 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 more information about the complete sample code that is used to copy a small object, visit GitHub.
    • For more information about the API operations that is called 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 operations that is called to copy a large object, see UploadPartCopy.