Tuesday, May 18, 2010

12:07 AM

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.
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.
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>  

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; rightright: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.

        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#'+file.id+' .cancel').bind('click', function(){ //Remove from queue on cancel click  
                var swfu = $.swfupload.getInstance('#swfupload-control');  
            // start the upload since it's queued  
        .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%'); 
            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 
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.


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.