Меня всегда мучал вопрос по поводу того, почему так устроен массив $_FILES в PHP, точнее то, почему он очень странным образом формирует его. В случае, если имена полей формы оформлены с использованием синтаксиса массива, $_REQUEST, $_GET или $_POST будут содержать правильное представление, но… такое использование не подходит для $_FILES!
Имеем форму:
При загрузке файлов через эту форму получаем массив $_FILES следующего вида:
Мне эта «фича» в большинстве случаев не подходит и кажется нелогичной. Простейшее решение — использовать простые (строковые) имена для полей типа «файл», например file_0, file_1, ..., file_N, но это не так удобно. Если, все-таки, вас интересует решение этой проблемы — читаем далее…
В autoprepend-файле или где-нибудь в момент инициализации вашего приложения стоит обработать массив $_FILE следующим образом:
В итоге имеем более «логичный» миссив:
Разместил это решение комментарием в официальной документации, т.к. вопросов много, а конкретного примера нет. Но, на момент публикации здесь его там пока ещё не появилось (не знаю, появится ли?).
Спасибо за внимание, надеюсь кому-нибудь пригодится.
UPD: Глядя на то, как мои слова «В autoprepend-файле или где-нибудь в момент инициализации вашего приложения стоит обработать массив $_FILE» и перезапись в коде массива $_FILES вызвали некоторое негодование некоторой части сообщества, заявляю: это пример того, как можно реализовать необходимый функционал, и я не призываю использовать данный код «как есть» в боевых проектах.
Проблема
Имеем форму:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="oneLevel[]">
<input type="file" name="oneLevel[]">
<input type="submit">
</form>
При загрузке файлов через эту форму получаем массив $_FILES следующего вида:
array(
'files' => array (
'name' => array (
0 => 'Lighthouse.jpg',
1 => 'Hydrangeas.jpg',
),
'type' => array (
0 => 'image/jpeg',
1 => 'image/jpeg',
),
'tmp_name' => array (
0 => '/tmp/phpQR67Qp',
1 => '/tmp/phpJjnAHA',
),
'error' => array (
0 => 0,
1 => 0,
),
'size' => array (
0 => 561276,
1 => 595284,
),
),
)
Мне эта «фича» в большинстве случаев не подходит и кажется нелогичной. Простейшее решение — использовать простые (строковые) имена для полей типа «файл», например file_0, file_1, ..., file_N, но это не так удобно. Если, все-таки, вас интересует решение этой проблемы — читаем далее…
Решение
В autoprepend-файле или где-нибудь в момент инициализации вашего приложения стоит обработать массив $_FILE следующим образом:
/**
* Рекурсивная функция для реструктуризации массива
*
* @param array $arrayForFill Массив для заполнения.
* Этот массив будет содержать "правильное"
* представление $_FILES
* @param string $currentKey Ключ текущей позиции
* @param mixed $currentMixedValue Значение текущей позиции
* @param string $fileDescriptionParam Текущий параметр описания файла
* (name, type, tmp_name, error или size)
* @return void
*/
function rRestructuringFilesArray(&$arrayForFill, $currentKey,
$currentMixedValue, $fileDescriptionParam)
{
if (is_array($currentMixedValue)) {
foreach ($currentMixedValue as $nameKey => $mixedValue) {
rRestructuringFilesArray($arrayForFill[$currentKey],
$nameKey,
$mixedValue,
$fileDescriptionParam);
}
} else {
$arrayForFill[$currentKey][$fileDescriptionParam] = $currentMixedValue;
}
}
// массив, в котором будем формировать "правильный" $_FILES
$arrayForFill = array();
// первый уровень проходим без изменения
foreach ($_FILES as $firstNameKey => $arFileDescriptions) {
// а вот со второго уровня интерпритатор делает то,
// что мне в большинстве случаев не подходит
foreach ($arFileDescriptions as $fileDescriptionParam => $mixedValue) {
rRestructuringFilesArray($arrayForFill,
$firstNameKey,
$_FILES[$firstNameKey][$fileDescriptionParam],
$fileDescriptionParam);
}
}
// перегружаем $_FILES сформированным массивом
$_FILES = $arrayForFill;
В итоге имеем более «логичный» миссив:
array(
'files' => array (
0 => array (
'name' => 'Lighthouse.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpKNqlsc',
'error' => 0,
'size' => 561276,
),
1 => array (
'name' => 'Hydrangeas.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpB8X3E8',
'error' => 0,
'size' => 595284,
),
),
)
Разместил это решение комментарием в официальной документации, т.к. вопросов много, а конкретного примера нет. Но, на момент публикации здесь его там пока ещё не появилось (не знаю, появится ли?).
Спасибо за внимание, надеюсь кому-нибудь пригодится.
UPD: Глядя на то, как мои слова «В autoprepend-файле или где-нибудь в момент инициализации вашего приложения стоит обработать массив $_FILE» и перезапись в коде массива $_FILES вызвали некоторое негодование некоторой части сообщества, заявляю: это пример того, как можно реализовать необходимый функционал, и я не призываю использовать данный код «как есть» в боевых проектах.