Introduction
This code allows you to upload files to Amazon S3, keep them private (in other words, not have them visible/downloadable simply from a S3 URL), but have them accessible from your own web pages.
Background
This project uses the ideas from Donovan Schönknecht and Nettuts+ as points of departure. Donovan has written a S3 PHP interface and Nettuts+ has used his code to implement uploading images and showing hyperlinks to the uploaded images.
This implementation uses the AWS SDK PHP code from Amazon instead of Donovan's code, and keeps the files private as opposed to Nettuts+'s implementation which uploads files to S3 with full public access.
Using the Code
The source code provided includes the AWS SDK PHP (version 2011.01.14), but you can't simply unzip it, throw it on a web server, and make it run. Assuming you have PHP enabled, you still need to do the following things:
- Have an Amazon S3 account.
- Have a bucket called "bucket" (or change the code to look in a different bucket).
- Create a config.inc.php file with your own S3 credentials from the config-sample.inc.php that is included (keep your config.inc.php file in the same folder/directory).
At that point, you should be good to go!
The first part of the code in index.php simply uploads a file using a form:
$s3 = new AmazonS3();
$bucket = "bucket";
if (isset($_POST['submit'])) {
$file = $_FILES['file'];
$filename = $file['name'];
$tmpname = $file['tmp_name'];
$contentType = $file['type'];
$fileResource = fopen($tmpname, 'r');
try {
$response = $s3->create_object($bucket, $filename,
array('fileUpload' => $fileResource, 'contentType' => $contentType));
if ($response->isOK())
echo "<strong>Upload of $filename succeeded.</strong>\n";
else
echo "<strong>Upload of $filename failed.</strong>\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
Note that I've put it into a try/catch
block because S3::create_object()
can blow up (I've notice it do so when I've tried to upload files that are several megabytes).
The second part of index.php displays the files you have in the pre-designated bucket. It loops through the files in the bucket and checks if the file is an image file (a simplistic check of the file extension). If it is an image, it displays it, if not, it makes a hyperlink to it showing a document icon:
$response = $s3->list_objects($bucket);
$contents = $response->body->Contents;
foreach ($contents as $content) {
$filename = $content->Key;
echo "<p>$filename</p>\n";
if (isImage($filename)) {
echo "<img width='150' height='100' src='file." +
"php?bucket=$bucket&filename=$filename'/>\n";
} else {
echo "<a href='file.php?bucket=$bucket&filename=$filename'>" +
"<img width='50' height='50' src='document.png'/></a>\n";
}
}
The hyperlink or the source of the image is gotten from the file.php file, which is very straightforward:
$bucket = $_GET['bucket'];
$filename = $_GET['filename'];
require_once 'sdk.class.php';
$s3 = new AmazonS3();
$response = $s3->get_object($bucket, $filename);
$contentType = $response->header['_info']['content_type'];
header("Content-type: $contentType");
header("Content-Disposition: filename=$filename");
echo $response->body;
The only "magic" lies in the header directives which provide the content type and preserves the file name when downloading.
The only thing missing is more defensive code in both files that restricts its access. I'll leave that up to the reader as an exercise :-)
Points of Interest
At first, I was stupidly futzing around with PHP GD to make the images appear. However, there's no need for it.