Multiple File Upload With Progress Bar Using jQuery

Posted in jQuery

The default browser file input boxes do not allow multiple file selection for uploading at once and also do not provide any visual clue as to how much of the files selected have uploaded. Earlier I wrote about multiple file upload using AJAX, but that did not provide multiple file selection and a progress bar.

Today I am going to show you how to create a multiple file upload form that allows multiple file selection using Ctrl/Shift keys and also displays a progress bar for each of the selected files while they are uploading.

Multiple File Upload With Progress Bar

For this tutorial, you will need the all powerful jQuery library(latest version) and SWFUpload jQuery Plugin.

Folder Structure

Place the jQuery library in js folder, extract the SWFUpload jQuery Plugin somewhere and copy the jquery.swfupload.js in the src folder to the js folder. Also, copy the swfupload folder inside vendor folder of SWFUpload jQuery Plugin to js Folder. Here’s what your folder structure should look like.

Folder Structure

Add reference to jQuery library and then jquery.swfupload.js in the head tag of your page.

HTML Structure

Since we will be using SWFUpload, we’ll need a container that will act as placeholder for SWFUpload button, and a list to show the queue of files.

<div id="swfupload-control">
	<p>Upload upto 5 image files(jpg, png, gif), each having maximum size of 1MB(Use Ctrl/Shift to select multiple files)</p>
	<input type="button" id="button" />
	<p id="queuestatus" ></p>
	<ol id="log"></ol>
</div>

CSS Styles

Here are some CSS styles to stylize our File Uploader, modify them as you want. Important ones are .progressbar and .progress that define the progress bar for file upload, you can adjust their height and color.

#swfupload-control p{ margin:10px 5px; font-size:0.9em; }
#log{ margin:0; padding:0; width:500px;}
#log li{ list-style-position:inside; margin:2px; border:1px solid #ccc; padding:10px; font-size:12px; 
	font-family:Arial, Helvetica, sans-serif; color:#333; background:#fff; position:relative;}
#log li .progressbar{ border:1px solid #333; height:5px; background:#fff; }
#log li .progress{ background:#999; width:0%; height:5px; }
#log li p{ margin:0; line-height:18px; }
#log li.success{ border:1px solid #339933; background:#ccf9b9; }
#log li span.cancel{ position:absolute; top:5px; right:5px; width:20px; height:20px; 
	background:url('js/swfupload/cancel.png') no-repeat; cursor:pointer; }

The JavaScript Code

The JavaScript code is a bit bulkier but it is not that difficult to understand as it looks.

$(function(){
	$('#swfupload-control').swfupload({
		upload_url: "upload-file.php",
		file_post_name: 'uploadfile',
		file_size_limit : "1024",
		file_types : "*.jpg;*.png;*.gif",
		file_types_description : "Image files",
		file_upload_limit : 5,
		flash_url : "js/swfupload/swfupload.swf",
		button_image_url : 'js/swfupload/wdp_buttons_upload_114x29.png',
		button_width : 114,
		button_height : 29,
		button_placeholder : $('#button')[0],
		debug: false
	})
		.bind('fileQueued', function(event, file){
			var listitem='<li id="'+file.id+'" >'+
				'File: <em>'+file.name+'</em> ('+Math.round(file.size/1024)+' KB) <span class="progressvalue" ></span>'+
				'<div class="progressbar" ><div class="progress" ></div></div>'+
				'<p class="status" >Pending</p>'+
				'<span class="cancel" >&nbsp;</span>'+
				'</li>';
			$('#log').append(listitem);
			$('li#'+file.id+' .cancel').bind('click', function(){ //Remove from queue on cancel click
				var swfu = $.swfupload.getInstance('#swfupload-control');
				swfu.cancelUpload(file.id);
				$('li#'+file.id).slideUp('fast');
			});
			// start the upload since it's queued
			$(this).swfupload('startUpload');
		})
		.bind('fileQueueError', function(event, file, errorCode, message){
			alert('Size of the file '+file.name+' is greater than limit');
		})
		.bind('fileDialogComplete', function(event, numFilesSelected, numFilesQueued){
			$('#queuestatus').text('Files Selected: '+numFilesSelected+' / Queued Files: '+numFilesQueued);
		})
		.bind('uploadStart', function(event, file){
			$('#log li#'+file.id).find('p.status').text('Uploading...');
			$('#log li#'+file.id).find('span.progressvalue').text('0%');
			$('#log li#'+file.id).find('span.cancel').hide();
		})
		.bind('uploadProgress', function(event, file, bytesLoaded){
			//Show Progress
			var percentage=Math.round((bytesLoaded/file.size)*100);
			$('#log li#'+file.id).find('div.progress').css('width', percentage+'%');
			$('#log li#'+file.id).find('span.progressvalue').text(percentage+'%');
		})
		.bind('uploadSuccess', function(event, file, serverData){
			var item=$('#log li#'+file.id);
			item.find('div.progress').css('width', '100%');
			item.find('span.progressvalue').text('100%');
			var pathtofile='<a href="uploads/'+file.name+'" target="_blank" >view &raquo;</a>';
			item.addClass('success').find('p.status').html('Done!!! | '+pathtofile);
		})
		.bind('uploadComplete', function(event, file){
			// upload has completed, try the next one in the queue
			$(this).swfupload('startUpload');
		})	
});

Code Explanation
Since we are using SWFUpload jQuery Plugin, firstly we initialize it on the placeholder element using the $('#placeholder').swfupload({ settings }) function and pass it a settings object that defines various parameters like server side file that will handle uploads, maximum size of the file, number of maximum uploads, allowed file types, button url, button size etc. For complete detail of settings you can use, refer to SWFUpload docs.

At this stage, your file upload script will work but will not show any visual clue to users about the upload. SWFUpload fires certain events that we can use to provide information to user about the file uploads. So, next thing is to bind functions to various events to show required output. That’s what all bind calls are doing. They are pretty much self-explanatory.

Limitations

Since this script uses SWFUpload to upload files, which requires flash plugin, so this will not work if flash plugin is not installed in end user’s browser. Make sure to provide an alternative upload form so that users without flash can upload files.

Also, SWFUpload has some known issues when used on linux systems and if user is behind proxies. Make sure to read them before you use it in production environment.

View Working Demo or Download Source Code

Tags:

Share


Subscribe to Full RSS Feed

RSS FeedIf you found this article useful, then consider subscribing to our RSS Feed or e-mail updates to stay updated with latest Web Design/ Development articles. You can also follow @webdevplus on twitter for latest updates.

38 Responses (Add Your Comment)

  1. Very Nice and helpful Tutorial. Will try this in one of my next projects with uploads.

    Daniel

  2. David Bolton says:

    Really great script, always had problems with multiple uploads, I built my own but using 5 input fields, this is much more elegant. I create session variables with my images created (timestamped so as not overwrite other images) and think this would be awesome to adapt my way of uploading images with this brilliant script.
    Thanks
    David Bolton

  3. leandro says:

    Hi,i found several flash dependent fle uploaders. What is the main reason preventing to achieve the same functionality using pure Javascript code?.Thanks

  4. Ryan says:

    Safari 4 has this functionality built in http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html and I wrote about Firefox 3.6a1 support for multiple drag and drop file uploading http://www.thecssninja.com/javascript/drag-and-drop-upload

  5. Ryan says:

    This is great. I’m trying to modify it so I can upload files directly to Amazon S3.

  6. Bob says:

    Two things

    1) When I center the button/progress area, the progress bar starts in the middle and spans both sides until complete. This is awkward, can I would like it to proceed left to right. How do I do this?

    2) How can I add a “stop upload” for uploads that are in progress?

  7. Jaspal Singh says:

    Excellent tutorial to implement multiple image upload with progressbar. Thanks for sharing.

  8. sorin says:

    This is a great script, however I found that there’s some problems in it. The upload procedure does not upload the files greater then x mb althoug I did the necesary modifications. It generates the ok messages, doesn’t give any warnings or errors, but still the uploaded file isn’t found in the upload folder.
    Anyway, thanks for sharing.

    • Satbir says:

      sorin, in case of swfupload, it gives success message only on successful upload to the server and not on whether your server side script was able to move it to specified folder or not.
      You’ll have to set up uploadSuccess function binding in a way that it tests serverData variable and shows message accordingly.
      Also, try enabling the debug mode of swfupload by settingdebug:true in javascript code and see what the server side response is.

  9. Jurgen Van de Water says:

    Thanks for this tutorial! I’m using this in my website but it won’t work.

    I tested it with the source files and it doesn’t work. When I do an upload it says that it is uploading but it keeps saying uploading… and my upload bar goes directly to 100%. When I see in the map uploads there is nothing in it. Can somebody please help me with this problem?

  10. yves says:

    great work! thanks for sharing

  11. tester says:

    hi,
    i need a form to upload the files with text field , is it possible

  12. vinay says:

    Hey very nice script…. I have a question!!!
    is it possible to post some data with the files????

    Thanks in advance…

  13. Jimmy says:

    I am using this plugin, and I think its really nice..
    I just want to know if there is any way to get the resolution of the image just when the image is slected and added to queue… Actually i want to show a thumbnail of the image being uploaded but i cant do it with plain JS..

    • Satbir says:

      This type of operation though not possible with regular JS, but here’s a nice trick that should do the job for you.
      http://community.invisionpower.com/topic/226158-thumbnail-preview-before-image-upload/
      Also, refer to the swfupload docs to find out the path to selected image

      • Jimmy says:

        Thanks for replying but i have already tried a similar thing before.. The problem is that in this way i cannot maintain the aspect ratio of the thumbnails and it looks really odd for portrait pics.. :-(

    • Jimmy says:

      Maybe I can still do something if i can get the path of the image, but i couldn’t find any reference in the the SWFUpload docs..
      “File Object{

      name : string, // The file name. The path is not included.

      }”
      I’m displaying an animated wait image for the time being.. but its not wt i really want to do..
      Does anyone there have any idea how to get the path of the image..?

  14. Sean says:

    Great tutorial! Can you advise on a method for detecting when *all* uploads are complete?

  15. Sean says:

    Found a solution for detecting ‘all uploads complete’ (I’m totally new to JS so apologies in advance!)

    1) Within the (fileDialogueComplete) event set a global variable ‘totalFiles’ with the value of ‘numFilesQueued’
    2) Within the (uploadSuccess) event split ‘file.id’ with ‘_’ and compare the last element in the array plus 1 with ‘totalFiles’.

    If they are equal, all uploads are complete.

    I would have liked to handle this all in the fileDialogueComplete event, but this event doesn’t get ‘file’ passed to it.. (Interested to learn how this could receive ‘file’).

    Interested in feedback if there is a better way to achieve this.

    Thanks!

    Sean

  16. Michael Douglas says:

    This script is just what I need. I have successfully managed to increase the # of uploads from 5 to suit my needs. This is working fine.

    I’m having issues with increasing the file size allowed. I have changed the java/php script together. I does allow the file to be uploaded on my site, but the file never moves into the ‘uploads’ folder. Can someone please point me in the correct direction.

    Thanks….Mike

    • Michael Douglas says:

      Please disregard my last post. It was my mistake, some of my changes did not take.

      I have now sucessfully allowed up to 60 uploads, with max file size of 5MB.

      Now, because of this script, my website is done!!

  17. Andrew says:

    Great script!

    Is there any way to pass information to the PHP script processing the uploads? Specifically, I need to pass POST or GET variables so that the php script can update a database with the user’s name/id and also an ID for the page they’re uploading from.

    I’m able to get files into my filesystem and even rename them, but this lack of other information is causing issues. I’m a bit of a newbie to javascript, so I’m using the demo more or less as written.

  18. Andrew says:

    Actually, I think I’ve figured it out. I’m using php, so I take information from the page that calls the script and insert a GET query line in the ‘upload_url’ variable so it reads something like:

    upload_url: “upload_swf.php?username=joe&user_id=1&subject_id=285″,

  19. Sam says:

    Hey exellent upload script! I’ve just about had enough of trying to force others to work but this works straight outta the box. Awesome!

    One thing I’d like to integrate though is email support. I want to get an email when users add a file to the server as well as add their name and email which would come with the email.

    Any ideas how I’d do this (Im ok with php but not excellent)

    Cheers!

  20. Mike says:

    I would like to change the file name to represent MMYYDD, once it has been uploaded and moved the the ‘upload’ folder. That way if someone uploads the same file name, it wont overwrite the first file. Can someone please help me accomplish this or point me in the correct direction.
    I know its an addition to the php script, just dont know what to add and also where to add it.
    I appreciate help on this, thanks

    Mike D.

  21. devnull says:

    @Mike
    in your upload script use the date function to format your timestamp
    add the timestamp to the beginning of the file name
    save that filename
    echo a success string back with your new filename
    in your jquery script parse the response to check for error string
    if not error, use the serverdata as the new filename
    ???

    I am using this plugin in my own framework and had to pass the PHPSID through the query string to gain access to the session. I suppose this is a cookie issue with flash ? Or is the cookie plugin for swf required ?

  22. justintime says:

    Very nice!
    However, javascript and flash are too HUGE dependencies…
    “provide an alternative upload”
    …hell, might as well not use it if you have to double the amount of work it takes. Unusable candy.

  23. kyle says:

    Great script. Everything seems to be working well, except: The browser doesn’t see the uploaded files. The files are there on the server in the uploads directory (and I’m able to download them using ftp), but when I click on “view” on the progress bar, or type in the url of the file directly into the browser, I get a 404 error. How weird is that?

    Any ideas?

    Thanks,
    Kyle

  24. kyle says:

    Ooops, I meant to say, 403 error in my last post.

    Kyle

  25. Jad says:

    Works well. I tried to upload 500 files at one go but go this strange error.
    “Sorry. Select fewer Files.”
    How can I remove this limit. My requirement is to upload 5000 images one shot and the client needs this badly.
    Please help.

    Thanks
    Jad

  26. Joel says:

    What about people uploading executable files? If I simply name a php file or any file with a .jpg at the end then I can execute it. I have this problem with all the upload scripts on the net.

    Security is always on the top of my priority list so I’m wondering how can I stop this from happening. I pretty much just hacked my own site in like 2 seconds with this script and I know nothing about that sort of thing so someone who does could do some serious damage.

    Any thoughts on the subject?

  27. Richard says:

    Is there any way to send any varible to ‘upload-file.php’?

    Why doesn’t ‘upload-file.php’ get $_GET variables?
    Why ;p can’t i contact mysql?

Comments are closed for this post.