If you’re reading this page (or my blog in general) it’s a pretty safe bet you already have Google+. If you’ve uploaded any photos to Google+ from Chrome or FF, you would also have noticed its snazzy HTML5 file uploader at work. This weekend I took it upon myself to whip up a quick and dirty version of that uploader and share its inner workings with the world.
Here’s a short video of my uploader at work:
https://www.youtube.com/watch?v=AXx8cu6rxV4
Requirements:
Disclaimer: Currently only Firefox and Webkit based browsers meet the requirements above. Opera supports the File API and probably XHR2 (I haven’t tested), however it doesn’t have drag and drop so this tutorial won’t work with it. If you’re curious about whether or not IE will work with this tutorial, I’m already laughing at you.
Download the finished script here.
The comments pretty much make this tutorial self explanatory so I’ll let the code below speak for itself. You’ll need an index.php, upload.php and uploads folder writable to by apache.
index.php:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style>
html, body {height:100%;margin:0px;padding:0px}
#message_upload {font-size:26px;color:lightgrey;margin:15px}
.box {float:left;width:150px;height:120px;background:lightgrey;margin:8px;text-align:center}
.box .name {height:25px;margin-top:5px}
.box .progresscontainer {height:5px;margin:80px 5px 0px}
.box .progress {background:grey;height:5px;width:1%}
.box.picture {background:none center top no-repeat;background-size:100%}
.box.picture .progresscontainer, .box.picture .name {display:none}
</style>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.6.2.min.js'></script>
<script type='text/javascript'>
var tpl_box =
"<div class='box'>
<div class='name'></div>
<div class='progresscontainer'><div class='progress'></div></div>
</div>";
$(document).ready(function() {
// Check for the various File API support.
if ( !window.File || !window.FileReader || !window.FileList || !window.Blob )
alert('The File APIs are not fully supported in this browser. Please upgrade your browser.');
//Listen for file drag and drop
document.body.addEventListener('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
}, false);
document.body.addEventListener('drop', function(e) {
e.stopPropagation();
e.preventDefault();
upload_files( e.dataTransfer.files );
}, false);
});
/*
* Upload a given FileList
*/
function upload_files( files )
{
$('#message_upload').hide();
//Loop through dropped files, uploading only images and ignoring all others
for (var i = 0, f; f = files[i]; i )
if ( f.type=='image/jpeg' || f.type=='image/png' || f.type=='image/gif' )
upload_file( f );
else
alert( f.name ' is not a valid image file.' );
}
/*
* Upload a given File
*/
function upload_file( f )
{
//Truncate long filenames
var name = f.name;
if ( name.length > 15 ) name = name.substr(0, 15) '...';
//Create our new upload box to display
var $box = $(tpl_box).find('.name').html( name ).end();
//Do the actual uploading
var XHR = new XMLHttpRequest();
XHR.open('PUT', 'upload.php', true);
//Send the file details along with the request
for (var key in f)
{
var val = f[key];
//This line is required for Firefox compatability
if ( typeof(val) == 'string' || typeof(val) == 'number' )
XHR.setRequestHeader('file_' key, val);
}
//Update our box's progress bar as the file uploads
XHR.upload.addEventListener("progress", function(e) {
if ( !e.lengthComputable) return;
var percentComplete = parseInt(e.loaded / e.total * 100);
$box.find('.progress').css('width', percentComplete '%');
}, false);
//Display the uploaded pictures thumbnail once upload is complete
XHR.onreadystatechange = function() {
// in case of network errors this might not give reliable results
if ( this.readyState == this.DONE )
$box.addClass('picture').css('background-image', 'url(' escape(this.responseText) ')');
}
XHR.send( f );
//Display the upload box
$('body').append( $box );
}
</script>
</head>
<body>
<div id='message_upload'>Drag images here to upload</div>
</body>
</html>
upload.php
<?php
//http://php.net/manual/en/features.file-upload.put-method.php
//http://stackoverflow.com/questions/541430/how-do-i-read-any-request-header-in-php
$headers = apache_request_headers();
//Webkit uses file_fileName, FF uses file_name
$name_header = isset($headers['file_fileName']) ? $headers['file_fileName'] : $headers['file_name'];
$upload_url = 'uploads/'.$name_header;
/* PUT data comes in on the stdin stream */
$putdata = fopen("php://input", "r");
/* Open a file for writing */
$fp = fopen(dirname(__FILE__).'/'.$upload_url, "w");
/* Read the data 1 KB at a time and write to the file */
while ($data = fread($putdata, 1024))
fwrite($fp, $data);
/* Close the streams */
fclose($fp);
fclose($putdata);
echo $upload_url;
Simply drag image files into your browser window and they’ll upload away as they do in Google+.
Have fun with it!
Download the finished script here.


