I like the attempt by @Lendrick to reconstruct the array. I totally agree that the original $_FILES array is purely insane in PHP.
Alternative 1
I came up with this function that supports multidimensional arrays such as <input type="file" name="a[b][c]" />
/*
* Return a sane list of uploaded files
* @author tim-international.net
*/
function get_uploaded_files() {
$result = [];
foreach (preg_split('#&#', http_build_query($_FILES, '&'), -1, PREG_SPLIT_NO_EMPTY) as $pair) {
list($key, $value) = explode('=', $pair);
$key = urlencode(preg_replace('#^([^\[]+)\[(name|tmp_name|type|size|error)\](.*)$#', '$1$3[$2]', urldecode($key)));
$result[] = $key .'='. $value;
}
parse_str(implode('&', $result), $result);
return $result;
}
Example output for <input type="file" name="image[]" multiple />:
array(1) {
["image"]=>
array(1) {
[0]=>
array(5) {
["name"]=>
string(20) "My uploaded file1.png"
["type"]=>
string(9) "image/png"
["tmp_name"]=>
string(27) "C:\Windows\Temp\php6A8E1.tmp"
["error"]=>
int(0)
["size"]=>
int(26570)
}
[1]=>
array(5) {
["name"]=>
string(20) "My uploaded file2.png"
["type"]=>
string(9) "image/png"
["tmp_name"]=>
string(27) "C:\Windows\Temp\php6A8E2.tmp"
["error"]=>
int(0)
["size"]=>
int(26570)
}
}
}
Example of use:
$uploaded = get_uploaded_files();
foreach ($uploaded['image'] as $i => $file) {
move_uploaded_file($uploaded[$i]['tmp_name'], ...);
}
Alternative 2
Another variant which gives a more flattened array that can be handy is this:
function get_uploaded_files() {
$result = [];
foreach (preg_split('#&#', http_build_query($_FILES, '&'), -1, PREG_SPLIT_NO_EMPTY) as $pair) {
list($key, $value) = explode('=', $pair);
if (preg_match('#^([^\[]+)\[(name|tmp_name|type|size|error)\](.*)$#', urldecode($key), $matches)) {
$result[$matches[1].$matches[3]][$matches[2]] = urldecode($value);
}
}
return $result;
}
Which returns the following for <input type="file" name="foo[bar][]" multiple />:
array(1) {
["foo[bar][0]"]=>
array(5) {
["name"]=>
string(20) "My uploaded file1.png"
["type"]=>
string(9) "image/png"
["tmp_name"]=>
string(27) "C:\Windows\Temp\php6A8E1.tmp"
["error"]=>
int(0)
["size"]=>
int(26570)
}
["foo[bar][1]"]=>
array(5) {
["name"]=>
string(20) "My uploaded file2.png"
["type"]=>
string(9) "image/png"
["tmp_name"]=>
string(27) "C:\Windows\Temp\php6A8E2.tmp"
["error"]=>
int(0)
["size"]=>
int(26570)
}
}
}
Example of use:
foreach (get_uploaded_files() as $field => $file) {
move_uploaded_file($file['tmp_name'], ...);
}
var_dump($_FILES)? A little debugging goes a long way to figuring out what PHP is doing.