Copy objects using OSS SDK for PHP 2.0
Use the OSS PHP SDK V2 to copy objects within a versioning-enabled bucket. For objects up to 1 GB, use CopyObject. For objects larger than 1 GB, split them into parts and copy each part using UploadPartCopy.
Prerequisites
Before you begin, ensure that you have:
oss:GetObjectandoss:PutObjectpermissions on both the source and destination buckets. For details, see Attach a custom policy to a RAM user.(Optional) The version ID of the object you want to copy, if you need to copy a specific version.
Usage notes
The sample code uses region ID
cn-hangzhou. By default, a public endpoint is used. To access OSS from other Alibaba Cloud services in the same region, use an internal endpoint. For a full list of regions and endpoints, see Regions and endpoints.CopyObjectcopies objects up to 1 GB from a source bucket to a destination bucket in the same region. For objects larger than 1 GB, use multipart copy.
Copy an object
CopyObject copies the current version of an object by default. To copy a specific version, set the sourceVersionId parameter.
Version ID behavior:
No version ID specified: copies the current version. If the current version is a delete marker, OSS returns HTTP 404.
Version ID specified: copies that specific version. Delete markers cannot be copied.
Copy a previous version to the same bucket: that version becomes the current version, effectively restoring it.
Destination bucket behavior:
Versioning enabled: OSS generates a unique version ID for the destination object, returned in the
x-oss-version-idresponse header.Versioning disabled or suspended: OSS assigns a null version ID and overwrites any existing null version.
The following example copies a specific version of an object:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// Load credentials from environment variables.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
// Initialize the client.
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion('cn-hangzhou'); // Replace with your region.
// $cfg->setEndpoint('<your-endpoint>'); // Uncomment to use an internal or custom endpoint.
$client = new Oss\Client($cfg);
// Copy the object.
$request = new Oss\Models\CopyObjectRequest(
bucket: '<destination-bucket>', // Destination bucket name.
key: '<destination-key>', // Destination object name.
sourceVersionId: '<source-version-id>', // Version ID of the source object. Remove this line to copy the current version.
);
$request->sourceBucket = '<source-bucket>'; // Source bucket name. Omit if copying within the same bucket.
$request->sourceKey = '<source-key>'; // Source object name.
$result = $client->copyObject($request);
printf(
'status code: %s' . PHP_EOL . // HTTP 200 indicates success.
'request ID: %s' . PHP_EOL, // Use the request ID to trace or debug the request.
$result->statusCode,
$result->requestId
);Replace the following placeholders:
| Placeholder | Description | Example |
|---|---|---|
<destination-bucket> | Name of the destination bucket | my-bucket |
<destination-key> | Name of the destination object | target/photo.jpg |
<source-version-id> | Version ID of the source object | CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDUy |
<source-bucket> | Name of the source bucket | my-source-bucket |
<source-key> | Name of the source object | source/photo.jpg |
Copy objects using multipart copy
For objects larger than 1 GB, use UploadPartCopy to copy the object in parts.
UploadPartCopy copies data from the current version of an object by default. Specify sourceVersionId to copy a specific version.
Delete marker behavior:
No version ID specified and the current version is a delete marker: OSS returns 404 Not Found.
Version ID specified and that version is a delete marker: OSS returns 400 Bad Request.
The multipart copy workflow has four stages:
Initiate: call
initiateMultipartUploadto start the task and get an upload ID.Get object size: call
headObjecton the source to get its content length.Copy parts: split the object into 1 MB parts and call
uploadPartCopyfor each part. Collect the ETag from each response.Complete: call
completeMultipartUploadwith the part list to assemble the final object.
The following example copies an object larger than 1 GB using multipart copy:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// Load credentials from environment variables.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
// Initialize the client.
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion('cn-hangzhou'); // Replace with your region.
// $cfg->setEndpoint('<your-endpoint>'); // Uncomment to use an internal or custom endpoint.
$client = new Oss\Client($cfg);
$destinationBucket = '<destination-bucket>'; // Destination bucket name.
$destinationKey = '<destination-key>'; // Destination object name.
$sourceBucket = '<source-bucket>'; // Source bucket name. Set to $destinationBucket if copying within the same bucket.
$sourceKey = '<source-key>'; // Source object name.
$sourceVersionId = '<source-version-id>'; // Version ID of the source object. Remove this to copy the current version.
// Stage 1: Initiate the multipart copy task.
$initResult = $client->initiateMultipartUpload(
new Oss\Models\InitiateMultipartUploadRequest(bucket: $destinationBucket, key: $destinationKey)
);
$uploadId = $initResult->uploadId;
// Stage 2: Get the size of the source object.
$headResult = $client->headObject(
new Oss\Models\HeadObjectRequest(bucket: $sourceBucket, key: $sourceKey)
);
$objectSize = $headResult->contentLength;
// Stage 3: Copy the object in 1 MB parts.
$partSize = 1024 * 1024; // Part size in bytes (1 MB).
$partCount = intdiv($objectSize, $partSize) + 1;
$parts = [];
for ($i = 1; $i <= $partCount; $i++) {
$partRequest = new Oss\Models\UploadPartCopyRequest(
bucket: $destinationBucket,
key: $destinationKey,
partNumber: $i,
uploadId: $uploadId,
sourceVersionId: $sourceVersionId, // Remove this line to copy the current version.
);
$partRequest->sourceBucket = $sourceBucket;
$partRequest->sourceKey = $sourceKey;
$partRequest->sourceRange = getPartRange($objectSize, $partSize, $i);
$partResult = $client->uploadPartCopy($partRequest);
$parts[] = new Oss\Models\UploadPart(
partNumber: $i,
etag: $partResult->etag, // Save the ETag to complete the upload later.
);
}
// Stage 4: Complete the multipart copy.
$completeResult = $client->completeMultipartUpload(
new Oss\Models\CompleteMultipartUploadRequest(
bucket: $destinationBucket,
key: $destinationKey,
uploadId: $uploadId,
completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(parts: $parts),
)
);
printf(
'status code: %s' . PHP_EOL . // HTTP 200 indicates success.
'request ID: %s' . PHP_EOL . // Use the request ID to trace or debug the request.
'result: %s' . PHP_EOL,
$completeResult->statusCode,
$completeResult->requestId,
var_export($completeResult, true)
);
/**
* Calculates the byte range for a given part.
*
* @param int $totalSize Total size of the source object in bytes.
* @param int $partSize Size of each part in bytes.
* @param int $partNumber Part number (1-based).
* @return string Byte range string, e.g., "bytes 0-1048575".
*/
function getPartRange(int $totalSize, int $partSize, int $partNumber): string
{
$start = ($partNumber - 1) * $partSize;
$end = min($partNumber * $partSize - 1, $totalSize - 1);
return sprintf('bytes %d-%d', $start, $end);
}Replace the following placeholders:
| Placeholder | Description | Example |
|---|---|---|
<destination-bucket> | Name of the destination bucket | my-bucket |
<destination-key> | Name of the destination object | target/large-file.zip |
<source-bucket> | Name of the source bucket | my-source-bucket |
<source-key> | Name of the source object | source/large-file.zip |
<source-version-id> | Version ID of the source object | CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDUy |