28 Dec

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!

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

        • 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 😉

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

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

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

  8. Pingback: HTML 5 multi file upload with PHP - QuestionFocus

  9. Pingback: HTML 5 multi file upload with PHP – w3toppers.com

Leave a Reply to adminCancel reply