Using S3 with CakePHP

Despite the fact I’ve used amazon S3 on and off for the past 3-4 years I’ve never had to integrate the service into anything and on having to do so for a project I’m currently involved in I’ve come across a bit of a misunderstanding of how it works.

I’ve always assumed it was basically access to a file system on a bunch of server space. There was some clever mapping in the background to push the files/directories around but nothing more than that. Turns out my understanding was wrong. I’m sure the files are still pushed around or mapped to huge SANs in a very clever way but amazon S3 does not have the concept of physical directories.

Amazon S3 is simply a map of keys to files at its most basic level. The keys can contain URI mappings but the actual concept of a directory is incorrect. This misunderstanding stems from using third party tools to access S3. It always seemed like you could created a directory in a bucket, but in most of these tools what you are actually doing is creating a specially named file to represent a directory.

This misunderstanding only became apparent when I was using a simple plugin to my system which interfaced with S3. The plugin uploaded physical files, but what I wanted to do was upload directories for the files first. Something which this library didn’t do.

As always there has to be a better way and in fact there most certainly was. I ended up using the excellent PHP S3 class created by Donovan Schönknecht. Using it was a breeze and integrating it with my CakePHP app turned out to be very simple. Below is an example of pushing a file to S3. Its barebones and not a complete example, in the app I’m working on I have the whole thing integrated with RabbitMQ and the Media plugin through a shell but it should give you an idea of how easy this class is to use.

Download the S3 class and place it in your vendors folder, then in your controller assuming the file is already on the server.


public function pushToS3($file) {

  App::import('Vendor', 'S3');
  $s3 = new S3('access_key', 'secret_key');

  $upload_file = $s3->inputFile($file, false);
  $s3->putObject($upload_file, 'bucket', $file, S3::ACL_PUBLIC_READ);

}

Its as simple as that. The third argument to the putObject() function is where you specify the key to the file, if you want a URI with a directory like structure here is where you specify it.

Huge thanks must go to Donovan Schönknecht as his class takes absolutely all of the heavy lifting required out of interfacing with S3. There’s a whole bunch of operations which the class can do, so if you need to do stuff a bit more complex I would highly recommend using this class.