You don’t have to make files on Amazon S3 public (they aren’t by default). But you can generate special keys to allow access to private files. These keys are passed through the URL and can be made to expire.
<?php
if(!function_exists('el_crypto_hmacSHA1')){
/**
* Calculate the HMAC SHA1 hash of a string.
*
* @param string $key The key to hash against
* @param string $data The data to hash
* @param int $blocksize Optional blocksize
* @return string HMAC SHA1
*/
function el_crypto_hmacSHA1($key, $data, $blocksize = 64) {
if (strlen($key) > $blocksize) $key = pack('H*', sha1($key));
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack( 'H*', sha1(
($key ^ $opad) . pack( 'H*', sha1(
($key ^ $ipad) . $data
))
));
return base64_encode($hmac);
}
}
if(!function_exists('el_s3_getTemporaryLink')){
/**
* Create temporary URLs to your protected Amazon S3 files.
*
* @param string $accessKey Your Amazon S3 access key
* @param string $secretKey Your Amazon S3 secret key
* @param string $bucket The bucket (bucket.s3.amazonaws.com)
* @param string $path The target file path
* @param int $expires In minutes
* @return string Temporary Amazon S3 URL
* @see http://awsdocs.s3.amazonaws.com/S3/20060301/s3-dg-20060301.pdf
*/
function el_s3_getTemporaryLink($accessKey, $secretKey, $bucket, $path, $expires = 5) {
// Calculate expiry time
$expires = time() + intval(floatval($expires) * 60);
// Fix the path; encode and sanitize
$path = str_replace('%2F', '/', rawurlencode($path = ltrim($path, '/')));
// Path for signature starts with the bucket
$signpath = '/'. $bucket .'/'. $path;
// S3 friendly string to sign
$signsz = implode("\n", $pieces = array('GET', null, null, $expires, $signpath));
// Calculate the hash
$signature = el_crypto_hmacSHA1($secretKey, $signsz);
// Glue the URL ...
$url = sprintf('http://%s.s3.amazonaws.com/%s', $bucket, $path);
// ... to the query string ...
$qs = http_build_query($pieces = array(
'AWSAccessKeyId' => $accessKey,
'Expires' => $expires,
'Signature' => $signature,
));
// ... and return the URL!
return $url.'?'.$qs;
}
}
?>
Usage
<?php echo el_s3_getTemporaryLink('your-access-key', 'your-secret-key', 'bucket-name', '/path/to/file.mov'); ?>
You should mention the real author when you paste my code here.
Without further ado… the original source of this snippet is:
5ubliminal’s Amazon S3 Expiring Link Builder.
Thank you!
Great, thanks for noting. I always try and do that. I was looking for this function for myself, found it on Snipplr, and it wasn’t clear who the original author was, so I just credited the page I found it on.
What is to stop someone from refreshing the screen and getting a new URL? I thought AWS was supposed to be able to provide a secure URL, but short of learning the PHP API is there not a way to deliver content securely?
Thanks for this script. Both of you.
Nothing, but then that NEW link expires after the time limit too. The point is, in order to have a useful link to the file, you have to be viewing that particular page, because otherwise the link is pretty useless.
Chris,
Can you please provide some more detailed instructions for a PHP noob like me?
Got following questions:
a) Where do I put the first file?
b) How do I name it?
c) Where exactly would I put the 2nd box that you show here?
d) Won’t the bad guy be able to see my Access KEy etc when he opens that page?
Thanks.
Your way of explaining everything in this article is actually good, every
one be capable of effortlessly know it, Thanks a lot. http://shop-computer.
info Very very first, for every single store.Try to find the product or service be
substituted for something you normally use?
This is nice tutorial….it helps me a lot.. I have checked all over but didn’t get right solution.
Here I find the right solution without wasting a time…
Nice tutorial.. Kepp it up…
5***** stars
Is there a working version of this anywhere? I saw one on wordpress but the problem was that the temporary link actually revealed the access key if you mouse over it. Another on revealed the access key & secret key when you mouse over it.
So yeah, is there a working version? And if not could someone make this into a workable WordPress plugin? :)
To clarify this blog post, the Amazon documentation (scroll to the last example) specifies that the string to be used to generate the signature is:
“GET\n\n\n1378560058\n/path/to/file”
That string is used to produce a binary sha1-hmac, which should be base64 encoded. It seems strange to do the hmac generation manually (I assume the original code was for older PHP versions) – the following is a more succinct way to do the same thing:
Which would have the same usage:
I like your snippet however would this method still work if the downloadable file is big and url expires while downloading before the file is downloaded completely.
I just have 1 doubt…what if I want the url to be valid forever i.e it should not expire or you can say infinite expiry time
Then you’ll be able to simply make the S3 link public. That’ll give the users unlimited access to the S3 files. The blog post was aiming to restrict that unlimited access by creating a pre-signed URL.
Hi,
Is there anyone who can help me to write the above two functions in c#? I have very little knowledge of php and trying to create the same on .net world.
Thanks in advance,
Anuruddha
Big Ups!
Is there a way to set a custom error page to display when these expire? As far as I can work out you can only do that when using the webhosting options in s3 console. When using that the expiry code here does not work.