AWS S3: Copy object fails when object name contains % with an error – Invalid copy source encoding

Advertisements

I have a PHP script that copies files from one folder to another in an S3 bucket using the copyObject action. However, when a filename contains a percentage sign (%) this results in a 400 Bad Request error:

<Error><Code>InvalidArgument</Code><Message>Invalid copy source encoding</Message><ArgumentName>x-amz-copy-source</Argum (truncated...) InvalidArgument (client): Invalid copy source encoding - <Error><Code>InvalidArgument</Code><Message>Invalid copy source encoding</Message><ArgumentName>x-amz-copy-source</ArgumentName><ArgumentValue>x-amz-copy-source</ArgumentValue><RequestId>MJ6JPP4CJY87A4D2</RequestId><HostId>3iEO5xRKnpHhNAp+pTpGYUWgVEwP97k2qtQuJRTIiBKRL9KFGTMJLXUu8irha4PTtW2q3hWdxQA=</HostId></Error>'

An example of a problematic filename is: ID!@£$%.jpg

Relevant PHP code:-

$filename = 'ID!@£$%.png';
$file_key = 'source/' . $filename;
$new_file_key = 'destination/' . $filename;
$bucketname = 'my-bucket';

$result = $client->copyObject(array(
  'Bucket'     => $bucketname,
  'Key'        => $new_file_key,
  'CopySource' => $bucketname."/".($file_key),
  'MetadataDirective' => 'COPY',
));

I also tried making a copy-object operation with aws cli and it worked fine for this filename:

aws s3api copy-object --copy-source my-bucket/source/ID!@£$%.png --key destination/ID!@£$%.jpg --bucket my-bucket

Could someone please help me to figure out what I am doing wrong here?

Thank you.

>Solution :

When you are using AWS SDK for PHP to copy an object from one location to another in S3, the source (CopySource) must be URL-encoded in a specific manner. The issue you’re facing with special characters, like %, in the filename is due to this URL encoding requirement.

Here’s what you need to do:

  1. URL-encode the filename:
    Use PHP’s rawurlencode() function to encode the file key. This function is specifically designed for encoding query string values and is more suitable for this task than urlencode().

  2. Avoid double encoding:
    Since you’re already using URL encoding, ensure that the AWS SDK for PHP doesn’t attempt to encode the value again.

Let’s modify your code:

$filename = 'ID!@£$%.png';
$file_key = 'source/' . $filename;
$new_file_key = 'destination/' . $filename;
$bucketname = 'my-bucket';

// URL encode the file key for the copy source
$encoded_file_key = 'source/' . rawurlencode($filename);

$result = $client->copyObject(array(
  'Bucket'     => $bucketname,
  'Key'        => $new_file_key,
  'CopySource' => $bucketname . "/" . $encoded_file_key,
  'MetadataDirective' => 'COPY',
));

By URL encoding the file key for the CopySource value, your code should work as expected for filenames that include special characters.

Leave a ReplyCancel reply