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!