Как вы перебираете массив $_FILES?
Вот входы, которые я хочу выполнить через
Main photo: <input type="file" name="image[]" />
Side photo 1: <input type="file" name="image[]" />
Side photo 2: <input type="file" name="image[]" />
Side photo 3: <input type="file" name="image[]" />
Произошла пара странных вещей, когда я ничего не загружал, я использую count($_FILES['image'])
, я повторил эту функцию и вернул значение 5. В этом массиве не должно быть элементов. Почему есть один дополнительный вход, когда у меня есть только 4 файла?
Теперь с собственно циклизацией я пытаюсь использовать цикл foreach, но он не работает.
foreach($_FILES['image'] as $files){echo $files['name']; }
Ничего не получилось, что я в конечном итоге хотел бы сделать, это просмотреть все изображения, убедиться, что они являются правильным форматом, размером и переименовывают каждый из них. Но этот простой цикл foreach() показывает, что каким-то образом я не могу даже пропустить массив $_FILES, а count() еще больше смутил меня, когда он сказал, что в массиве есть 5 элементов, когда я даже ничего не загружал.
Ответы
Ответ 1
Ваша примерная форма должна работать нормально. Просто вы ожидаете, что структура суперклапана $_FILES
будет отличаться, чем на самом деле, при использовании структуры массива для имен полей.
Структура этого многомерного массива выполняется следующим образом:
$_FILES[fieldname] => array(
[name] => array( /* these arrays are the size you expect */ )
[type] => array( /* these arrays are the size you expect */ )
[tmp_name] => array( /* these arrays are the size you expect */ )
[error] => array( /* these arrays are the size you expect */ )
[size] => array( /* these arrays are the size you expect */ )
);
Для этого count( $_FILES[ "fieldname" ] )
даст 5
.
Но подсчет более глубоких измерений также не приведет к ожидаемому результату. Например, подсчет полей с помощью count( $_FILES[ "fieldname" ][ "tmp_name" ] )
всегда будет приводить к количеству полей файла, а не количеству загруженных файлов. Вам все равно придется перебирать элементы, чтобы определить, было ли что-либо загружено для определенного поля файла.
ИЗМЕНИТЬ
Итак, чтобы прокрутить поля, вы сделаете что-то вроде следующего:
// !empty( $_FILES ) is an extra safety precaution
// in case the form enctype="multipart/form-data" attribute is missing
// or in case your form doesn't have any file field elements
if( strtolower( $_SERVER[ 'REQUEST_METHOD' ] ) == 'post' && !empty( $_FILES ) )
{
foreach( $_FILES[ 'image' ][ 'tmp_name' ] as $index => $tmpName )
{
if( !empty( $_FILES[ 'image' ][ 'error' ][ $index ] ) )
{
// some error occured with the file in index $index
// yield an error here
return false; // return false also immediately perhaps??
}
/*
edit: the following is not necessary actually as it is now
defined in the foreach statement ($index => $tmpName)
// extract the temporary location
$tmpName = $_FILES[ 'image' ][ 'tmp_name' ][ $index ];
*/
// check whether it not empty, and whether it indeed is an uploaded file
if( !empty( $tmpName ) && is_uploaded_file( $tmpName ) )
{
// the path to the actual uploaded file is in $_FILES[ 'image' ][ 'tmp_name' ][ $index ]
// do something with it:
move_uploaded_file( $tmpName, $someDestinationPath ); // move to new location perhaps?
}
}
}
Для получения дополнительной информации см. документы.
Ответ 2
просто переименуйте свои поля таким образом
Main photo: <input type="file" name="image1" />
Side photo 1: <input type="file" name="image2" />
Side photo 2: <input type="file" name="image3" />
Side photo 3: <input type="file" name="image4" />
и вы сможете обычным образом повторить его:
foreach($_FILES as $file){
echo $file['name'];
}
Ответ 3
Короткая функция для восстановления $_FILES ['files'] в более ожидаемой структуре.
function restructureFilesArray($files)
{
$output = [];
foreach ($files as $attrName => $valuesArray) {
foreach ($valuesArray as $key => $value) {
$output[$key][$attrName] = $value;
}
}
return $output;
}
Ответ 4
Я придумал решение, которое работает для массивов $_FILES произвольной глубины. В качестве быстрого объяснения вам нужен алгоритм, который делает это:
For each subtree in the file tree that more than one item deep:
For each leaf of the subtree:
$leaf[a][b][c] ... [y][z] -> $result[z][a][b][c] ... [y]
Вот какой код действительно работает.
function sane_file_array($files) {
$result = array();
$name = array();
$type = array();
$tmp_name = array();
$error = array();
$size = array();
foreach($files as $field => $data) {
foreach($data as $key => $val) {
$result[$field] = array();
if(!is_array($val)) {
$result[$field] = $data;
} else {
$res = array();
files_flip($res, array(), $data);
$result[$field] += $res;
}
}
}
return $result;
}
function array_merge_recursive2($paArray1, $paArray2) {
if (!is_array($paArray1) or !is_array($paArray2)) { return $paArray2; }
foreach ($paArray2 AS $sKey2 => $sValue2) {
$paArray1[$sKey2] = array_merge_recursive2(@$paArray1[$sKey2], $sValue2);
}
return $paArray1;
}
function files_flip(&$result, $keys, $value) {
if(is_array($value)) {
foreach($value as $k => $v) {
$newkeys = $keys;
array_push($newkeys, $k);
files_flip($result, $newkeys, $v);
}
} else {
$res = $value;
// Move the innermost key to the outer spot
$first = array_shift($keys);
array_push($keys, $first);
foreach(array_reverse($keys) as $k) {
// You might think we'd say $res[$k] = $res, but $res starts out not as an array
$res = array($k => $res);
}
$result = array_merge_recursive2($result, $res);
}
}
Просто вызовите sane_files_array на $_FILES, и вам должно быть хорошо, независимо от глубины массива $_FILES. Это действительно должно быть частью самого языка, потому что форматирование массива $_FILES абсолютно нелепо.
Ответ 5
Может быть:
Main photo: <input type="file" name="image1" />
Side photo 1: <input type="file" name="image2" />
Side photo 2: <input type="file" name="image3" />
Side photo 3: <input type="file" name="image4" />
$i=1;
while (isset($_FILES['image'.$i])) {
print_r($_FILES['image'.$i]);
$i++;
}
Если вам нужно перебрать определенные поля файла.
Ответ 6
Выбор PHP для обработки $_FILES тратит много времени на разработку. Основываясь на ответе @Lendrick, вот аналогичный подход OO.
/**
* @brief get the POSTed files in a more usable format
Works on the following methods:
<form method="post" action="/" name="" enctype="multipart/form-data">
<input type="file" name="photo1" />
<input type="file" name="photo2[]" />
<input type="file" name="photo2[]" />
<input type="file" name="photo3[]" multiple />
* @return Array
* @todo
* @see http://stackoverflow.com/questions/5444827/how-do-you-loop-through-files-array
*/
public static function GetPostedFiles()
{
/* group the information together like this example
Array
(
[attachments] => Array
(
[0] => Array
(
[name] => car.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpe1fdEB
[error] => 0
[size] => 2345276
)
)
[jimmy] => Array
(
[0] => Array
(
[name] => 1.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpx1HXrr
[error] => 0
[size] => 221041
)
[1] => Array
(
[name] => 2 ' .jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpQ1clPh
[error] => 0
[size] => 47634
)
)
)
*/
$Result = array();
$Name = array();
$Type = array();
$TmpName = array();
$Error = array();
$Size = array();
foreach($_FILES as $Field => $Data)
{
foreach($Data as $Key => $Val)
{
$Result[$Field] = array();
if(!is_array($Val))
$Result[$Field] = $Data;
else
{
$Res = array();
self::GPF_FilesFlip($Res, array(), $Data);
$Result[$Field] += $Res;
}
}
}
return $Result;
}
private static function GPF_ArrayMergeRecursive($PaArray1, $PaArray2)
{
// helper method for GetPostedFiles
if (!is_array($PaArray1) or !is_array($PaArray2))
return $PaArray2;
foreach ($PaArray2 AS $SKey2 => $SValue2)
$PaArray1[$SKey2] = self::GPF_ArrayMergeRecursive(@$PaArray1[$SKey2], $SValue2);
return $PaArray1;
}
private static function GPF_FilesFlip(&$Result, $Keys, $Value)
{
// helper method for GetPostedFiles
if(is_array($Value))
{
foreach($Value as $K => $V)
{
$NewKeys = $Keys;
array_push($NewKeys, $K);
self::GPF_FilesFlip($Result, $NewKeys, $V);
}
}
else
{
$Res = $Value;
// move the innermost key to the outer spot
$First = array_shift($Keys);
array_push($Keys, $First);
foreach(array_reverse($Keys) as $K)
$Res = array($K => $Res); // you might think we'd say $Res[$K] = $Res, but $Res starts out not as an array
$Result = self::GPF_ArrayMergeRecursive($Result, $Res);
}
}
Ответ 7
Я боролся с этой дилеммой почти неделю! Ничто из того, что я нашел в сети, не могло мне помочь. Я знал, что делать, но не мог понять, как правильно перебирать массив $_FILES - до сих пор, когда я читал отредактированный пост принятого ответа.
Я внес некоторые изменения, хотя в script, как было опубликовано, так как он не работал должным образом для меня. Я хотел бы иметь возможность определить, был ли вообще выбран файл, поэтому я изменил строку
"if (! empty ($ _FILES ['image'] ['error'] [$ index]))"
в
"if (! empty ($ _FILES ['image'] ['size'] [$ index]))"
а затем вместо "return false;" вместо этого я вставляю размер в переменную:
"$ Size = $_FILES ['upload'] ['size'] [$ index];"
Таким образом, я мог проверить, была ли переменная $Size больше нуля. Если это так, то был выбран файл, и я мог бы продолжить подсчет количества файлов и фактическую загрузку. В принятом ответе я не использовал никаких "лишних" script после "return false;". Надеюсь, это поможет кому-то.
: P
/MacD