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:
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>
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
That generally indicates that your AWS keys aren’t set up correctly.
i set it up correctly i change something on the code:
CFCredentials::set(array(
‘loc’ => array(
‘key’ => $accesskey,
‘secret’ => $secretkey,
‘certificate_authority’ => false
),
‘@default’ => ‘loc’
));
it works, the problem now is when i try to upload, there is an error about the “policy” , refrerring to “success_action_redirect”
Sometimes you can also get certificate errors when your system clock is out of sync with amazon’s .
one more thing, the “footer.php” is that a required file or not?
Nope, strictly decorative.
is it too much to ask about a downloadable version of your code?
The formatted code on the page should be copy/paste capable in most browsers
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?
What do I need to do to copy into a folder of a bucket?
What changes in code needs to be done?
You change
to
another question is where does the value for ${filename} come from?
How do I do to check if the file already exists on s3. If yes, opt the user to overwrite?
Can you think of a way to limit the file size that’s selected?
Is there any chance of this being updated, with the release of Amazon PHP SDK 2?
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
What is AWSSDKforPHP/sdk.class.php file here. I downdlod the AWS S3 SDK But not finding this type of file.