Skip to content

Instantly share code, notes, and snippets.

@carsonmcdonald
Created September 2, 2012 01:59
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save carsonmcdonald/3593744 to your computer and use it in GitHub Desktop.
Save carsonmcdonald/3593744 to your computer and use it in GitHub Desktop.
Use S3 CORS FileAPI uploader
function createCORSRequest(method, url)
{
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr)
{
xhr.open(method, url, true);
}
else if (typeof XDomainRequest != "undefined")
{
xhr = new XDomainRequest();
xhr.open(method, url);
}
else
{
xhr = null;
}
return xhr;
}
function handleFileSelect(evt)
{
setProgress(0, 'Upload started.');
var files = evt.target.files;
var output = [];
for (var i = 0, f; f = files[i]; i++)
{
uploadFile(f);
}
}
/**
* Execute the given callback with the signed response.
*/
function executeOnSignedUrl(file, callback)
{
var xhr = new XMLHttpRequest();
xhr.open('GET', 'signput.php?name=' + file.name + '&type=' + file.type, true);
// Hack to pass bytes through unprocessed.
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e)
{
if (this.readyState == 4 && this.status == 200)
{
callback(decodeURIComponent(this.responseText));
}
else if(this.readyState == 4 && this.status != 200)
{
setProgress(0, 'Could not contact signing script. Status = ' + this.status);
}
};
xhr.send();
}
function uploadFile(file)
{
executeOnSignedUrl(file, function(signedURL)
{
uploadToS3(file, signedURL);
});
}
/**
* Use a CORS call to upload the given file to S3. Assumes the url
* parameter has been signed and is accessible for upload.
*/
function uploadToS3(file, url)
{
var xhr = createCORSRequest('PUT', url);
if (!xhr)
{
setProgress(0, 'CORS not supported');
}
else
{
xhr.onload = function()
{
if(xhr.status == 200)
{
setProgress(100, 'Upload completed.');
}
else
{
setProgress(0, 'Upload error: ' + xhr.status);
}
};
xhr.onerror = function()
{
setProgress(0, 'XHR error.');
};
xhr.upload.onprogress = function(e)
{
if (e.lengthComputable)
{
var percentLoaded = Math.round((e.loaded / e.total) * 100);
setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.');
}
};
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('x-amz-acl', 'public-read');
xhr.send(file);
}
}
function setProgress(percent, statusLabel)
{
var progress = document.querySelector('.percent');
progress.style.width = percent + '%';
progress.textContent = percent + '%';
document.getElementById('progress_bar').className = 'loading';
document.getElementById('status').innerText = statusLabel;
}
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
<AllowedHeader>origin</AllowedHeader>
</CORSRule>
</CORSConfiguration>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css" />
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<table>
<tr>
<td>File selection:</td>
<td><input type="file" id="files" name="files[]" multiple /></td>
</tr>
<tr>
<td>Progress:</td>
<td><div id="progress_bar"><div class="percent">0%</div></div></td>
</tr>
<tr>
<td>Status:</td>
<td><span id="status"></span></td>
</tr>
</table>
<script type="text/javascript">
document.getElementById('files').addEventListener('change', handleFileSelect, false);
setProgress(0, 'Waiting for upload.');
</script>
</body>
</html>
<?php
//
// Change the following settings
//
$S3_KEY='S3 Key Here';
$S3_SECRET='S3 Secret Here';
$S3_BUCKET='/uploadtestbucket';
$EXPIRE_TIME=(60 * 5); // 5 minutes
$S3_URL='http://s3.amazonaws.com';
$objectName='/' . $_GET['name'];
$mimeType=$_GET['type'];
$expires = time() + $EXPIRE_TIME;
$amzHeaders= "x-amz-acl:public-read";
$stringToSign = "PUT\n\n$mimeType\n$expires\n$amzHeaders\n$S3_BUCKET$objectName";
$sig = urlencode(base64_encode(hash_hmac('sha1', $stringToSign, $S3_SECRET, true)));
$url = urlencode("$S3_URL$S3_BUCKET$objectName?AWSAccessKeyId=$S3_KEY&Expires=$expires&Signature=$sig");
echo $url;
?>
#progress_bar {
width: 200px;
margin: 10px 0;
padding: 3px;
border: 1px solid #000;
font-size: 14px;
clear: both;
opacity: 0;
-moz-transition: opacity 1s linear;
-o-transition: opacity 1s linear;
-webkit-transition: opacity 1s linear;
}
#progress_bar.loading {
opacity: 1.0;
}
#progress_bar .percent {
background-color: #99ccff;
height: auto;
width: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment