Amazon S3 Create Expiring Links PHP Script

Have you ever wondered how to to create Amazon S3 expiring links? It is not as hard as Amazon makes it, gosh they have such confusing documentation! You would think that a billion dollar company could make a simple interface with easy to understand documentation.

Before we get started reviewing this simple PHP script, I have a warning: The following code has not been tested in rouge environments. We see no reason to worry about the PHP security but cannot and will not place any type of guarantee. Use at your own risk. This tutorial and script are for educational purposes only.

Let’s get started by looking at the three (3) PHP files for the Amazon S3 Expiring Links:

First PHP file is keys.php which holds your public and secret keys. We recommend you placing this out site of your public we directory (ie; public_html).

# File is best placed: /{outside-public--directory}/keys.php
$secretKey = 'aBaBaBaBaBaBaBaB'

Second PHP file is download.php which is a example file you can test with.

# Include the s3-expiring-url.php for echo below.

<h2>S3 Expiring URL</h2>

<p>Link is valid according to your settings in s3-expiring-url.php. Set value to 1 for a quick test. After loading page wait couple of minutes and try link again.</p>

<p><a href="<?php echo getSignedUrl($awsAccessKey, $secretKey, $bucket, ''); ?>">DOWNLOAD THE FILE</a></p>

Third PHP file is s3-expiring-url.php which is the main part of amazon s3 expiring links.

# This File is: s3-expiring-url.php

# Change the include path to your keys.php (best outside public folder).

# Replace with your bucket name.
$bucket = 'your-bucket-name';

# BE SURE TO SET EXPIRE TIME BELOW @ # Calculate the expire time.

    * 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);

    * Create signed URLs to your protected Amazon S3 files.
    * @param string $awsAccessKey Your Amazon S3 access key
    * @param string $secretKey Your Amazon S3 secret key
    * @param string $bucket The bucket (
    * @param string $objectPath The target file path
    * @param int $expires In minutes
    * @param array $customParams Key value pairs of custom parameters
    * @return string Temporary signed Amazon S3 URL
    * @see
    function getSignedUrl($awsAccessKey, $secretKey, $bucket, $objectPath, $expires = 5, $customParams = array()) {
        # Calculate the expire time 5 = 5 minutes, 30 = 30 Minutes (set to 1 for testing).
        $expires = time() + intval(floatval($expires) * 30);
        # Clean and url-encode the object path.
        $objectPath = str_replace(array('%2F', '%2B'), array('/', '+'), rawurlencode( ltrim($objectPath, '/') ) );
        # Create the object path for use in the signature.
        $objectPathForSignature = '/'. $bucket .'/'. $objectPath;
        # Create the S3 friendly string to sign.
        $stringToSign = implode("\n", $pieces = array('GET', null, null, $expires, $objectPathForSignature));
        # Create the URL friendly string to use.
        $url = 'http://' . $bucket . '' . $objectPath;
        # Custom parameters.
        $appendCharacter = '?'; // Default append character.
        # Loop through the custom query parameters (if any) and append them to the string-to-sign, and to the URL strings.
        if(!empty( $customParams )){
                foreach ($customParams as $paramKey => $paramValue) {
                        $stringToSign .= $appendCharacter . $paramKey . '=' . $paramValue;
                        $url .= $appendCharacter . $paramKey . '=' . str_replace(array('%2F', '%2B'), array('/', '+'), rawurlencode( ltrim($paramValue, '/') ) );
                        $appendCharacter = '&';
        # Hash the string-to-sign to create the signature.
        $signature = el_crypto_hmacSHA1($secretKey, $stringToSign);
        # Append generated AWS parameters to the URL.
        $queries = http_build_query($pieces = array(
            'AWSAccessKeyId' => $awsAccessKey,
            'Expires' => $expires,
            'Signature' => $signature,
        $url .= $appendCharacter .$queries;
        # Return the URL.
        return $url;


As you can see this a very simple PHP script which creates time expiring URL’s for Amazon S3. Basically there are only a handful of settings and are as follows:

  1. Set your public and secret keys in key.php
  2. Set your bucket name in s3-expiring-url.php @ line 8. The file delivering from bucket should not need any special permissions.
  3. Set your link expire time in s3-expiring-url.php @ line 51. To test, set line 51 to a value of 1.
  4. Set your filename from specified bucket in download.php (a href area).
  5. Upload files, navigate to download.php and test the link. Wait for time to expire and click link again. Should get expire message from Amazon.

If you wish to fork this from GitHub, go here.

You can either download the ZIP containing the above files from link above or directly here.

We hope you enjoyed this tutorial and thank you for visiting our site! Be sure to signup to our newsletter for more freebies.

The QikSoft Team

QikSoft Team

View posts by QikSoft Team
We are a small team of young people learning to program and have fun doing it!
Scroll to top