jQuery HTML5 Drag-and-Drop File Upload

March 8th, 2012 Leave a comment 3 comments
Like the article?
jQuery HTML5 Drag-and-Drop File Uploads

Often we have a situation on our site where we want users to be able to upload a file. Whether this is for a profile, pictures of any item or other scenario, creating a file upload doesn’t have to be tricky. With some of the nice tricks in HTML5 and jQuery we can even add the nice touch of being able to drag and drop files directly into the uploader, making your site feel extra-special. In this tutorial we will discuss the techniques of both of these techniques that make this trick possible as well as create a drag and drop image uploader of our own.

HTML5 File Upload Process

There are some new, built-in features of HTML5 that make uploading files really easy. The File Reader and Drag and Drop APIs will be a necessary part of our process. The Drag and Drop API (links at bottom), will allow us to fire an event when the user drags a file onto the browser window. This is what will contain the information about the files the user dropped. The File Reader API will allow us to read in the files as binary data and store them in memory while we decide what to do with them.

An AJAX component will be necessary to send the files in memory to the server. A standard XMLHttpRequest object can be used to accomplish this.

The jQuery Components

jQuery has an excellent add-in called FileDrop that allows users to drag and drop multiple files onto the browser window from their computer. This addon uses the HTML5 File Reader API to accomplish this task. You will need both the FileDrop add-on and the standard jQuery library before we can get started.

Downsides to This Process

Currently, the File Upload API is only usable in Firefox and Chrome so you would need to provide upload functionality for users of other browsers. Bummer.

Creating the Upload Page

The HTML page is very simple. The best place to start is with a standard HTML5 document. Make sure you have the jQuery library and the FileDrop add-in. Here is what the HTML looks like:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>HTML5 and jQuery Uploader</title>

        <style type="text/css">
        .box {
            background-color: gray;
            color: white;
            border: 5px solid black;
            position: absolute;
            width: 150px;
            height: 150px;
        }
        </style>
    </head>

    <body>
	<header>
		<h1>HTML5 and jQuery Uploader</h1>
	</header>

	<div id="dropbox">
		<span class="box">Drop images here to upload. </span>
	</div>

	<!-- Including The jQuery Library -->
	<script src="jquery-1.7.1.min.js"></script>

	<!-- Including the HTML5 Uploader plugin -->
	<script src="assets/js/jquery.filedrop.js"></script>

	<!-- Our jQuery Script for File Processing -->
	<script src="script.js"></script>
    </body>
</html>

The only div necessary for this example is “dropbox” since it is the only one that the FileDrop add-on will interact with. We will pass this div to the add-on so it can detect when a file has been dropped on it for processing.

The jQuery add-on will handle the file preview that takes place when a file is dropped in the div. Since we are only looking to work with images in this example, the script is set up to receive the image.

There are two functions in the script file that work this process. Here is the first function:

var template = '<div class="preview">'+
	'<span class="imageHolder">'+
	'<img />'+
	'<span class="uploaded"></span>'+
	'</span>'+
	'<div class="imgHolder">'+
	'<div class="img"></div>'+
	'</div>'+
	'</div>';
	
function createImage(file) {
	var preview = $(template), 
		image = $('img', preview);
		
	var reader = new FileReader();
	
	//change these settings to customize the preview
	//size of the picture
	image.width = 100;
	image.height = 100;

	reader.onload = function(e) {		
		// e.target.result holds the DataURL which
		// can be used as a source of the image:
		image.attr('src', e.target.result);
	};
	
	// Reading the file as a DataURL. When finished,
	// this will trigger the onload function above:
	reader.readAsDataURL(file);		
	message.hide();

	//add the preview file to the div
	preview.appendTo(dropbox);

	// Associating a preview container
	// with the file, using jQuery's $.data():
	
	$.data(file, preview);
}

function showMessage(msg) {
	message.html(msg);
}

In this function we are creating the HTML5 markup for the preview of the file. The DataURL of the image is received as a base64 encoded string that contains a representation of the image bytes. This becomes the source of the image. This information is then appended to the dropbox div.

In the next function we call the fileDrop add-in:

var dropbox = $('#dropbox');
var message = $('.message', dropbox);

dropbox.filedrop({
	// The name of the $_FILES entry:
	paramname: 'pic',

	url: 'img_file.php', //this is the PHP file used for processing

	uploadFinished: function(i, file, response) {
		$.data(file).addClass('done');
		// response is the JSON object that img_file.php returns
	},
	
	// Called before each upload is started
	beforeEach: function(file) {
		if (!file.type.match(/^image\//)) {
			alert('Only images are allowed!');
			
			// Returning false will cause the
			// file to be rejected
			return false;
		}
	},
	
	uploadStarted: function(i, file, len) {
		createImage(file);
	}
});

In this function we are listening for the file drop, testing that it is a valid image file and then calling the PHP script to process the file. We’ll look at the PHP script in the next section:

// Set the directory where files will be saved
$upload_dir = 'uploads/';
$allowed_ext = array('jpg', 'jpeg', 'png', 'gif');

if (strtolower($_SERVER['REQUEST_METHOD']) != 'post') {
	exit_status('Error! Wrong HTTP method!');
}

if (array_key_exists('pic', $_FILES) && 
		$_FILES['pic']['error'] == 0 ) {
	$pic = $_FILES['pic'];

	if (!in_array(get_extension($pic['name']), $allowed_ext)) {
		exit_status('Only ' . 
			implode(',', $allowed_ext) . ' files are allowed!');
	}

	// Move the uploaded file from the temporary 
	// directory to the uploads folder:	
	if (move_uploaded_file($pic['tmp_name'], $upload_dir.$pic['name'])) {
		exit_status('File was uploaded successfully!');
	}
	
}

exit_status('Something went wrong with your upload!');

// Helper functions
function exit_status($str) {
	echo json_encode(array('status' => $str));
	exit;
}

function get_extension($file_name) {
	$ext = explode('.', $file_name);
	$ext = array_pop($ext);
	return strtolower($ext);
}

In the PHP file we setup the folder where the images will be uploaded, in this case, “upload” is our folder. You can set the upload_dir variable to your own value or a dynamic value if you are letting users upload to their own folder. This script runs some standard checks against the HTTP method to ensure the file extension is valid. You can also modify the allowed_ext to select or remove additional file extensions. If you have seen a standard PHP file upload script, this isn’t any different just because we are using the drag and drop method. The bonus to this, is that if you need to implement a different interface for browsers that don’t support the HTML5 method, you don’t need a different back-end solution as well.

Of course you would want to use a style sheet to make this a little nicer looking and have it fit with your site. If you download the demo it is pretty sparse, since I only wanted to show the process. You can also use this as a starting point for adding the drag and drop, HTML5 file upload to your own pages. Looking for a more comprehensive PHP and jQuery training? Check out our PHP, JavaScript, AJAX, and jQuery training course.

Links:

Article Source Files

DescriptionNameSizeDownload method
jQuery HTML5 Drag-and-Drop File Upload Source Codejquery-html5-uploader-demo.zip38KBHTTP
Help us spread the word!
  • Twitter
  • Facebook
  • LinkedIn
  • Pinterest
  • Delicious
  • DZone
  • Reddit
  • Sphinn
  • StumbleUpon
  • Google Plus
  • RSS
  • Email
  • Print
Don't miss another post! Receive updates via email!

3 comments

  1. Hello

    Do you have any suggestion for adding a “Upload” button to this so users that have problems with drag/drop to select files with an open dialog?

    Thanks

    • Michael Dorf says:

      Cristian, the PHP processing script would work with either upload method. All you need to do is add an “Upload” form field to your form. It should be trivial to do.

  2. Marjan says:

    Just to say thanks!

Comment