multiple file uploads using HTML5

As a response to a reported bug where Chrome was taking ages to load up a flash multiple-file uploader, I’ve updated KFM to use HTML5′s multiple-file input box where possible.

To do this, first create the element:

  var input=document.createElement('input');
  input.type='file'; // use old-style JavaScript method to make sure all browsers respect it
  input.name='kfm_file';

Notice that we’re not using setAttribute to set the type and name – that’s a DOM method which works in most browsers but not (of course…) in Internet Explorer 6, where it has bugs.

And now, we tell the input to use the multiple-upload method. We use .setAttribute in this case because we only expect newer browsers to succeed with it.

  input.setAttribute('multiple','multiple');
  if(input.multiple)input.name='kfm_file[]';

In the second line, we check to see if the element is now marked as a multiple-uploader (most current browsers will not succeed in this), and if it does, then rename the input element by adding a [] to the end. If this is not done, then the server will only see the first file which is uploaded.

That’s the client-side done. This will only be visible in newer browsers such as Chrome, Safari 4, Firefox 3.6. I expect Internet Explorer will eventually catch up by 2020 or so.

If you’re doing this in pure HTML, then I suppose this would be good enough for you:

<input type="file" multiple="multiple" name="kfm_file[]"/>

In this case, you must put the [] in the name in all cases.

On the server-side, you need to write your upload receiver to expect either a single element, or an array.

For some really goddamned stupid reason, when multiple files are uploaded to PHP, the results are interlaced in a really crappy and awkward manner (I don’t like it).

Instead of something logical and easy to use, like this:

array(
  [0] => array(
    'name'     => 'file1.txt',
    'tmp_name' => '/tmp/abcdef'
    ....
  ),
  [1] => array(
    'name'     => 'file2.txt',
    'tmp_name' => '/tmp/ghijkl'
    ....
  )
);

You get this…

array(
  'name' => array(
    [0] => 'file1.txt',
    [1] => 'file2.txt'
  ),
  'tmp_name' => array(
    [0] => '/tmp/abcdef',
    [1] => '/tmp/ghijkl'
  ),
  ...
);

While that looks at first glance to be easy to use, it’s not. You can’t do a simple “foreach($_FILES['kfm_file'] as $file)” and expect the above to be usable at all…

So, the first thing I do, is to check for the $_FILES['kfm_file'], and convert it into the first form above, which is very easy to work with:

$files=array();
$fdata=$_FILES['kfm_file'];
if(is_array($fdata['name'])){
 for($i=0;$i<count($fdata['name']);++$i){
  $files[]=array(
   'name'     => $fdata['name'][$i],
   'tmp_name' => $fdata['tmp_name'][$i],
  );
 }
}
else $files[]=$fdata;

In my own case, I’m only interested in the name and tmp_name variables, so that’s all I set up.

Now you can do a foreach on $files and treat them all individually.

foreach ($files as $file) {
  // uploaded location of file is $file['tmp_name']
  // original filename of file is $file['name']
}

If you want to see this in KFM, have a look at the nightly-updated demo tomorrow, or download from SVN right now.

oh – and buy my book!

18 Thoughts on “multiple file uploads using HTML5

  1. Pingback: ??????? » [Web] ????

  2. Pingback: Death to Flash | Guild Media

  3. Pingback: Webworks Blog » Blog Archive » KFM 1.4.6 released

  4. In regards to your PHP, why can’t you do a simple foreach()?


    foreach($fdata as $i => $d){
    ...
    }

  5. John – as I said in the article, when you get the initial array, you can’t simply foreach the $fdata because it’s not an array of files – it’s an array of file attributes (name, tmpname, etc).

    try it and see…

    • Still, why not?
      foreach ($fdata as $i => $d) {
      $files[] = array(
      'name' => $d,
      'tmp_name' => $fdata['tmp_name'][$i] // nasty comma
      );
      }

      • Sorry, wrong :oops:

        foreach ($fdata['name'] as $i => $d) {
        $files[] = array(
        'name' => $d,
        'tmp_name' => $fdata['tmp_name'][$i]
        );
        }

        That’s better.

        • Kae Verens on November 6, 2011 at 10:39 am said:

          ah! I misunderstood the original “why can’t you use foreach()” as being about the original array.

          yes, good point. in fact, I’ve no idea why I used for() – maybe I was tired when I wrote it ;-)

  6. Chris on May 13, 2011 at 9:58 pm said:

    Shouldn’t that be $file['name'] instead of $file['file'] ?

  7. admin on May 31, 2011 at 2:57 pm said:

    thanks Chris – corrected.

  8. how name=”file[]”
    is link with kmp_file

  9. Kae Verens on October 6, 2011 at 1:21 pm said:

    deepak – that should be name=”kfm_file[]”

    thanks. corrected.

  10. I must ask: why is this so complicated? I’m missing a point, why do you put name for input “kfm_file” (without brackets) in the first place. Whether the “multiple” argument is supported or not, you only operate on array, which make the code so much simpler, either JavaScript or PHP. Also you could use foreach loop as stated above.

    Unless I missed some use cases in which those steps are required, then it could make sense.

    Cheers.

  11. can just do whatever I want for the files in the first ‘for’ and save the ‘foreach’?

  12. Kae Verens on November 6, 2011 at 10:43 am said:

    for the last two posters; i wrote this article because I was doing a HTML5 multiple file upload for KFM (a file manager), so that’s why “kfm” is in the input. Of course, you could do this whatever way you want.

    The point of the article was to illustrate how to convert PHP’s file upload array into something useful.

    Pat, do it whatever way you want!

    pepkin88′s foreach example in the comments above is more efficient and easier to read than what I did in the post.

  13. for($i=0;$i<count($fdata['name']);++$i){
    в процессе цикла пересчитывать количество элементов смешно. также могут элементы пропущенны. используйте foreach

  14. thanx! you should left html4, use 5 instead for uploading multiple files at once

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Post Navigation