Coldfusion - Amazon S3 upload via Form POST example

02/23/2010
0

Amazon S3 is a great way to store files that need to be exposed on the web. Every uploaded file can be accessible to the public or accessible to authorized users only via a clever system of expiring signatures.

Joe Danziger wrote an excellent CFC to do all kinds of operations via the S3 REST interface.

The only missing part is the new way Amazon is offering to upload files without the need to first buffer them on your own server.

The old way:

  • You send a user (let’s say a user of your CMS) to a page where he can upload a file
  • The user clicks on ‘Browse’ to find the file on his harddisk and submits the form.
  • The file is sent to your server.
  • You send the file to S3 via a REST put.
  • On success: you save a record in your database so you can remember what you sent to S3

The better way:

  • You send a user to a page where he can upload a file
  • The user clicks on ‘Browse’ to find the file on his harddisk and submits the form.
  • The file is sent directly to a certain bucket of your Amazon S3 storage
  • Amazon tells you about a successful upload and you update your database.


This is our example:

<cfparam name="URL.step" default="view">
<cfoutput>
  <cfif URL.step eq "view">
    <cfscript>
        // IMPORTANT: Set your key, accesskey and bucket here
        Variables.accessKeyId = "YOURACCESSKEY";
        Variables.secretAccessKey = "YoUrOmGvErYsEcReTAcCeSsKeYgOeShErE";
        Variables.BucketName='yourbucketname'; // Put your bucket name here
        // Map S3 to Joe Danziger's S3 REST Wrapper (http://amazons3.riaforge.org/)
        // Place the s3.cfc in the same directory as this file
        S3=createObject("component","S3"); // 
        Variables.RedirectURL='http://#CGI.HTTP_HOST##CGI.SCRIPT_NAME#?step=upload';
        Variables.Expiration=Dateformat(DateAdd("d", 7, "#now()#"), "yyyy-mm-dd")&'T00:00:00Z'; // Expiry Date
        Variables.Path='TestPath/'; // the will be put in from of every file uploaded with this form
        Variables.Auth='authenticated-read'; // secure the file - you can always change this later. Set it to 'public-read' for public access
        Variables.ContenType='';
        Variables.Filesize=250000000; // max allowed upload size in Bytes
        // Init
        S3.init('#Variables.accessKeyId#','#Variables.secretAccessKey#');
    </cfscript>
    <h1>S3 Form POST Upload</h1>
    <cfsavecontent variable="Variables.S3policy">                   
      {"expiration": "#Variables.Expiration#",
          "conditions": [ 
            {"bucket": "#Variables.BucketName#"}, 
            ["starts-with", "$key", "#Variables.Path#"],
            {"acl": "#Variables.Auth#"},
            {"success_action_redirect": "#Variables.RedirectURL#"},
            ["starts-with", "$Content-Type", "#Variables.ContenType#"],
            ["content-length-range", 0, #Variables.FileSize#]
          ]
      }
    </cfsavecontent>
    <cfset Variables.PolicyBase64 = ToBase64(Variables.S3policy)>   
    Select a file:
    <form name="s3upload" id="s3upload" action="https://#Variables.BucketName#.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
      <input type="hidden" name="key" value="#Variables.Path#${filename}">
      <input type="hidden" name="AWSAccessKeyId" value="#Variables.accessKeyId#"> 
      <input type="hidden" name="acl" value="#Variables.Auth#"> 
      <input type="hidden" name="success_action_redirect" value="#Variables.RedirectURL#">
      <input type="hidden" name="policy" value="#Variables.PolicyBase64#">
      <input type="hidden" name="signature" value="#S3.createSignature(Variables.PolicyBase64)#">
      <input type="hidden" name="Content-Type" value="video">
      <input name="file" id="file" type="file">&nbsp;<input type="submit" />
    </form>
  <cfelseif URL.step eq "upload">
    <h1>Response from Amazon S3</h1>
    Bucket: #URL.bucket#<br />
    ETag: #URL.etag#<br />
    Key: #URL.key#
  </cfif>
</cfoutput>

Save this code as tests3.cfm (or any other name you like) together with the s3.cfc from Joe Danzigers S3 REST Wrapper in a directory.

Set your accessKeyId, secretAccessKey and BucketName in the file and run it.

Feel free to use this example in your own projects. Enjoy :)

In case you want to read a little bit more about the specs check out this article: Browser Uploads to S3 using HTML POST Forms

UPDATE: Fixed a missing variable in the above code based or Marty McGee’s comment.

If you've read this far you might as well follow me on Twitter here.


Comments