All Products
Search
Document Center

Object Storage Service:Copy files (PHP SDK V1)

Last Updated:Mar 20, 2026

Copy an object within a bucket or from a source bucket to a destination bucket in the same region. Use this operation to:

  • Create additional copies of objects.

  • Rename objects by copying them and then deleting the originals.

  • Change object metadata without re-uploading the object.

  • Move data between buckets in the same region.

Prerequisites

Before you begin, make sure that you have:

Usage notes

  • The source bucket and destination bucket must be in the same region. Cross-region copies are not supported. For example, you cannot copy from a bucket in China (Hangzhou) to a bucket in China (Qingdao).

  • If either the source or destination bucket has a retention policy configured, the copy fails with: The object you specified is immutable.

  • The examples in this topic use the public endpoint for China (Hangzhou): oss-cn-hangzhou.aliyuncs.com. To access OSS from other Alibaba Cloud services in the same region, use the internal endpoint.

Choose a copy method

Object sizeMethodSDK call
Smaller than 1 GBSimple copycopyObject
Larger than 1 GBMultipart copyinitiateMultipartUploaduploadPartCopycompleteMultipartUpload

Copy a small file

Use $ossClient->copyObject for objects smaller than 1 GB.

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

// Read credentials from environment variables.
// Set OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET before running this example.
$provider = new EnvironmentVariableCredentialsProvider();

$endpoint    = "https://oss-cn-hangzhou.aliyuncs.com"; // Replace with your endpoint.
$from_bucket = "srcexamplebucket";                     // Source bucket name.
$from_object = "srcdir/exampleobject.txt";             // Source object path (no bucket name).
$to_bucket   = "destexamplebucket";                    // Destination bucket name.
$to_object   = "destdir/exampleobject.txt";            // Destination object path (no bucket name).

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

    $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");

Optional request headers

Pass optional headers in the $options array to control copy behavior:

HeaderDescription
x-oss-forbid-overwriteSet to true to prevent overwriting a destination object with the same name.
x-oss-copy-source-if-matchCopy only if the source object ETag matches the specified value. Returns 200 OK on match.
x-oss-copy-source-if-none-matchCopy only if the source object ETag does not match the specified value. Returns 200 OK on mismatch.
x-oss-copy-source-if-unmodified-sinceCopy only if the source object has not been modified since the specified time.
x-oss-copy-source-if-modified-sinceCopy only if the source object has been modified since the specified time.
x-oss-metadata-directiveHow to set metadata on the destination object. Set to COPY to copy metadata from the source.
x-oss-server-side-encryptionServer-side encryption algorithm for the destination object (for example, KMS).
x-oss-server-side-encryption-key-idCustomer master key (CMK) ID managed by Key Management Service (KMS). Valid only when x-oss-server-side-encryption is set to KMS.
x-oss-object-aclAccess permissions for the destination object (for example, private).
x-oss-storage-classStorage class for the destination object (for example, Standard).
x-oss-taggingTags for the destination object. Specify multiple tags as key-value pairs: k1=v1&k2=v2.
x-oss-tagging-directiveHow to set tags on the destination object. Set to COPY to copy tags from the source.

Example with optional headers:

$options = [
    'headers' => [
        'x-oss-forbid-overwrite'   => 'true',
        'x-oss-metadata-directive' => 'COPY',
        'x-oss-object-acl'         => 'private',
        'x-oss-storage-class'      => 'Standard',
    ],
];
$ossClient->copyObject($from_bucket, $from_object, $to_bucket, $to_object, $options);

Copy a large file

For objects larger than 1 GB, use multipart copy: split the object into parts and copy each part with uploadPartCopy. All parts except the last must be larger than 100 KB.

Steps:

  1. Call $ossClient->initiateMultipartUpload to initialize the multipart copy task and get an upload ID.

  2. Call $ossClient->uploadPartCopy for each part. All parts except the last must be larger than 100 KB.

  3. Call $ossClient->completeMultipartUpload to commit the task.

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

// Read credentials from environment variables.
// Set OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET before running this example.
$provider = new EnvironmentVariableCredentialsProvider();

$endpoint    = "http://oss-cn-hangzhou.aliyuncs.com"; // Replace with your endpoint.
$from_bucket = "yourSrcBucketName";
$from_object = "yourSrcObjectName";
$to_bucket   = "yourDestBucketName";
$to_object   = "yourDestObjectName";

$part_size = 256 * 1024 * 1024; // 256 MB per part. Adjust as needed.

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

    // Get the source object size.
    $objectMeta = $ossClient->getObjectMeta($from_bucket, $from_object);
    $length     = $objectMeta['content-length'] + 0;

    // Step 1: Initialize the multipart copy task.
    $upload_id = $ossClient->initiateMultipartUpload($to_bucket, $to_object);

    // Step 2: Copy parts.
    $pieces               = $ossClient->generateMultiuploadParts($length, $part_size);
    $response_upload_part = [];
    $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 = [
            'start' => $from_pos,
            'end'   => $to_pos,
            'headers' => [
                // If the ETag of the source object matches the ETag that you specify, OSS copies the object and returns 200 OK.
                // 'x-oss-copy-source-if-match' => '5B3C1A2E053D763E1B002CC****',
                // If the ETag of the source object does not match the ETag that you specify, OSS copies the object and returns 200 OK.
                // 'x-oss-copy-source-if-none-match' => '5B3C1A2E053D763E1B002CC****',
                // If the specified time is the same as or later than the actual 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 specified time is earlier than the actual modification time of the 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++;
    }

    // Step 3: Commit the multipart copy task.
    $upload_parts = [];
    foreach ($response_upload_part as $i => $etag) {
        $upload_parts[] = [
            '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");

What's next

  • For the complete sample code, see GitHub.

  • For the API reference for simple copy, see CopyObject.

  • For the API reference for multipart copy, see UploadPartCopy.