PHP Direct Upload to S3

Here’s an easy way to upload directly to S3 from an HTML form. No Java, no Flash. Thanks to @RaamDev for his handy little bit of code for doing HMAC signatures. Based on the documentation from Amazon. Makes use of the AWS SDK for PHP to list the buckets.

Screen shots:

Bucket Selection

File Selection

File Selected

Upload Success

code:


<HTML>
<HEAD>
<TITLE>Upload a file to S3</TITLE>
<link href="style.css" rel="stylesheet" type="text/css" />
</HEAD>
<BODY>
<H1>S3 File Upload</H1>

<?php
error_reporting(0);
$accesskey='XXXXXXXXXXXXXXXX';
$secretkey='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

require_once 'AWSSDKforPHP/sdk.class.php';
if (!class_exists('CFRuntime')) die('No direct access allowed.');
CFCredentials::set(array(
        $name => array(
                'key' => $accesskey,
                'secret' => $secretkey,
                'certificate_authority' => false
        ),
        '@default' => $name
));

$s3 = new AmazonS3();

if(!isset($_GET['bucket'])) {
        echo "<P>Please select a bucket:</P>\n";
        $buckets=$s3->get_bucket_list();
        echo '<FORM ACTION="#">';
        foreach ($buckets as $b) { echo '<INPUT TYPE="radio" name="bucket" value="'.$b.'">'.$b."</INPUT><BR>\n"; }
        echo '<BR><INPUT TYPE="submit" VALUE="Use this bucket">'."\n";

        } else {
        $bucket = $_GET['bucket'];

        $policy='
{"expiration": "2012-01-31T00:00:00Z",
  "conditions": [
    {"bucket": "'.$bucket.'"},
    ["starts-with", "$key", ""],
    {"acl": "public-read"},
    {"success_action_redirect": "success.php"},
    ["starts-with", "$Content-Type", ""]
  ]
}';

/*
 * Calculate HMAC-SHA1 according to RFC2104
 * See http://www.faqs.org/rfcs/rfc2104.html
 */
function hmacsha1($key,$data) {
    $blocksize=64;
    $hashfunc='sha1';
    if (strlen($key)>$blocksize)
        $key=pack('H*', $hashfunc($key));
    $key=str_pad($key,$blocksize,chr(0x00));
    $ipad=str_repeat(chr(0x36),$blocksize);
    $opad=str_repeat(chr(0x5c),$blocksize);
    $hmac = pack(
                'H*',$hashfunc(
                    ($key^$opad).pack(
                        'H*',$hashfunc(
                            ($key^$ipad).$data

                        )
                    )
                )
            );
    return bin2hex($hmac);
}

/*
 * Used to encode a field for Amazon Auth
 * (taken from the Amazon S3 PHP example library)
 */
function hex2b64($str)
{
    $raw = '';
    for ($i=0; $i < strlen($str); $i+=2)
    {
        $raw .= chr(hexdec(substr($str, $i, 2)));
    }
    return base64_encode($raw);
}

/* Create the Amazon S3 Policy that needs to be signed */

/*
 * Base64 encode the Policy Document and then
 * create HMAC SHA-1 signature of the base64 encoded policy
 * using the secret key. Finally, encode it for Amazon Authentication.
 */
$base64_policy = base64_encode($policy);
$signature = hex2b64(hmacsha1($secretkey, $base64_policy));

?>
    <form action="https://<?=$bucket?>.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
      <input type="hidden" name="key" value="${filename}">
      <input type="hidden" name="AWSAccessKeyId" value="<?=$accesskey;?>">
      <input type="hidden" name="acl" value="public-read">
      <input type="hidden" name="success_action_redirect" value="http://your.server.here/success.php">
      <input type="hidden" name="policy" value="<?=$base64_policy?>">
      <input type="hidden" name="signature" value="<?=$signature?>">
      <input type="hidden" name="Content-Type" value="image/jpeg">
      <!-- Include any additional input fields here -->

      <input name="file" type="file">
      <br>
      <input type="submit" value="Upload File to S3 bucket <?=$bucket?>">
    </form>
        <P><A HREF=".">Use a different bucket</A></P>
<?php
}
?>
  </body>
</html>

success.php:

<HTML>
<HEAD>
<TITLE>Upload Success!</TITLE>
<link href="style.css" rel="stylesheet" type="text/css" />
</HEAD>
<BODY>
<H1>Upload Success!</H1>

<?php

echo "<P>Successfully uploaded ".$_GET['key']." to bucket ".$_GET['bucket'].".</P>\n";
$url = "https://".$_GET['bucket'].".s3.amazonaws.com/".$_GET['key'];
echo '<P>Direct URL to the file is <A HREF="'.$url.'">'.$url."</A></P>\n";

include '../footer.php';
?>
</BODY>
</HTML>

17 Comments On “PHP Direct Upload to S3”

  1. i have this error Uncaught exception ‘CFCredentials_Exception’ with message ‘If more than one credential set is provided, a default credential set (identified by the key “@default”) must be specified

    Reply

  2.  Enjoyed the post. Two questions for you. 1) In AWSSDKforPHP_sampleslib there is a progress_bar sample. Any idea how to incorporate it into the script? 2) Any guess as to how large a file the script will handle?

    Reply

  3. What do I need to do to copy into a folder of a bucket?
    What changes in code needs to be done?

    Reply

  4. another question is where does the value for ${filename} come from?

    Reply

  5. How do I do to check if the file already exists on s3. If yes, opt the user to overwrite?

    Reply

  6. Can you think of a way to limit the file size that’s selected?

    Reply

  7. Is there any chance of this being updated, with the release of Amazon PHP SDK 2?

    Reply

  8. i tried to use this code 

    i got this error..

    Fatal error: Uncaught exception ‘CFCredentials_Exception’ with message ‘No credentials were provided. The SDK attempts to retrieve Instance Profile credentials from the EC2 Instance Metadata Service, but doing this requires the “default_cache_config” option to be set in the config.inc.php file or constructor. In order to cache the retrieved credentials.’ in /var/www/s3upload/sdk/sdk.class.php on line 439

    Reply

  9. What is AWSSDKforPHP/sdk.class.php file here. I downdlod the AWS S3 SDK But not finding this type of file.

    Reply

Leave a Reply to Ian B Cancel reply

Your email address will not be published. Required fields are marked *