• Posted on March 1, 2013

HTML5 Uploading with Progress Bar

With new web technologies such as CSS3, HTML5 and JavaScript updates the new web possibilities are endless. One thing that a lot of sites incorporated now are the ability to drag and drop files to upload them. Below is how to create a simple AJAX file upload with progress bar.

First we have the HTML webpage, this can be nearly everything since we are using the body tag to capture the files.

<html>
<head>
	<title>Image Upload</title>
	<script src="image.js"></script>
	<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
	Drag Files Anywhere Here
	<div id="process"></div>
</body>
</html>

Now we will make a simple stylesheet to give just a little color to the design and to create the progress bar for the image upload.

.progressbar {
	border: 1px solid black;
	height: 5px;
	width: 500px;
	margin-top: 7px;
	float: right;
}
.progressbar div {
	height: 5px;
	width: 0px;
	background-color: #0000ff;
}

We have to create the JavaScript to handle the dropped files, send the files to the server, show progress and more.

/*
	Wait for window to finish loading, then set event listeners for the body to procress the events
*/
window.onload = function() {
	var files = null;
	window.addEventListener('drop',dropEvent,false);
	window.addEventListener('drageneter',preventEvent,false);
	window.addEventListener('dragleave',preventEvent,false);
	window.addEventListener('dragover',preventEvent,false);
}
/*
	Stop Browser from Navigating to File / Default Handeling
*/
function preventEvent(e) {
	e.stopPropagation();
	e.preventDefault();
	return false;
}

/*
	When a file is dropped into the browser, the "drop" event listener points to this function.
*/
function dropEvent(e) {
	preventEvent(e);
	// Save all dropped files to global variable "files"
	files = e.dataTransfer.files;
	// Check if files were really dropped or not
	if(files.length > 0) {
		// Build an output display to show progress
		var output = '';
		var bg = null;
		for(var i = 0; i < files.length; i++) {
			if(bg == 'background-color:#ffffff;')
				bg = 'background-color:#bbbbbb;'
			else
				bg = 'background-color:#ffffff;';

			output += '<div style="height:20px;' + bg + '"><div style="float:left"><strong>' + escape(files[i].name) + '</strong></div><div class="progressbar"><div id="progress-child-' + i + '"></div></div><div style="clear:both"></div></div>';
		}
		document.getElementById('process').innerHTML = output;
		// Call function to upload files, starting at File[0]
		setTimeout(function(){uploadFiles(0);},100);
	}
	return false;
}

function uploadFiles(i) {
	var req = new XMLHttpRequest();
	var formdata = new FormData();
	req.upload.onprogress = function(e) {
	document.getElementById('progress-child-' + i).style.width = (e.position * 100 / e.totalSize) + '%';
}
req.onreadystatechange = function() {
	if(req.readyState == 4) {
		// Set Progress to 100% when finished
		document.getElementById('progress-child-' + i).style.width = '100%';
		if(req.status != 200) {
			// Turn Progress Red if Error
			document.getElementById('progress-child-' + i).style.backgroundColor = "#ff0000";
		}
		++i;
		// If more files, upload the next one
		if(i < files.length) {
			uploadFiles(i);
		}else{
			// After all uploads, refresh page
			//window.location.href=window.location.href;
		}
	}
}
// Create form data for the image so the PHP file can progress it
formdata.append("image", files[i]);
req.open("POST","upload.php",true);
req.send(formdata);
}

Last of all we need to create the server code to handle the file uploads. Since this code depends a lot on what you are uploading we are just going to do a very simple image upload that may not have the best security settings and functions in place.

<?php
	$success = false;
	$error = false;
	// Check if uploaded file and not a system file or other file
	if(isset($_FILES['image']) && is_uploaded_file($_FILES['image']['tmp_name']) && $_FILES['image']['error'] == 0) {
		if(!is_dir('uploads')) {
			mkdir('uploads');
		}
		// Sets the filename to a unique ID
		$filename = 'uploads/'.uniqid().'.jpg';
		// Check the image type and create image from GD using that type
		switch(exif_imagetype($_FILES['image']['tmp_name'])) {
			case 1:
				$img = imagecreatefromgif($_FILES['image']['tmp_name']);
				break;
			case 2:
				$img = imagecreatefromjpeg($_FILES['image']['tmp_name']);
				break;
			case 3:
			$img = imagecreatefrompng($_FILES['image']['tmp_name']);
				break;
			default:
				$error = true;
				break;
		}
		if($error == false) {
			// Convert image to jpeg and save to new location
			$success = imagejpeg($img, $filename, 100);
			imagedestroy($img);
			if($success) {
				// Successful Image name is $filename
			}
		}
	}
	if($success == false) {
		// Not Successful - should return error
		header("HTTP/1.1 500 Internal Server Error");
	}