various tag multiple move_uploaded_file images files ejemplo attribute array php loops input foreach form-processing

php - tag - ¿Cómo recorres la matriz $_FILES?



title html attribute (7)

¡He luchado con este dilema durante casi una semana! Nada de lo que encontré en la red podría ayudarme. Sabía qué hacer, pero no sabía cómo hacer un bucle a través de la matriz $ _FILES correctamente, hasta ahora cuando leí la publicación editada de la respuesta aceptada.

Sin embargo, hice algunos cambios en el guión como se publicó, ya que no funcionó correctamente para mí. Quería poder determinar si se seleccionó un archivo, así que cambié la línea "if (! Empty ($ _FILES [''image''] [''error''] [$ index]))" a "if (! vacío ($ _FILES [''imagen''] [''tamaño''] [$ índice])) "y luego en lugar de" devolver falso ", pongo el tamaño en una variable:" $ Tamaño = $ _FILES [''subir'' ] [''tamaño''] [$ índice]; "

De esta manera podría comprobar si la variable $ Size era mayor que cero. Si lo era, entonces se había seleccionado un archivo y podría continuar contando la cantidad de archivos y hacer la carga real. No utilicé ninguno de los guiones "innecesarios" después de "devolver falso", en la respuesta aceptada. Espero que esto ayude a alguien.

: P / MacD

Aquí están las entradas que quiero recorrer

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[]" />

Ocurrieron un par de cosas extrañas, cuando cargué nada, uso el count($_FILES[''image'']) , hice eco de esa función y devolvió un valor de 5. No debería haber elementos en esa matriz. ¿Por qué hay una entrada adicional cuando solo tengo 4 archivos para empezar?

Ahora, con el bucle en sí mismo, trato de usar el bucle foreach, pero no funciona.

foreach($_FILES[''image''] as $files){echo $files[''name'']; }

No surgió nada, lo que quería hacer en última instancia es recorrer todas las imágenes, asegurarme de que tengan el formato, el tamaño y el nombre correctos de cada una de ellas. Pero este simple bucle foreach () muestra que de alguna manera ni siquiera puedo recorrer la matriz $ _FILES y el conteo () me confundió aún más cuando dice que hay 5 elementos en la matriz cuando ni siquiera cargué nada.


Función corta para reconstruir $ _FILES [''archivos''] a una estructura más esperada.

function restructureFilesArray($files) { $output = []; foreach ($files as $attrName => $valuesArray) { foreach ($valuesArray as $key => $value) { $output[$key][$attrName] = $value; } } return $output; }


La elección de PHP de cómo manejar $ _FILES desperdicia mucho tiempo de desarrollador. Basado en la respuesta de @Lendrick, aquí hay un enfoque OO similar.

/** * @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://.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); } }


Se me ocurrió una solución que funciona para arrays $ _FILES de profundidad arbitraria. Como explicación rápida, lo que necesita un algoritmo que haga esto:

For each subtree in the file tree that''s more than one item deep: For each leaf of the subtree: $leaf[a][b][c] ... [y][z] -> $result[z][a][b][c] ... [y]

Aquí hay un código que realmente funciona.

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); } }

Simplemente llama a sane_files_array en $ _FILES y deberías estar listo, independientemente de la profundidad de la matriz $ _FILES. Esto realmente debería ser parte del lenguaje en sí, porque el formato de la matriz $ _FILES es absolutamente ridículo.


Tal vez:

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++; }

Si tienes que recorrer campos de archivo específicos.


Tu formulario de ejemplo debería funcionar bien. Es solo que está esperando que la estructura de $_FILES superglobal sea diferente de lo que realmente es, cuando se usa una estructura de matriz para los nombres de campo.

La estructura de esta matriz multidimensional es la siguiente:

$_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 */ ) );

Por lo tanto, la count( $_FILES[ "fieldname" ] ) producirá 5 .
Pero contar dimensiones más profundas tampoco producirá el resultado que puede esperar. Si cuenta los campos con count( $_FILES[ "fieldname" ][ "tmp_name" ] ) por ejemplo, siempre resultará en la cantidad de campos de archivo, no en la cantidad de archivos que realmente se han cargado. Aún tendría que recorrer los elementos para determinar si se ha cargado algo para un campo de archivo en particular.

EDITAR
Entonces, para recorrer los campos harías algo como lo siguiente:

// !empty( $_FILES ) is an extra safety precaution // in case the form''s 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''s 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? } } }

Para más información ver los documentos .


simplemente renombra tus campos de esta manera

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" />

y luego podrás iterarlo de la manera habitual:

foreach($_FILES as $file){ echo $file[''name'']; }