Validate file upload with html5 file api

The html5 file api provides lots of new features which can be used to read files on clientside from within the browser.

Lets take a look at this Demo first :

This file upload control will only take zip or png files which are less than 1MB in size. For any other files it will show an error message.

And this functionality if purely clientside. No server interaction or uploads yet.

Code

Html

<input type="file" data-file_type="zip|png" data-max_size="1000000">

As we can see above , the validation parameters are stored inside the input tag itself using custom data tags. So allowed file types are zip and png , and allowed maximum size is 1000000 bytes , that is nearly 1 MB.

Javascript

Data attributes are used to specify the allowed file types and the maximum size of the upload file. The extensions are used to map to a list of mime types (later in this article).

$('input[type=file]').each(function()
{
	if(typeof $(this).attr('data-file_type') == 'string')
	{
		var file_types = $(this).attr('data-file_type').split('|');
	}
	
	var mimes = get_mimes(file_types);
	var max_size = parseInt($(this).attr('data-max_size'));
	
	$(this).change(function(evt)
	{
		var finput = $(this);
		
		var files = evt.target.files; // FileList object

		// files is a FileList of File objects. List some properties.
		var output = [];
		
		for (var i = 0, f; f = files[i]; i++) 
		{
			//Check mime type
			if(jQuery.inArray(f.type , mimes) == -1)
			{
				alert('File type '+ f.type + ' not allowed');
				$(this).val('');
				continue;
			}
			
			//Check size
			else if(f.size > max_size)
			{
				alert('Maximum file size is ' + max_size + ' bytes.');
				$(this).val('');
			}
			
			//Validation ok
			else
			{
				output.push('<strong>', f.name, '</strong> (', f.type || 'n/a', ') - ', f.size, ' bytes, last modified: ', f.lastModifiedDate.toLocaleDateString() );
			}
		}
		
		finput.after('<div>' + output.join('') + '</div>');
	});
});

The above code uses jquery.

In html5 capable browsers when a file is selected for upload in a file input , then the input element has a Filelist object in its files attribute which is an object of type FileList (which is a Collection of File objects).







Information about each file can be retrieved like this :

var files = evt.target.files; // FileList object
var file_count = files.length;

var file_1 = files[0]; // or files.item(0);

var name = file_1.name;
var size = file_1.size; 
var type = file_1.type;
var lastModifiedDate = file_1.lastModifiedDate;

The things to check are file type and file size. That is all that can be checked.
The type variable contains the mime type of the file. So we have an existing list of mime types useful for the purpose.

List of mimes

var mime_types = {
"hqx":"application/mac-binhex40",
"cpt":"application/mac-compactpro",
"csv":["text/x-comma-separated-values","text/comma-separated-values","application/octet-stream","text/csv","application/csv"],
"bin":"application/macbinary",
"dms":"application/octet-stream",
"lha":"application/octet-stream",
"lzh":"application/octet-stream",
"exe":"application/octet-stream",
"class":"application/octet-stream",
"psd":"application/x-photoshop",
"so":"application/octet-stream",
"sea":"application/octet-stream",
"dll":"application/octet-stream",
"oda":"application/oda",
"pdf":["application/pdf","application/x-download"],
"ai":"application/postscript",
"eps":"application/postscript",
"ps":"application/postscript",
"smi":"application/smil",
"smil":"application/smil",
"mif":"application/vnd.mif",
"xls":["application/excel","application/vnd.ms-excel","application/msexcel"],
"ppt":["application/powerpoint","application/vnd.ms-powerpoint"],
"wbxml":"application/wbxml",
"wmlc":"application/wmlc",
"dcr":"application/x-director",
"dir":"application/x-director",
"dxr":"application/x-director",
"dvi":"application/x-dvi",
"gtar":"application/x-gtar",
"gz":"application/x-gzip",
"php":"application/x-httpd-php",
"php4":"application/x-httpd-php",
"php3":"application/x-httpd-php",
"phtml":"application/x-httpd-php",
"phps":"application/x-httpd-php-source",
"js":"application/x-javascript",
"swf":"application/x-shockwave-flash",
"sit":"application/x-stuffit",
"tar":"application/x-tar",
"tgz":"application/x-tar",
"xhtml":"application/xhtml+xml",
"xht":"application/xhtml+xml",
"zip":["application/x-zip","application/zip","application/x-zip-compressed"],
"mid":"audio/midi",
"midi":"audio/midi",
"mpga":"audio/mpeg",
"mp2":"audio/mpeg",
"mp3":["audio/mpeg",
"audio/mpg"],
"aif":"audio/x-aiff",
"aiff":"audio/x-aiff",
"aifc":"audio/x-aiff",
"ram":"audio/x-pn-realaudio",
"rm":"audio/x-pn-realaudio",
"rpm":"audio/x-pn-realaudio-plugin",
"ra":"audio/x-realaudio",
"rv":"video/vnd.rn-realvideo",
"wav":"audio/x-wav",
"bmp":"image/bmp",
"gif":"image/gif",
"jpeg":["image/jpeg","image/pjpeg"],
"jpg":["image/jpeg","image/pjpeg"],
"jpe":["image/jpeg","image/pjpeg"],
"png":["image/png","image/x-png"],
"tiff":"image/tiff",
"tif":"image/tiff",
"css":"text/css",
"html":"text/html",
"htm":"text/html",
"shtml":"text/html",
"txt":"text/plain",
"text":"text/plain",
"log":["text/plain","text/x-log"],
"rtx":"text/richtext",
"rtf":"text/rtf",
"xml":"text/xml",
"xsl":"text/xml",
"mpeg":"video/mpeg",
"mpg":"video/mpeg",
"mpe":"video/mpeg",
"qt":"video/quicktime",
"mov":"video/quicktime",
"avi":"video/x-msvideo",
"movie":"video/x-sgi-movie",
"doc":"application/msword",
"docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"word":["application/msword","application/octet-stream"],"xl":"application/excel","eml":"message/rfc822"
};

The above list of mime types can give the mime type of a give extension like zip or png. Next we have a function that provides the list of allowed mimes as an array :

/*
	Get the mimes of a list of extensions as an array
*/
function get_mimes(extensions)
{
	var mimes = [];
	for(var i in extensions)
	{
		var ext = extensions[i];
		
		if(ext in mime_types)
		{
			var mime = mime_types[ext];
			
			if($.isArray(mime))
			{
				jQuery.merge(mimes , mime);
			}
			else
			{
				mimes.push(mime);
			}
		}
	}
	
	return mimes;
}

This method can be used like this get_mimes(['zip' , 'png']) and it will return an array of mimes for the given extensions. This return values is used in the validation part to simply check if the mime of the selected file is there in this list or not. If not , then show error.

References :

The documentation of the file api lies here : http://www.w3.org/TR/file-upload/.

Details of browser support are available here : http://caniuse.com/#search=file api

Last Updated On : 30th June 2013

Subscribe to get updates delivered to your inbox

Leave a comment