Asynchronous POST Upload to AWS S3 using PHP

I came across this functionality while helping one of my friends trying to upload a video file from his browser.  I found some pointer from AWS website, however, it took some time for me as I encountered some new concepts like base64 encoding, adding policy and signature in HTTP header etc.

This was the first link I found on AWS:

https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html

It’s a long story after that. But before I start I must also thanks AWS support engineers for helping me understand the  concept. I would document my experience and learning so that at least I can refer the same in future. I hope  this will be helpful for the community too.

Here are the step you may follow to post a file asynchronously to AWS S3:

1) Sign-up for AWS Account

As usual this will be the first prerequisite to use any service. If you do not have an AWS account, you can sign-up for a new account by going to https://aws.amazon.com and following up the sign-up instruction on the page.

2) Create a configuration file

I created a file named config.php to keep AWS identifier. This is the content of the file:


// Enter your Access Key ID
$AWSAccessKeyId = 'AWS ACCESS KWY';

// Enter your Secret Access Key
$AWSSecretKey = 'AWS ACCESS SECRET KEY';

// Enter the name of the bucket you want to use for the samples
$bucket = 'S3 BUCKET NAME';

3) Write a script to sign your S3 Post form 

I used a sample php file from AWS. The file name is PostPolicy.php. You can find this file at following location:

https://aws.amazon.com/code/JavaScript/1618

This is a very different sample. I used only PostPolicy.php file from sample calculate base64 encoded policy and signature.

4) Write a POST Form Webpage

I used another AWS sample for my test. You may find this sample at – https://aws.amazon.com/articles/1434.

Here is the sample HTML source in my example:


<?php

require 'config.php';
require 'PostPolicy.php';

$success_action_redirect = 'callback.php';
$seq = time(); //temp only. replace with user + DB sequence
// Create a new POST policy document
$s3policy = new Aws_S3_PostPolicy($AWSAccessKeyId, $AWSSecretKey, $bucket, 86400);
$s3policy->addCondition('', 'acl', 'public-read')
          ->addCondition('', 'bucket', $bucket)
          ->addCondition('starts-with', '$key', '')
          ->addCondition('starts-with', '$Content-Type', '')
          ->addCondition('', 'success_action_redirect', $success_action_redirect);
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Language" content="en-us" />
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title> Test File Uploads to Amazon S3</title>
</head>
<body>
  <form action="<?php echo 'https://' . $bucket . '.s3.amazonaws.com/'; ?>" enctype="multipart/form-data" method="post">
  <p>
    <input type="hidden" name="AWSAccessKeyId" id="AWSAccessKeyId" value="<?php echo $s3policy->getAwsAccessKeyId(); ?>" />
    <input type="hidden" name="acl" id="acl" value="<?php echo $s3policy->getCondition('acl'); ?>" />
    <input type="hidden" name="key" id="key" value=<?php echo $seq.'.mp4' ?> />
    <input type="hidden" name="policy" value="<?php echo $s3policy->getPolicy(true); ?>" />
    <input type="hidden" name="Content-Type" id="contentType" value="" />
    <input type="hidden" name="signature" id="signature" value="<?php echo $s3policy->getSignedPolicy(); ?>" />
    <input type="hidden" name="success_action_redirect" value=  "<?php echo $s3policy->getCondition('success_action_redirect'); ?>" />
                     File: <input type="file" name="file" id="file" />
    <input type="submit" id="submit" value="Submit"/>
  </p>
  </form>
</body>
</html>

That’s it, you are all set. Open your html file in client browser. It can calculate the policy and signature, and use the same to sign the HTML S3 form, and can directly upload the file to the AWS S3 bucket.

Please do not hesitate to contact me  if you need any help. I’ll be happy to share the code. Just drop me a note.