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!
Comments