I have been trying for weeks to properly format a REST request to the Amazon AWS S3 API using the available examples on the web
Have you tried the Amazon AWS SDK for PHP? It's comprehensive, complete, and most importantly, written by Amazon. If their own code isn't working for you, something's gonna be really wrong.
Here is example code using the linked SDK to upload example.txt
in the current directory to a bucket named 'my_very_first_bucket'.
<?php
// Complain wildly.
ini_set('display_errors', true);
error_reporting(-1);
// Set these yourself.
define('AWS_KEY', '');
define('AWS_SECRET_KEY', '');
// We'll assume that the SDK is in our current directory
include_once 'sdk-1.3.1/sdk.class.php';
include_once 'sdk-1.3.1/services/s3.class.php';
// Set the bucket and name of the file we're sending.
// It happens that we're actually uploading the file and
// keeping the name, so we're re-using the variable
// below.
$bucket_name = 'my_very_first_bucket';
$file_to_upload = 'example.txt';
// Fire up the object
$s3 = new AmazonS3(AWS_KEY, AWS_SECRET_KEY);
// This returns a "CFResponse"
$r = $s3->create_object(
$bucket_name,
$file_to_upload,
array(
// Filename of the thing we're uploading
'fileUpload' => (__DIR__ . '/' . $file_to_upload),
// ACL'd public.
'acl' => AmazonS3::ACL_PUBLIC,
// No wai.
'contentType' => 'text/plain',
// The docs say it'll guess this, but may as well.
'length' => filesize(__DIR__ . '/' . $file_to_upload)
)
);
// Did it work?
echo "Worked: ";
var_dump($r->isOK());
// Status as in HTTP.
echo "\nStatus: ";
var_dump($r->status);
// The public URL by which we can reach this object.
echo "\nURL: ";
echo $s3->get_object_url($bucket_name, $file_to_upload);
// Tada!
echo "\n";
Appropriate API docs:
You can navigate the rest of the methods in the left menu. It's pretty comprehensive, including new bucket creation, management, deletion, same for objects, etc.
You should be able to basically drop this in to your code and have it work properly. PHP 5.2-safe.
Edit by Silver Tiger:
Charles -
The method you provide is using the API SDK functions to upload a file from the local file system to a bucket of my choosing. I have that part working already via Flex and uploads work like a charm. The problem in question is being able to submit a REST request to AWS S3 to change the file name from it's current "uploaded" name, to a new name more suited name that will work with my back end (database, tracking etc, which I handle and display seperately in PHP with MyySQL).
AWS S3 does not truly support a "copy" function, so they provided a method to re-"PUT" a file by reading the source from your own bucket and placing a new copy with a different name in the same bucket. The difficulty I have been having is processing the REST request, hence the HMAC encryption.
I do appreciate your time and understand the example you have provided as i also have a working copy of the PHP upload that was functioning before I designed the Flex application. The reason for the Flex was to enable status updates and a dynamically updated progress bar, which is also working like a charm :).
I will continue to persue a REST solution as from the perspective of Amason zupport, it will be the only way i can rename a file already existing in my bucket per thier support team.
As always, if you have input or suggestions regarding the REST submission I would be greatful for any feedback.
Thanks,
Silver Tiger
Proof copy/delete works:
$r = $s3->copy_object(
array( 'bucket' => $bucket_name, 'filename' => $file_to_upload ),
array( 'bucket' => $bucket_name, 'filename' => 'foo.txt' )
);
// Did it work?
echo "Worked: ";
var_dump($r->isOK());
// Status as in HTTP.
echo "\nStatus: ";
var_dump($r->status);
// The public URL by which we can reach this object.
echo "\nURL: ";
echo $s3->get_object_url($bucket_name, 'foo.txt');
echo "\nDelete: ";
// Nuke?
$r = $s3->delete_object($bucket_name, $file_to_upload);
// Did it work?
echo "Worked: ";
var_dump($r->isOK());
// Status as in HTTP.
echo "\nStatus: ";
var_dump($r->status);
Edit by Silver Tiger:
Charles -
No REST needed, no bothers ... SDK 1.3.1 and your help solved the issue. the code I used to test looks a lot like yours :
// Complain wildly.
ini_set('display_errors', true);
error_reporting(-1);
// Set these yourself.
define('AWS_KEY', 'removed for security');
define('AWS_SECRET_KEY', 'removed for security');
// We'll assume that the SDK is in our current directory
include_once 'includes/sdk-1.3.1/sdk.class.php';
include_once 'includes/sdk-1.3.1/services/s3.class.php';
// Set the bucket and name of the file we're sending.
// It happens that we're actually uploading the file and
// keeping the name, so we're re-using the variable
// below.
$bucket = 'bucket';
$file_to_upload = 'example.txt';
$Source_file_to_copy = 'Album.jpg';
$Destination_file = 'Album2.jpg';
// Fire up the object
// Instantiate the class
$s3 = new AmazonS3();
$response = $s3->copy_object(
array( // Source
'bucket' => $bucket,
'filename' => $Source_file_to_copy
),
array( // Destination
'bucket' => $bucket,
'filename' => $Destination_file
)
);
// Success?
var_dump($response->isOK());
Now I will implement the delete after the copy, and we're golden. Thank you sir for your insight and help.
Silver Tiger
Best Solution
S3 returns a 403 instead of a 404 when the user doesn't have permission to list the bucket contents.
If you query for an object and receive a 404, then you know that object doesn't exist. This is information you shouldn't know if you don't have permission to list the bucket contents so instead of telling you it doesn't exist, S3 just tells you that you're trying to do something you're not allowed to do. When you get a 403 instead of a 404 you have no way of knowing that the object you requested doesn't exist. It might not exist or it might exist and you just don't have permission to access it. There's no way for you to know for sure and so no security is bypassed.
I believe anyone with access to list the bucket contents will get a 404 instead of a 403.