About & Contact

Ajax Upload; A file upload script with progress-bar, drag-and-drop.

An older ajax upload plugin, which only used iframe for uploads, and was licensed under MIT license is located on github.

This plugin uses XHR for uploading multiple files with progress-bar in FF3.6+, Safari4+, Chrome and falls back to hidden iframe based upload in other browsers, providing good user experience everywhere.


To upload a file, click on the button below. Drag-and-drop is supported in FF, Chrome. Progress-bar is supported in FF3.6+, Chrome6+, Safari4+

Upload a file
  • mercedes-benz-carbon-bike.jpg60.4kBFailed

Download Donate GitHub repo



This plugin is open sourced under GNU GPL 2 or later. If this license doesn't suit you mail me at andrew (at) valums.com.

Please donate if you are willing to support the further development of file upload plugin.

Known Issues

Plugin breaks back button functionality in Opera.

Getting started

The fileuploader.js contains two classes that are meant to be used directly. If you need a complete upload widget (from demo) to quickly drop into your current design, use qq.FileUploader.

If you want to customize uploader, by using a different looking file list or change the behaviour or functionality use qq.FileUploaderBasic.

The difference between them is that qq.FileUploader provides a list of files, drag-and-drop, but qq.FileUploaderBasic only creates button and handles validation. Basic uploader is easier extendable, and doesn't limit possible customization.

qq.FileUploader extends qq.FileUploaderBasic, so that all the options present in the basic uploader also exist in the full widget.

qq.FileUploader - Setting up full upload widget

Include fileuploader.js and fileuploader.css into your page. Create container element.

<div id="file-uploader">       
        <p>Please enable JavaScript to use file uploader.</p>
        <!-- or put a simple form for upload here -->

Initialize uploader when the DOM is ready. Change the action option. For example ../server/php.php for the default folder structure. In the server folder you will find examples for different platforms. If you can't find the one you need, check the readme.txt in the same folder.

var uploader = new qq.FileUploader({
    // pass the dom node (ex. $(selector)[0] for jQuery users)
    element: document.getElementById('file-uploader'),
    // path to server-side upload script
    action: '/server/upload'

Options of both classes

// url of the server-side upload script, should be on the same domain
action: '/server/upload',
// additional data to send, name-value pairs
params: {},

// validation    
// ex. ['jpg', 'jpeg', 'png', 'gif'] or []
allowedExtensions: [],        
// each file size limit in bytes
// this option isn't supported in all browsers
sizeLimit: 0, // max size   
minSizeLimit: 0, // min size

// set to true to output server response to console
debug: false,

// events         
// you can return false to abort submit
onSubmit: function(id, fileName){},
onProgress: function(id, fileName, loaded, total){},
onComplete: function(id, fileName, responseJSON){},
onCancel: function(id, fileName){},

messages: {
    // error messages, see qq.FileUploaderBasic for content            
showMessage: function(message){ alert(message); }

Instance methods

Changing alert/messages to something more user friendly

If you limited file types and max size, you will probably want to change the default alert and messages as you see fit, this is possible using showMessage callback and messages option.

Sending additional params

To add a parameter that will be passed as a query string with each upload use params option.

var uploader = new qq.FileUploader({
    element: document.getElementById('file-uploader'),
    action: '/server-side.upload',
    // additional data to send, name-value pairs
    params: {
        param1: 'value1',
        param2: 'value2'

To change params based on the state of your app, use

   anotherParam: 'value' 

It can be nicely used in onSubmit callback.


If you can't get the uploader to work, please try the following steps before asking for help.

If the upload doesn't complete, saying failed.

It should be {success:true} for completed requests. If it's not, then you have a problem with your server-side script.


Thanks to everybody who contributed, either by sending bug reports or donating. And special thanks to:

John Yeary
Sidney Maestre
Patrick Pfeiffer
Sean Sandy (SeanJA)
Andy Newby
Ivan Valles

  • and 552 others liked this.

Glad you liked it. Would you like to share?

Sharing this page …

Thanks! Close

Add New Comment

Showing 80 of 939 comments

Sort by   Subscribe by email   Subscribe by RSS
  • How can I disable the Drag&Drop-Feature?
  • sasuke 1 week ago
              It well work with firefox, chrome, safari.. can't make multiple selection in ie and opera browser... Anybody know how to overcome this problem..? if no give me other solution that didn't use the flash element for displaying the progress bar...
  • Firefox, Chrome, and Safari work better with the script than Internet Explorer and Opera.  Internet Explorer and Opera receive different parameters, and you need to have your application handle the data differently.  Try to look at the params sent to the server when you upload a file in Internet Explorer, to get a better idea of what you need to do.  Sorry if that's too vague, I hope it helps you at least.
  • sasuke what's the file I havce to open to see the form upload. I did a paste of the whole form I haven't done any integration I am having troulbe to find the form for upload.
  • hamochi 3 months ago
    About 90 % of the time some files get "stuck" when uploading in safari 5 (osx). They go to 2-5% and nothing happens any more. No console errors. This means if i have 5 allowed upload at the same times and if 3 gets stuck only 2 will continue at the time, when canceling the stucked files, 5 files will continue to upload again at the same time. The console error after the cancel is Failed to load resource: cancelled. I have both used the do-nothing.html and php.php.

    The strange thing is that this never happens when trying the demo on this page. This could be a server side problem, but then again this never happens when using chrome or firefox.

    Any ideas?
  • @Asdd Reminds me of a story about a doctor. A man goes to the doctor because his arm hurts. When he arrives, he demonstrates to the doctor saying, "Doctor, my arm hurts when I do this." He poked himself in the arm and winced in pain. The doctor replied, "I have the cure. Don't poke yourself there."
  • I fixed this oddity with a *synchronous* ajax call attached to onSubmit to a simple php page that contains header('connection: close');. Needs to be synchronous so it happens before the next upload attempt occurs.

    Using jQuery this looks like:

    async: false,
    url: './connection-close.php'

    Seems to be an issue with Safari being too clever when it comes to caching. Worked fine in Chrome et. al. without the close connection call, but now is very stable in Safari too. Hope that helps!
  • Knossos 7 months ago
    There are quite a few negative comments here, I just wanted to say thank you very much for all your work and to all involved.

    I have had absolutely no problems. I had to change a couple of things in the javascript for my purposes. Such as "Upload a file", I wanted something a bit more custom.

    Again, thank you very much.
  • This is good script with little problem.
    more custom with client side is better.

    i have only one problem with multi upload, it's stop when processing some stuff like gd / ImageMagick.
  • i am trying to use it with image magick too but it just didnt passed the basic robustness like special chars in file name and submitting large files apprx 100mb
    its is a good effort really butt everything spoils when these things occour
  • Special chars in file name are not allowed by upload protocol. Is not fault of plugin.
  • phpfreak is right, actually I personally always prefer a-z0-9 file names only.
    If you want special characters (in German ä,ö,ü,ß etc.) you may have to wirte an escape method, which escapes the characters correctly (similar to URLs with %20 instead of Space etc.)
  • Can you help me WHERE and HOW to do this escaping of special characters?
    Thanks in advance!
  • been trying to figure a better option than the upload in http://www.cheapaschina.com/up...
  • cheapaschina uploader , its cheap in look also :)
  • dfdfdf
  • bogdanbr 4 months ago
    Hello. Great script but it dose not work on Mozilla Firefox 3.5. Can someone help me? I am desperate !
  • This is only going to work in FireFox 3.6 and above since it requires HTML 5 support.
  • I have FireFox 3.6.12, and when I try to upload, the HttpFileCollection is empty. It works in IE. The header looks populated... please let me know if anyone has any ideas.

    User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv: Gecko/20101026 Firefox/3.6.12
    Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language en-us,en;q=0.5
    Accept-Encoding gzip,deflate
    Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive 115
    Connection keep-alive
    X-Requested-With XMLHttpRequest
    X-File-Name Penguins.jpg
    Content-Type application/octet-stream
    Content-Length 777835
    Cookie __utma=63923887.845348791.1296242425.1296242425.1296244235.2; __utmb=63923887.7.10.1296244235; __utmz=63923887.1296242425.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); ASP.NET_SessionId=brkcnzmnkrq1wg55rdmdh2ag; __utmc=63923887; CustomerID=RCCLADMIN; .ASPXAUTH=D320AD4B4AFC4D13E6773752DF36955323B6F73A6C75BBB81300328701E9C54BE392ADA0CF81962E35A57A8E7083F0D53CBA78B5E840805C4D4E44D43840BF9F3AA83A05E11D66EDE1E374740F43507D93FECF1BDA62DD92FCC0E7F85DE3DE161E98814BDA3A5E7468FA76047EA4BB79E97EC467EE13F113C17E3CBA5C6C9AB360FF1FC1
  • Any news on this? on firefox 3.6.17 it is not working also the $_FILES is empty.
  • never mind - Andrew gives an example of the server side code for FireFox further down.
  • where is this example?
  • hey, have you figured this out? this doesn't seem to work in .net thanks
  • when i upload, in firebug the response is { error : file is empty }
    Please help.
  • Why are you uploading a file with 0 bytes?
  • Andrew Valums  Is it posible to dequeue the list and thereby reset the id to 0 once the upload is complete ? can't get this to work :(  Is it posible to dequeue the list and thereby reset the id to 0 once the upload is complete ? can't get this to work :(
  • a detailed documentation is missing imho. especially on how to modify the look & feel etc.
  • Netiasuka 3 months ago
    i cant post it to server-side ?
    function createUploader(){
    var uploader = new qq.FileUploader({
    element: document.getElementById('file-uploader-demo1'),
    action: 'php.php',
    debug: true

    this._options = {
    // container element DOM node (ex. $(selector)[0] for jQuery users)
    element: null,
    // url of the server-side upload script, should be on the same domain
    action: 'php.php',
  • Hi,Netiasuka.
    i am not good at English.
    i hit the same problem as you. you moust apache post_max_size and upload_max_filesize check.
    your php.ini file.
    The problem was solved.
  • Nitinjadster 5 months ago
  • Badcode 7 months ago
    With the Perl script does not work.

    my $file = $IN->param('POSTDATA');
    my $temp_id = $IN->param('temp_id');

    $file and $temp_id are empty.
  • Hi. Have you been able to solve this problem? I'm not the author of the perl script, so unfortunately I can't help.
  • Would it be possible to contact the author? Sorry for my English, I write with the help of Google Translate. ;-)
  • I'm running into the same problem, I emailed Andrew, before I found this discussion. Sorry Andrew, I wasn't aware the perl wasn't yours, it isn't attributed in the file.

    I do get the file available to me in the cgi using
    my $file = $IN->param('POSTDATA');
    but that is all if I do
    my $params = $IN->Vars;
    my $foo = join (',' , keys %$params);

    die "foo is: $foo";

    Then all I get in the log is 'foo is: POSTDATA' if I switch the keys in the above code snippet to values, then I get 'foo is: '

    But any extra params I try to pass through and the $temp_id are indeed empty.

    I've looked at it in firebug and the url seems to be being encoded properly like...

    cust is my added param and qqfile is the name of the file I'm uploading although still no temp_id

    I have a suspicion that this is all to do with content-type as the perldocs on CGI.pm say:

    "If POSTed data is not of type application/x-www-form-urlencoded or multipart/form-data, then the POSTed data will not be processed, but instead be returned as-is in a parameter named POSTDATA."

    but that would seem to me to suggest that POSTDATA should contain the params, and it doesn't, just the contents of the file.

    Seems we need a perl guru to explain what is happening to them.

    I'll have a look at this further, and maybe post to perl monks soon, I'll come back here and let you all know if I have any success. In the meantime if anyone has any bright ideas please let me know
  • That should read in the above code snippet to values, then I get 'foo is: [%contents of file%]' I used angle brackets before that get et by the bbcode cleaner or somesuch.
  • Ok I've made a perl script which seems to work here fine. I've only tested it so far in Firefox 3.6.10 but it should work in other browsers too.

    The code is here http://pastebin.com/w72f6hKS
  • Ok, here it goes - CGI.pm param(POSTDATA) is empty with Opera 10.x and 11 beta 1 so the perl.cgi FAILS, with Firefox 3.6.x, Chrome 4.x, Safari 4.x it WORKS. It is some odd behaviour going on here ...
  • voltron 4 months ago
    Does the destination really need to be the same domain?

    I've seen scripts that upload directly to S3. Is that possible here?
  • Need this too.
    What i should delete to post on another domain.

    Need it very much
  • Lamp Mia 4 months ago
  • Minhtribt 3 months ago
    cannot cancel a file when upload success ?? ==> uncomfortable
  • Cannot cancel when a file has successfully uploaded?
    Are you mad?
    To cancel, means to stop a process from happing, hence cancelling WHILE it's uploading, NOT after.
    This script isn't for deleting files once they've been uploaded.
  • Great script, only i have 1 question. What is the best way to intergrate a resizing script?
    Thanks for the code.
  • Stanley1610 2 months ago
    I run demo.htm in Mac OS X by Firefox 4 or Safari 5 but it showed failed once I tried to upload a file.

    However, I run it in Win XP by IE6 and no failed showed.

    What's wrong?
  • Yes ,IE 6、IE 8 can't use
  • Yes ,IE 6、IE 8 can't use
  • Great script, I've gotten it to work with my customer server side code. I was hoping to just pass this object a list of files and have it upload in the background as I am trying to reduce the interaction between client and server. Basically I would have the user select several files to upload then click a button and they would all be uploaded. Any way to do this?
  • Did anyone find a solution to this problem?

    Im interested, too...
  • Hello. In Opera 10.60 not work "multiple file select".
  • Can you post full ASP.NET example or if already exists can you post link, please.. I keep getting a zero count for my HttpFileCollection when I use HttpContext.Current.Request.Files. Do you know what I might be missing? Thanks
  • Here is a basic idea how to handle the upload, thanks to Vaies for the code.

    <%@ WebHandler Language="C#" Class="FileUploader" %>

    using System;
    using System.Web;
    using System.IO;

    public class FileUploader : IHttpHandler {

    public void ProcessRequest (HttpContext context) {
    string result = "{\"success\":true}";
    string path = System.Configuration.ConfigurationManager.AppSettings["Files"].ToString();
    string saveLocation = string.Empty;
    string fileName = string.Empty;

    int length = 4096;
    int bytesRead = 0;
    Byte[] buffer = new Byte[length];

    //This works with Chrome/FF/Safari
    // get the name from qqfile url parameter here
    fileName = context.Request["params"];
    saveLocation = context.Server.MapPath(path) + "\\" + fileName;

    using (FileStream fileStream = new FileStream(saveLocation, FileMode.Create))
    bytesRead = context.Request.InputStream.Read(buffer, 0, length);
    fileStream.Write(buffer, 0, bytesRead);
    while (bytesRead > 0);
    catch (UnauthorizedAccessException ex)
    // log error hinting to set the write permission of ASPNET or the identity accessing the code
    result = result.Replace("true","false, \"error\":" + ex.Message + " " + ex.InnerException);
    //This works with IE
    fileName = Path.GetFileName(context.Request.Files[0].FileName);
    saveLocation = context.Server.MapPath(path) + "\\" + fileName;
    catch (Exception ex)
    result = result.Replace("true", "false, \"error\":" + ex.Message + " " + ex.InnerException);


    public bool IsReusable {
    get {
    return false;

  • hey, nice code. its working in asp.net. but i need content type when upload is done using inputstream. can get file's content type from file using "context.Request.Files[0].ContentType" but how to do that for other browsers ? any idea ? can we pass content type as parameter or something?
  • Thank you very much andrew
  • How to check the content type of an image file inside this image handler in ASP.NET?

    Can i check the content type in the client side itself?
  • Have you figured this out?
  • hi how can I do a posting comment script lie this one?
  • Hey, thanks for your efforts! I really like your works :)

    Anyway, I was implementing it using ASP.NET serverside. I am trying this code but I have two errors:

    1) System.Configuration.ConfigurationManager.AppSettings["Files"].ToString();
    This can't find the path to the uploads directory. I changed it in something like "C:\\root\\my_site\\Uploads". Now the error is skypped.

    2) Trying to upload a file I get this error:
    {"success":false, "error":Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index }

    Can please help me? I am really pissed because I think I am soooo close!
  • I get #2 as well. To respond to Gangbang:

    It comes up when I compile FileUpload.ashx, but it also comes up just running the page with the uploader control. It shows up in the java console right after data is sent to FileUploader.ashx. The code in the try loops don't seem to run at all.
  • When do you specifically receive the second error? I have no problems with the piece of code valums provided.
  • Hi. Could you please help with the asp.net sample?

    I created an ashx exactly like you post here and my client code is like this:

    var uploader = new qq.FileUploader({
    element: document.getElementById('file-uploader-demo1'),
    action: 'uploader.ashx'

    But I'm receiveing and Fail message:
    * f007.jpg39.4kBFailed
    * f010.jpg59.4kBFailed
    * f011.jpg55.3kBFailed

  • Marco:

    I was getting this same error when running the project in debug mode from Visual Web Developer. It wasn't running the ashx file. But if you just build the project and then run the uploader from localhost, it seems to run the ashx file. Shrug.
  • This is more of a reply to Marco Borsoi. I was getting the same error. You have to include the fileuploader.css
  • ha-ha) just found your error. you receive the 2) error when you try to compile FileUpload.ashx. just try to run your website from Default.aspx or another page where you have the uploader control.
  • Marco, did you try to put some breakpoints inside your "uploader.ashx" file and to see what happens in debug mode? If you didn't just try it and see what kind of errors you have and then let me know if you stille have problems.
  • have you figured this out?
  • onComplete: function(id, fileName, responseJSON){},
  • Metreveli 4 months ago
    Hello. In IE not work "multiple file select". :(
  • Hi, I'm trying to get this to work with MVC. I get the file and can save it fine but the status always says "Failed". The Response is "{success:true}" as is the responseJSON. I'm using FF 3.6.15.

    Here's the code:
    function createUploader() {
    var uploader = new qq.FileUploader({
    element: document.getElementById('file-uploader'),
    action: "/Photo/Upload2",
    debug: true,
    onSubmit: function (id, fileName) {
    caption: jQuery('#caption').val(),
    comment: jQuery('#comment').val()
    onComplete: function (id, fileName, responseJSON) { alert(responseJSON); }

    and the MVC controller method:
    public ActionResult Upload2(long SouvenirInstanceID, string caption, string comment)
    var fileName = Request["qqFile"];

    var saveLocation = "C:\\" + fileName;

    var result = "{success:true}";

    using (var fileStream = new FileStream(saveLocation, FileMode.Create))
    var length = 4096;
    var bytesRead = 0;
    var buffer = new Byte[length];
    bytesRead = Request.InputStream.Read(buffer, 0, length);
    fileStream.Write(buffer, 0, bytesRead);
    } while (bytesRead > 0);
    catch (Exception ex)
    result = result.Replace("true", "false, error:" + ex.Message + " " + ex.InnerException);

    return Json(result, "text/html");

    Any help is greatly appreciated. Thanks
  • How do you start the file upload dialog via Javascript. Is it possible to generate the button click event via javascript?
  • I have the same question. Did you find an answer yet?
  • I've been having issues get the onComplete callback to work uniformly across different versions of firefox. The problem is that while everything works great on FF3.6, on FF3.5 the responseJSON object is nowhere to be found. so a function like

    onComplete: function(id, fileName, responseJSON) { doSomethingWithJSON(responseJSON); }

    Works fine in 3.6 but not in 3.5. Any idea why that might happen and how to resolve this?
  • hey, sa125, do you manage to fix the firefox 3.5 problem?
  • South African Developer 9 months ago
    I see it's impossible to make the mouse cursor change to pointer when moving over the upload button in Firefox (version 3.6.8)

    Any ideas on how to fix the cursor? The styling only works in other browsers. (Even IE got it right, lol.)
  • Same problem here! PLEASE HELP ! :)
  • It's a security thing. CSS styling of a file input field isn't allowed in general.
  • It's a firefox bug. You just can't do it.
  • Sebastian 9 months ago
    Very useful, thanks a lot.

    But I had the problem that the function apache_request_headers was not available. Had to rewrite the UploadFileXhr from the server directory to look like this (and the handleUpload function to call the close method at the end):

    class QQUploadFileXhr {

    private $tmp_fp = null;

    function __construct(){
    $input = fopen("php://input", "r");

    $this->tmp_fp = tmpfile();

    while($content = fread($input,1024)){

    function save($path){

    $fp = fopen($path, "w");
    fseek( $this->tmp_fp , 0 , SEEK_SET );

    while ($data = fread($this->tmp_fp, 1024)){


    function getName(){
    return $_GET['qqfile'];

    function getSize(){
    if( function_exists('apache_request_headers') ){

    $headers = apache_request_headers();
    return (int)$headers['Content-Length'];

    } else {

    fseek( $this->tmp_fp , 0 , SEEK_END );
    return ftell( $this->tmp_fp );



    function close(){

  • i know i did already post something about that with other issues, but found something new on that subject :

    what about only changing

    function getSize(){
    return $_ENV['CONTENT_LENGTH'];

    it worked properly to get the content-length, the early test i did were with "-" instead of "_".. :)

    FROM PHP WEBSITE, on apache_request_headers() :
    « Note: You can also get at the value of the common CGI variables by reading them from the environment, which works whether or not you are using PHP as an Apache module. Use phpinfo() to see a list of all of the available environment variables. »
  • The UploadFileForm class needs an empty "close()" function for this to work properly.
Show more comments …