Mozilla

interactive file uploads with Drag and Drop, FileAPI and XMLHttpRequest

In previous posts, we showed how to access a file through the input tag or through the Drag and Drop mechanism. In both cases, you can use XMLHttpRequest to upload the files and follow the upload progress.

Demo

If you’re running the latest beta of Firefox 3.6, check out our file upload demo.

Uploading

XMLHttpRequest will send a given file to the server as a binary array, so you first need to read the content of the file as a binary string, using the File API. Because both Drag and Drop and the input tag allow you to handle multiple files at once, you’ll need to create as many requests as there are files.

var reader = new FileReader();
reader.onload = function(e) {
  var bin = e.target.result;
  // bin is the binaryString
};
reader.readAsBinaryString(file);

Once the file is read, send it to the server with XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open("POST", "upload.php");
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
xhr.sendAsBinary(bin);

You can choose to be notified when specific events, such as error, success, or abort, occur during the request (see the MDC documentation for more details).

Following the Upload Progress

The progress event provides the size of the uploaded portion of the binary content. This allows you to easily compute how much of the file has been uploaded.

Here’s an example showing the percentage of the file that has been uploaded so far:

xhr.upload.addEventListener("progress", function(e) {
  if (e.lengthComputable) {
    var percentage = Math.round((e.loaded * 100) / e.total);
    // do something
}, false);

27 comments

Comments are now closed.

  1. Michael Irwin wrote on December 15th, 2009 at 11:40:

    Wow! This is looking really good. I can’t wait for the final release to come! :-)

  2. Ryan wrote on December 15th, 2009 at 23:14:

    I like the canvas loader, sexy.

    A few observations from my own drag and drop uploader I did a while back, http://www.thecssninja.com/javascript/fileapi

    - Using a function passed into the progress event listener and using e.target to access the loader container fails randomly and loses reference to itself. To fix this I used an anonymous function inside the listener rather than passing on the duties to external function. That way I could directly access the container rather than using e.target.

    - Another issue is if I drag in the Windows Vista sample images they all begin to upload fine, but when it gets to 2 particular files it craps itself and throws an exception

    uncaught exception: [Exception... "Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMFileReader.readAsBinaryString]” nsresult: “0×80004003 (NS_ERROR_INVALID_POINTER)” location: “JS frame :: http://thecssninja.com/demo/drag-drop_upload/v2/ :: anonymous :: line 147″ data: no]

    2 files always fail and are the 2 largest files out of the sample images. There seems to be sporadic failures with images larger than ~550kb, but this also depends on how many images I’m uploading.

    1. Mark S wrote on October 28th, 2010 at 12:37:

      Ryan, have you got a chance to get around Component returned failure code: 0×80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMFileReader.readAsBinaryString]” nsresult: “0×80004003 (NS_ERROR_INVALID_POINTER)” location: problem?

      I’m going to try /catch it but it’s a pity it’s almost been an year since that comment and no one seems to fix that bug.

      1. Ryan wrote on October 28th, 2010 at 15:29:

        Mark, I haven’t really looked into it for a while. A potential solution, although only in FF4, would be to use the createBlobURL[1] method so you can link to the file and display it without loading it all into memory. Loading to much data directly into memory could potentially be the cause of the exception. Paul if you have a better insight please let us know.

        [1] https://developer.mozilla.org/en/DOM/window.createBlobURL

        1. Mark S wrote on October 28th, 2010 at 15:50:

          FF4 is not going to cut it -)
          Trying to check the status of those and work around to retry uploading automatically.
          Thanks a lot, great work on your site, let me know if you find anything.

  3. Jose wrote on December 16th, 2009 at 03:29:

    Does anyone know if downloading files in the same way is possible? Or is that something that might come in a future release (if at all)? Would this bug https://bugzilla.mozilla.org/show_bug.cgi?id=338478 be that?

  4. thinsoldier wrote on December 17th, 2009 at 09:12:

    In a future post you should show how to take a dropped 5 megapixel photo and use canvas to resize it down to both an 800×600 and a 100×75 thumbnail. Then upload those 2 canvas generated images to the server instead of the huge original.

  5. iNsuRRecTiON wrote on December 18th, 2009 at 13:35:

    Hi there,

    nice, but you are unable to remove single pictures from the drop zone, if you don’t want to send this pic.

    Example, you are select 15 pics, but then you see in the preview in the drop zone, you don’t want to send two of them.
    Now there is no ability to remove the two pics.
    You have to re drag and drop or open dialog the files, without those two, which is bad user experience!

    regards,

    iNsuRRecTiON from Germany

  6. Chrom wrote on December 29th, 2009 at 04:48:

    @insurrection
    That could be easily solved by adding a “waste-basket” that you can drag added files to.

  7. Christopher wrote on December 29th, 2009 at 12:53:

    Am I right that all files are transferred through the browsers memory since they are available as binary string within the JavaScript?
    I suppose that if I read (or upload) a 100 MB file via FileReader, my browsers memory usage increases accordingly?!

    Is that intended?

  8. Tom wrote on January 21st, 2010 at 01:59:

    +1 for thinsoldier’s suggestion.

    I’d love to see resizing before upload example. This can be achieved with Gears at the moment (e.g. Google Wave). But I’d love to see how to do it with File API.

    Thanks for this great work.

  9. andym801 wrote on January 21st, 2010 at 19:40:

    thinsoldier’s suggestion would be nice, but you guys are over-complicating the simplicity of a Drag and Drop upload system. Maybe in the future they’ll showcase a Drag and Drop photo re-sizer.

    What I would like to see… is a green check-mark or red “x” on my photos to confirm whether or not the upload was successful. This would be handy if you had a lot of big photos to upload, and wanted to walk away from your computer. In which case you wouldn’t have seen the little progress ring.

  10. Pingback from Drag & drop Uploads with XMLHttpRequest2 and PHP at Web Development and stuff… on January 24th, 2010 at 16:02:

    [...] And according to the new specs. This would allow for easy file uploads. Now there’s been some examples [2] on the web already. But i just wanted to get my hands [...]

  11. Pingback from Firefox 3.6 uses the W3C File API | Broken Links on January 25th, 2010 at 16:37:

    [...] of the API, showing first multiple file uploads, then a drag and drop upload interface, next adding progress information (although this doesn’t work for me), then reading EXIF data from a JPEG image. You can imagine [...]

  12. Pingback from firefox 3.6 « kravca.mu/blog on January 26th, 2010 at 04:32:

    [...] uploads http://hacks.mozilla.org/2009/12/uploading-files-with-xmlhttprequest/ http://demos.hacks.mozilla.org/openweb/uploadingFiles/ (very [...]

  13. Preben Borch wrote on January 28th, 2010 at 08:22:

    Are there any server side PHP script examples for receiving the files. The form method works as expected, but when I try the XMLHttpRequest method I get nothing into the PHP script? Something I missed?

  14. Ryan wrote on January 28th, 2010 at 16:22:

    Thia article delves into handling file uploads from a drag and drop action. http://www.appelsiini.net/2009/10/html5-drag-and-drop-multiple-file-upload

  15. Preben Borch wrote on January 29th, 2010 at 08:22:

    I dumped the standard input to a file, and there it was. It would be a good idea with a more complete example – sending filename in the url would be a nice. Otherwise this new functionality is great! I have made a Google Gears upload which worked very well, but somehow updates of Google Gears is slow for new releases. Sending files in chunks would be a good idea as well, and publishing the server side script (well, I’m happy right now, but there may be others).

  16. Ryan wrote on January 29th, 2010 at 18:33:

    Sending files in chunks is currently being disucssed on the webapps mailing list and therefore mozilla held off on adding this functionality to ff3.6. They will have a blob which can be sliced into smaller chunks, obviously gaining these ideas from google gears. http://www.w3.org/TR/FileAPI/#dfn-Blob

  17. Eric Jain wrote on February 4th, 2010 at 17:48:

    Too bad you can’t set the dropped file(s) into an

  18. Craig Morrison wrote on March 1st, 2010 at 21:55:

    I’ve got my take on this at:

    http://www.sillywindows.com/

    It is clearly obvious which link to click on to grab it.

  19. Pingback from Using the File API for reading file information & multiple file uploads – another sister specification to HTML5 - Robert's talk on April 22nd, 2010 at 08:32:

    [...] After you have read out the necessary data about the file(s), you can get the binary data by using a FileReader object and then use the XMLHTTPRequest object to post it to a web server. More information about that can be found in the FileReder documentation and in Paul Rouget’s article Interactive file uploads with Drag and Drop, FileAPI and XMLHttpRequest. [...]

  20. Daniel Kirsch wrote on September 21st, 2010 at 15:02:

    How can I send both usual form data together with the file and use the progress indicator? Do I need to first upload the files using xhr.sendAsBinary and than send the other form data on success with a second request?
    In FF4 I could use FormData, however I also want to support FF 3.6.

  21. Helio Bentes wrote on December 29th, 2010 at 06:26:

    How can I get the image and save it in my server using PHP?

    1. hash wrote on December 29th, 2010 at 14:56:

      You may compose multipart request, send it via sendAsBinary method and deal with it at server side as you usually do width file uploadings.

  22. kris wrote on February 24th, 2011 at 00:24:

    I’ve been playing around with the fileAPI a bit today – something has me stumped, and this may be a bit of a noob question, or a need-more-coffee question, but i’m going to ask it:

    what does the upload.php look like in this example??
    what does my server-side code look like to access the data i’m receiving ??

    is is all just raw data in $_POST ??? – i guess i can try that for myself and see can’t i … just a minute … yeah, no, $_POST is an empty array, so is $_FILES

    please help ! (I see that “Hello Bentes” and “Preben Borch” have asked the same question but no replies to this yet… “Ryan” your reply was great, but still wonder if there is a possible server-side program that doesn’t require creating a custom JS upload)

  23. Preben Borch wrote on February 28th, 2011 at 10:24:

    kris, you need to open stdin in PHP and dump this to a file.

    To open a file pointer to stdin follow this example:

    http://php.net/manual/en/features.commandline.io-streams.php

Comments are closed for this article.