The File API has changed

Dec 10
 
The File API has changed

Recently I have been touting how awesome and revolutionary the File API is through a few demo’s. After some feedback on webapps mailing list there have been some major changes to the API and how it works.

I have updated my previous drag and drop upload demo to reflect the API changes, as of Firefox 3.6b3 the API supports both the original API and the updated one. The older model will eventually be dropped, it’s only in there for legacy purposes. To use the demo you will need Firefox 3.6 installed. You can also watch the screencast of it in action.

The biggest change is with the file handling, it is now processed asynchronously with progress events so we can attach listeners. The advantage of this is if a user drags in many files or a large file the UI won’t be locked up while it’s processing the data, much like XmlHttpRequest works.

The File object

The File object has been updated to reflect the new specs changes and has deprecated all the previous methods we used to get the file in various formats e.g. getAsDataUrl(), getAsText(), getAsBinary(). We now handle these methods in the new FileReader object.

It has also renamed the 2 properties for accessing the files name and size from fileName/fileSize to name/size respectively.

The FileReader object

This new object allows us to asynchronously read the contents of a file from a drop event.

var reader = new FileReader();
 
reader.addEventListener("loadend", TCNDDU.buildImageListItem, false);
reader.readAsDataURL(file);

Instead of locking the UI while we wait for it to loop through all the dropped files and then convert them to a DataUrl. The FileReader does this asynchronously. We attach to the onloadend event handler which will fire once the current file has been read into the result attribute. Upon the event firing we then take the event result and add the DataURL to the source of the image to be displayed to the user while it uploads.

Send the binary data

Once we have the file we send it to be processed for an XHR call so we can upload it to the server. Same as above we need to create a file reader and attach to the onloadend event which we then pass to the sendAsBinary() method.

var getBinaryDataReader = new FileReader();
 
getBinaryDataReader.addEventListener("loadend", function(evt){xhr.sendAsBinary(evt.target.result);}, false);
getBinaryDataReader.readAsBinaryString(file);

Similar code we used for the image display handling, but we use the readAsBinaryString() method to return the files binary data for uploading.

Further reading

As the 3.6 final release date is coming closer Mozilla has been ramping up demos and documentation about the File API. Some good documentation on handling files in web applications.

Update: Mika Tuupola has a good article on handling the server side (PHP) part of file uploading.

The hacks blog has recently put up some great information about the File API along with an excellent demo extracting EXIF data from an image.

Now we just need webkit to push out the File API to their nightly builds.

 
 

Post filed under: html5, javascript.

Skip to comment form.

Comments

  1. Any word on how this will play with Safari? I’m working on a site that only need to support FF and Safari and this could be a great addition.

    Luke, January 23rd, 2010
  2. Not sure when they will implement the File API, but there has been a bug filed on webkits bug tracking site requesting they add it.

    The Css Ninja, January 23rd, 2010
  3. Nice work!

    surreydude, February 5th, 2010
  4. Tested the demo to work in the release version of Firefox 3.6. Very cool. I noticed after the image is “uploaded” it outputs the image as a base64 encoded data URI… any reason you’re doing this instead of storing the image on the server?

    I assume it is possible to simply store the image on the server if desired.

    Michael Butler, February 6th, 2010
  5. @Michael – It’s actually encoded into a base64 string before it uploads (using the File API). That way I can display the image to the user before any uploading happens. If you disable your network connection and drag in the images it will still display them but will obviously fail on trying to upload them to the server.

    The Css Ninja, February 6th, 2010
  6. That makes sense! I can see how easy it is then to use the offline data API to store the images locally and upload them later on. Can’t wait to try this out.

    Michael, February 6th, 2010
  7. When I try the demo in FF3.6 on Ubuntu, Firefox tries to open the dropepd document, instead of uploading them. It seems to ignore the File and Drag And Drop APIs.

    Émile Jetzer, February 28th, 2010
  8. @Émile – That’s not good, I don’t have a linux machine available for me to test on so I can’t see what’s happening. Can you try my font dragr web app (it uses the file API too) in FF3.6 on your linux machine and let me know if you have the same issue?

    The Css Ninja, March 1st, 2010
  9. The font dragr doesn’t work either. It seems to be exactly the same issue.

    Émile Jetzer, March 1st, 2010
  10. @Émile – So I asked around for a few people with linux to try my demo and it’s working for them, but someone did mention that having the Jetpack add-on installed kills the drag and drop functionality but only on linux machines, mac/windows are OK. It’s been filed in the issue tracker so they’re aware of it.

    The Css Ninja, March 2nd, 2010
  11. I disabled Jetpack, and now it works all right! Thank you!

    Émile Jetzer, March 6th, 2010
  12. This is really cool! Ubuntu/Firefox isn’t working for me (no Jetpack here), but it works great on my windows machine. I’m going to hack on it for a while to see if I can figure out where Linux is going wrong…

    Shawn, April 7th, 2010
  13. Shawn, don’t have a linux box to test on so I can’t help you on that front. Only linux issue is the Jetpack plugin but you’ve stated you don’t have it. If you figure out the problem I would be interested to know what it was.

    The Css Ninja, April 7th, 2010
  14. Could you update your article to include a little blurb on how update.php handles it? As in: $_POST['what goes here???']. I don’t see a name property set anywhere for the post data in your code…

    Curt, April 24th, 2010
  15. Curt, have a look at this article as it goes into handling the server side of the upload, should help you out.

    The Css Ninja, April 24th, 2010
  16. @Curt
    Using some inspiration from this article, I came up with a JSON solution to upload both binary and/or user data.
    http://alex-tech-adventures.com/development/x-html–css–javascript/97-drag-and-drop-upload-using-html5-with-firefox.html

    Alexander Romanenko, May 15th, 2010
  17. hi,
    i’m trying to get the server site working :

    my upload.php server side is a simple var_dump($_FILES)

    i added an event listener for the ready state change for the xhr to log the response

    i get an empty array

    firefox 3.6
    php 5.2.10
    apache 2.2.11
    on windows XP 32b

    Guillaume, May 19th, 2010
  18. Looks nice, but how to store the files on the server?

    I’m sorry if I read over this – English is not my first language..

    The article you postet on April 24th doesn’t want to help me ;)

    Holger, May 23rd, 2010
  19. any chance you could let me know how to add “cancel (single object)” and/or “cancel all” method(s)?

    chris malcolm, June 6th, 2010
  20. Thanks for the sample, really helped me a lot!

    However, I discovered a small bug in the handleDrop() function which prevents the file name from being propagated past the drop event. Not really a big deal, but for what I’m doing some information is encoded in the file name which I need to access between the drop and the upload. Anyways, to fix the issue line 96 should be setting reader.name to droppedFileName.

    Clark, June 18th, 2010
  21. know how I can get the data in a JSP instead of php,because I need to upload the files using JAVA

    salvador, June 19th, 2010
  22. I just finished a jQuery plugin for this:
    http://github.com/weixiyen/jquery-filedrop

    Assuming Webkit follows suit, this should be future-compatible, but it works perfectly with FF3.6 right now.

    Weixi Yen, June 22nd, 2010
  23. WoooWW
    Best thing ever in html
    I saw this in gmail and later on in google wave presentation, i didn’t think that i can find the source code …..
    Thanks a lot, it will sure come in handy in my projects.
    Wooooooooooow :D :D

    Farzan mc, June 23rd, 2010
  24. @Chris M – Not sure what you mean. You want to be able to cancel an image upload?

    The Css Ninja, July 5th, 2010
  25. @Salvador – Not familiar with JSP but I’m sure they share similar functions. Might be better off asking on a JSP forum.

    The Css Ninja, July 5th, 2010
  26. @Holger – Have a look at the previous comment I made it has a link to a website which goes into handling the data on the server side.

    The Css Ninja, July 5th, 2010
  27. I was implementing some of these features by looking in your zip file download… ran in to an issue where you do:
    fileUpload.log = container;

    But the log property doesn’t carry over 90% of the time in the load event of the XHR… you must have realized this because this part is commented out in your live demo, which uses anonymous functions to keep a handle on the progress bar!

    Michael Butler, August 15th, 2010
  28. @Michael B – Ah must of forgot to update the demo files zip file, thanks for pointing that out. Source files zip is updated now.

    The Css Ninja, August 15th, 2010
  29. One of the problems I keep coming up against with drag & drop is the lack of affordance. Even in gmail– I don’t know that I can drag and drop an image until I’ve already tried it, and the actual area I can drop my files in isn’t the “Rich Text” portion of the app, which is debatably where I’d want to see my file.

    One of the things I’ve tried is to simply swap classes on input, so that if the user drags a file into the window, the entire window can receive the file. Otherwise, style it to look like a button in my rich text editor so that it behaves normally.

    After successful drop, a small “Uploading” message is set with a fixed position, similar to gmail’s “sending…” message.

    Upon successful upload, the final file location(s) (I’m resizing along the way) are sent back as jsonp so that img tags can be generated and inserted into the rich text editor.

    Not feasible for say, a CMS with multiple Rich Text fields, but less does indeed seem to be more when it comes to managing user expectation of how dropping files should operate.

    Adam, September 2nd, 2010
  30. I should note it really doesn’t solve the affordance problem, it just seems to be what laypeople expect from my limited experience testing :]

    Adam, September 2nd, 2010
  31. @Adam – There’s nothing stopping you attaching a drop event on the body which will capture the drop no matter where the user drops it.

    The Css Ninja, September 2nd, 2010
  32. hey CSS Ninja, thought you might want to know that it seems Chrome version 6 now has the FileReader() class, but it might be incomplete because it says “Object #<a> has no method ‘addEventListener’”. any ideas why you can’t use addEventListener methods on FileReader objects?

    Michael Butler, September 15th, 2010
  33. @Michael B – Yep I filed a report on their bug tracker a while back, it’s still in their latest canary build also which is v7. However there is an easy work around, use DOM0 event listeners e.g. reader.onloadend = f(){} I did make the changes to my font drag web app so that will work in Chrome 6.

    The Css Ninja, September 15th, 2010
  34. Ninja, thanks for this tutorial. I’m using Firefox 3.6.10 and when I look at the response in firebug from the post/upload, I just see:
    Array
    (
    )

    I see that the file looks like it was posted correctly – is that response to be expected, or should there be content in that array? I’m seeing this both on your demo and on my test on my local machine. Thanks!

    Joe, September 22nd, 2010
  35. @Joe – If you take a look at this comment I link to another blog that delves into handling the data on the server side, I believe it needs to be handle differently than your normal file upload.

    The Css Ninja, September 22nd, 2010
  36. Perfect – that did the trick. Obviously, I missed that comment the first time though, so thanks for pointing it out!!

    Joe, September 23rd, 2010
  37. The code to POST to the upload.PHP does not appear to be correct as $_FILES is null with posted data.

    samuel elrod, September 24th, 2010
  38. @Samuel it’s very simple and has already been discussed. using the CSS Ninja style ajax upload, there will be no $_FILES array! On PHP, simply do $file_data = file_get_contents(‘php://input’); and you have the file data right there.

    Michael Butler, September 24th, 2010
  39. Wait where can you define where it is uploading the files? I have tried to use your script and it appears it’s working but doesn’t appear to upload the images anywhere on the server?

    sticky, October 17th, 2010
  40. @sticky – See here for handling the server side of uploaded images.

    The Css Ninja, October 18th, 2010
  41. Maybe you will be interested with new JS library, which can be used to add drag&drop upload files functionality which works on Firefox, Safari and Chrome: http://code.google.com/p/html5uploader/ It’s on one of open source licenses.

    Woj, November 9th, 2010
  42. Hey ninja Great Work here. Thank You.
    This is exactly what I need for an intranet app I am working on. However, I wanted to add the functionality of being able to keep adding pictures to the container. Right now if you drag for example 5 pictures, it previews all 5 pictures. And if you drag another 2 it previews only the last 2 I dragged. I wanted it so it keeps on adding them to the list, and also so that they could erase from it. I think that’s the only thing missing.
    Plus I am not uploading the pictures to the server, since all I want is the actual path of the pictures. (that’s taken care of)

    The example here let’s you keep adding pictures without removing the old ones: http://code.google.com/p/html5uploader/
    I looked thru both codes but I can’t figure out what to change in yours to make it work.

    Can you please guide me on how to do this.

    Thanks in advance.

    Robert, November 10th, 2010
  43. @Robert – That is an easy change. In the TCNDDU.setup() method I attach the dragenter event and in there I clear the drop area using dropListing.innerHTML = '';, just remove that line and images won’t be removed.

    The Css Ninja, November 10th, 2010
  44. Hey Ninja! Thanks for this great work, very neat!

    I have a question as to if it would be possible to pre-populate the dropContainer from file paths?

    I have an edit page where users should be able to see the pictures already loaded in the dropContainer.

    Is that possible or is that a security threat? I do have the correct file paths tho.

    Roberto, November 13th, 2010
  45. @Roberto – In short, no. That would be a huge security hole to look through a users filesystem without them knowing or giving permission to do so.

    The Css Ninja, November 16th, 2010
  46. Thanks for the quick response. I found a workaround the security issue by creating a virtual directory in my intranet mapping to the shared folder where all the images are located. So now I am able to get full URL paths to the images.
    But I still can’t figure out a way to pre-populate the images in the container.
    How should I go about doing this?

    Roberto, November 16th, 2010
  47. @Roberto – You can’t iterate over a file system even if you have the full URL path to the images. You would need some server-side code to let you know what files are in the images folder. Do an XHR get request to a webservice that scans the folder returns all the files in JSON. Iterate over the image names, create an img element and append path plus filename, lastly append the documentFragment to the document itself.

    The Css Ninja, November 16th, 2010
  48. This is amazing. Have you had a chance to try and get this working in Chrome or Safari since they support HTML5?

    Jmactacular, November 19th, 2010
  49. @Jmactacular – Chrome since version 6 has had support for the File API, only issue is that the FileReader object doesn’t support DOM2 event listeners so you’ll need to use DOM0 to get it working on chrome.

    The Css Ninja, November 21st, 2010
  50. Hi ninja! Great work.

    How would I go about uploading the files to a ftp server. I don’t know how to get the $_FILES[] global array since one doesn’t exist since you don’t use one, or do you?

    Well I need to upload the files to a ftp server using php, I need to be able to get the all the files from the $_FILES[] array once my form is submitted but I can’t see how to it with your implementation of drag and drop. Is it possible?

    Thank you

    Bob, December 8th, 2010
  51. @Bob – I’ve mentioned a few times in the comments of this article that goes into the serverside handling of the file upload. I’ve also updated the article to link to it.

    The Css Ninja, December 8th, 2010
  52. please give me a Demo code ,this code isn’t upload.php file

    luokai, January 4th, 2011
  53. Brilliant! thanks for the demo.
    File opens in IE and Chrome but works a treat in FF
    Thanks for all the links posts too will give it all a good read… then drop files directly to database through PHP.
    Perfect for my project with special needs kids THANKS

    droid, January 14th, 2011
  54. Hi Ninja,

    its really very cool functionalityand very good. I have implemented
    in one of my project.

    Still I got one problem.

    is there any limitation on the size of bytes on total files uploaded. If i upload total 7 files . each files are of more then 1 Mb size and seems like it does not upload the 7th file.

    and getBinaryDataReader.readAsBinaryString(file); gives error on upload. its exception error. so flow does not interrupted but the file was not uploaded.

    please suggest on this if you got any idea.

    Thanks

    Dipak Basantani, January 21st, 2011
  55. Hello There,
    Thanks for such a nice plug-in, this is what I am looking for, This plugin is working fine on firefox,but it does not working on other browsers, Could u please focus on the same, so that user can enjoy the plugin for other browser.


    Thanks & regrads
    Sarvesh

    Sarvesh, February 23rd, 2011
  56. Ryan: It works fine. However, the upload.php script does NOT see any $_POST variables. The script gets called, but the $_POST array is empty. Using production 3.6 browser.

    Thoughts?

    Larry

    Larry Bradley, February 27th, 2011
  57. @Larry B

    Should you not be accessing the $_FILES super global to access uploaded files?

    The Css Ninja, February 28th, 2011
  58. how I can get the data in a JSP instead of php,any comments

    manikavasakam, April 15th, 2011
  59. @manikavasakam

    Don’t know JSP so can’t help you there.

    The Css Ninja, April 21st, 2011
  60. Thank you very much for your the effort into this code, but please let me say that it is quite useless without a working upload.php file. I read the links you provided about and tried long to work it out, but without success. Many of us are not so proficiency in PHP to change the code to fit it into your example. So, meanwhile some guru publishes here a working upload.php, none of us will fully enjoy your code in our applications.

    Enrico, June 20th, 2011
  61. @Enrico

    If you read the comments you’ll see I mention *many* times where to find server side help.

    Ryan Seddon, June 24th, 2011
  62. tested the live demo on chrome 12.0.742.112/Win, there’s an error popped out on the devtool’s console, it says:

    Object # has no method ‘addEventListener’
    on: /demo/drag-drop_upload/v2/:114

    I think the latest File API don’t have addEventListener or something, but i’ve successfully implemented the same functionality using:

    FileReader.onloadend = function(){};

    and it works on chrome 12, FF4/5, and opera 11

    the only problem that I have is with readAsBinaryString on file larger than 100KB, the onloadend seems to never called, even after waiting for 10 minutes (yupz, i actually waited for that long …. @__@)

    as you might already know, i use readAsBinaryString for uploading to the server … but i never got a chance to upload anything, as everytime i try to readAsBinaryString it never ends … >.<

    would really appreciate some help, tried googling this, but doesn't seem to be anything to help me …

    in the meantime will try to slice the file for readAsBinaryString, it that's possible at all …

    cheers

    pilus, July 22nd, 2011
  63. I went through all the above post but your are redirecting to http://www.appelsiini.net/2009/10/html5-drag-and-drop-multiple-file-upload when ever some one asks for the server side script.

    I tried many ways with $_POST, $_FILES and then finally file_get_contents(“php://input”). $_POST and file_get_contents(“php://input”) are returning some data which is not giveing proper result when sent to image tag in PHP as below
    $file_data = file_get_contents(“php://input”);
    print “”;

    This is not useful for me until I store the posted data into server.

    If anyone have got success with PHP. Please paste the code in this thread.

    Thanks

    Praveen, July 29th, 2011
  64. @pilus

    Yes I too came across DOM2 event handling not working on FileReader, I filed a bug a long time ago but it still hasn’t been fixed.

    Haven’t come across your issue with readAsBinaryString not working. Do you have a testcase for this?

    Ryan Seddon, August 3rd, 2011
  65. Hi Ryan,

    Thanks so much for providing this demo. The code reads really well and is a great starting point I feel for many developers (including me) getting their head around the Drag and Drop capabilities.

    Keep up the great work.

    Anton Babushkin, August 4th, 2011
  66. Similar to your code i’ve came up with this
    http://www.ashantyk-design.com/dev-3-Upload%27em+JS

    I said similar because i pulled out the % loading thing because that shows the progress of the file being loaded into the browser, not the server and i put in a connection limit part with queueing.

    Also i extended the delete/cancel function. users can delete uploaded files after upload completion, using a session variable so they won’t delete any files that they didn’t uploaded (security reasons)

    Barbieru Gabriel, August 6th, 2011
  67. Hi Ninja!

    Great work! I was inspired by your drag and drop uploader so I rewrote it and optimized it to work also in chrome browser.

    The demo is on:

    http://www.ninja-scripts.com/demos/drag/

    and the uploaded files:

    http://www.ninja-scripts.com/demos/drag/files

    Regards,
    Nenad

    Nenad, November 23rd, 2011
  68. Can the demo work?

    Uncaught TypeError: Object # has no method ‘addEventListener’

    zero, December 1st, 2011
  69. @zero –

    There’s been a long standing bug in Chrome not supporting DOM2 event binding on FileReader().

    However you can use DOM0 event binding to get around in the mean time.

    Ryan Seddon, December 21st, 2011

Trackbacks

  1. [...] This post was Twitted by kilianbarrera [...]

    Twitted by kilianbarrera, August 7th, 2010
  2. [...] DropMocks : Image Hosting gratuito drag & drop DropMocks è un servizio di image hosting minimalista. DropMocks supporta il drag & drop e i soli Firefox e Google Chrome. DropMocks è un servizio minimalista di image hosting costruito in HTML 5. Il servizio non offre form per l’uplod, neppure il Flash Upload. L’utente che vuole caricare le foto online deve disporre di un Browser che supporta l’HTML 5 (Firefox e Chrome) e la funzione “file upload drag&drop”. (per maggiori info sulla funzione file upload si invita alla lettura del post di CSS Ninja intitolato “The File API has changed“). [...]

    DropMocks : Image Hosting gratuito drag & drop » Italia SW, September 30th, 2010
  3. [...] Being the web geek I am I had to figure out how it functioned. Firefox was easy and I have covered drag and drop uploading already. They also mentioned in their post that Chrome was supported but I know Chrome is yet to [...]

    TechMachi » How Gmail’s Drag and Drop of Attachment From Desktop Works, October 1st, 2010

Leave a comment