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:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | <!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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?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.