Amazon S3 SDK for PHP v2.0
I want to change my file upload code so that, instead of storing files on my server, they’re hosted in Amazon S3.
I’ve been playing with Undesigned‘s S3 class, but there seems to be a problem with it: when I specifyserver-side encryption of my files on S3, I get an error (watching tail -f /var/log/apache2/error.log):
S3::putObject(): [SignatureDoesNotMatch] The request signature we calculated does not
match the signature you provided. Check your key and signing method.
The error only appears when I request SSE, and the advice I’ve seen on Stack Overflow regarding this kind of error seems to be, use the Amazon AWS SDK for PHP. But there aren’t yet (early 2013) many tutorials around for a PHP SDK Version 2 solution, so I’m going to have to blunder around like an oaf until I work it out, leaving a turdtrail of crappy notes in my wake, purely selfishly because I know I’ll forget what I find out within a month.
Installation
Caveat
I’ve got an EC2 instance (Ubuntu 12.04) to play with. If you’re on shared hosting and/or don’t have command-line access to your server, I can’t help you installing what you might need to pursue this exact solution.
I’m not going to say “get Amazon EC2″ because I know there are rumblings in the community about EC2 being wonderfully scalable, but not providing emphatically good value-for-money in terms of computing power – but having a free-tier AWS rig to play with is definitely teaching me some useful DevOps chops.
Composer
The SDK documentation makes multiple references to the PHP package manager Composer, so – while there are alternative solutions using PEAR or phar, I decided to install Composer, using these instructions…
In some directory (not important where):
curl -sS https://getcomposer.org/installer | php
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
That creates a command composer… and it worked for me, I can execute it (the file’s executable, and when I type composer at the command prompt, I see a list of options)
Tell Composer what libraries your project depends on
The project I’m working on uses the CodeIgniter framework, and 3rd-party class files are typically stored in the project’s application/libraries directory. Your project’s likely completely different – just work out the best file path for your code.
So my first attempt at installing the AWS SDK in my project is to create the file application/libraries/composer.json.
The file contains just a reference to the AWS SDK package – here’s its total contents:
{
"require": {
"aws/aws-sdk-php": "*"
}
}
Actually install the packages
cd /path/to/application/libraries composer install
OK – composer does some work, then reports in the terminal that it’s installed various packages (EG symfony/event-dispatcher, guzzle/guzzle, aws/aws-sdk-php) – no errors reported.
Tell PHP code about installed packages
The next step is to “require Composer’s autoloader”, says the AWS documentation. I haven’t read up on this properly – I’m guilty here of just installing Composer to achieve a specific goal, thinking “maybe that’ll come in handy again sometime”. Sorry. I expect Composer’s proper cool. Sorry.
At the command prompt, from my application/libraries directory, a ls -l command shows a new directory called “vendor”. In that, there’s a file “autoload.php”, and subdirectories with names like “aws” and “guzzle”. Looks good. So I predict that, to require my autoloader, it’s a case of writing a line in whatever files use the SDK, saying:
require_once('relative/path/to/application/libraries/vendor/autoload.php');
…And a quick test suggests that works fine.
Writing Code
So now for the actual challenge itself: code to upload a file to S3, optionally declaring that it should be server-side encrypted. This is where I was having trouble with the Undesigned S3 class (and I wasn’t alone) – I think maybe, in the S3 API, the option to specify at runtime whether a given file should be server-side encrypted is a relatively recent/late feature, and I don’t know how well-supported it is in the various libraries. That’s why I wanted to base my solution on the version 2 SDK.
I had a look at the documentation, but couldn’t see the relevant detail, so I dropped a post on the AWS Developer forum. Turns out I’d failed to work out the UI of the documentation, and just hadn’t clicked on the section heading to reveal the details. Patiently corrected by a guy called Michael at AWS, I found my way to the docs, and this time clicked on the paragraph and saw the goodness:
Accepts an associative array with the following keys (required keys are bold):
- ACL – (string) – The canned ACL to apply to the object.
- …ner ner probably very cool options here…
- Bucket – (string)
- …ner ner…
- Key – (string)
- …options ner…
- ServerSideEncryption – (string) – The Server-side encryption algorithm used when storing this object in S3.
- …
So now, I just needed to add the option to my code whenever it’s needed.
$s3 = S3Client::factory(array(
'key' => $this->config->item('access_key_id', 's3'),
'secret' => $this->config->item('access_key', 's3'),
'region' => Region::IRELAND
));
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $key,
'SourceFile' => $file,
'ServerSideEncryption' => 'AES256',
'ACL' => CannedAcl::PRIVATE_ACCESS
));
Boom shaka-laka. I thought I should write it up to make sure I had the process recorded, because there are a number of steps there (EG Composer installation)… but it’s cool, it all works.
Plus, check out my funny band: http://www.youtube.com/watch?v=vZfzP88Fmlg
Reblogged this on Ninja Develop.