php 你如何遍历 $_FILES 数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5444827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you loop through $_FILES array?
提问by Ben
Here are the inputs I want to loop through
这是我想要循环的输入
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[]" />
A couple weird things happened, when I uploaded nothing I use the count($_FILES['image'])
, I echoed that function, and it returns a value of 5. There should be no elements in that array. Why is there one extra input when I only have 4 files to begin with?
发生了一些奇怪的事情,当我没有上传任何东西时,我使用了 count($_FILES['image'])
,我回显了该函数,它返回了 5 的值。该数组中应该没有元素。当我只有 4 个文件时,为什么会有一个额外的输入?
Now with the actually looping itself, I try using the foreach loop, but it doesn't work.
现在实际循环本身,我尝试使用 foreach 循环,但它不起作用。
foreach($_FILES['image'] as $files){echo $files['name']; }
Nothing came up, what I wanted to ultimately do is to loop through all images, make sure they are correct format, size, and rename each of them. But this simple foreach() loop shows that somehow I can't even loop through the $_FILES array and the count() confused me even more when it say that there are 5 elements in the array when I didn't even upload anything.
什么都没出现,我最终想做的是遍历所有图像,确保它们的格式、大小正确,并重命名每个图像。但是这个简单的 foreach() 循环表明,不知何故,我什至无法遍历 $_FILES 数组,而当我什至没有上传任何内容时,当它说数组中有 5 个元素时,count() 使我更加困惑。
回答by Decent Dabbler
Your example form should work fine. It's just that you are expecting the structure of the $_FILES
superglobal to be different than it actually is, when using an array structure for the field names.
您的示例表单应该可以正常工作。只是$_FILES
在对字段名称使用数组结构时,您期望超全局的结构与实际不同。
The structure of this multidimensional array is as followed then:
这个多维数组的结构如下:
$_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 */ )
);
Therefor count( $_FILES[ "fieldname" ] )
will yield 5
.
But counting deeper dimensions will also not produce the result you may expect. Counting the fields with count( $_FILES[ "fieldname" ][ "tmp_name" ] )
for instance, will always result in the number of file fields, not in the number of files that have actually been uploaded. You'd still have to loop through the elements to determine whether anything has been uploaded for a particular file field.
因此count( $_FILES[ "fieldname" ] )
会屈服5
。
但是计算更深的维度也不会产生您可能期望的结果。count( $_FILES[ "fieldname" ][ "tmp_name" ] )
例如,对字段进行计数,将始终得到文件字段的数量,而不是实际上传的文件数量。您仍然需要遍历元素以确定是否已为特定文件字段上传任何内容。
EDIT
So, to loop through the fields you would do something like the following:
编辑
因此,要遍历字段,您将执行以下操作:
// !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?
}
}
}
For more information see the docs.
有关更多信息,请参阅文档。
回答by Your Common Sense
just rename your fields this way
只需以这种方式重命名您的字段
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" />
and then you'll be able to iterate it usual way:
然后你就可以用通常的方式迭代它:
foreach($_FILES as $file){
echo $file['name'];
}
回答by j4r3k
Short function to rebuild $_FILES['files'] to some more expected structure.
将 $_FILES['files'] 重建为一些更预期的结构的简短函数。
function restructureFilesArray($files)
{
$output = [];
foreach ($files as $attrName => $valuesArray) {
foreach ($valuesArray as $key => $value) {
$output[$key][$attrName] = $value;
}
}
return $output;
}
回答by Lendrick
I came up with a solution that works for $_FILES arrays of arbitrary depth. As a quick explanation, what you need an algorithm that does this:
我想出了一个适用于任意深度的 $_FILES 数组的解决方案。作为快速解释,您需要一个执行此操作的算法:
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]
Here's some code that actually works.
这是一些实际有效的代码。
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);
}
}
Just call sane_files_array on $_FILES and you should be good to go, regardless of how deep the $_FILES array is. This really should be part of the language itself, because the formatting of the $_FILES array is absolutely ridiculous.
只需在 $_FILES 上调用 sane_files_array 就可以了,无论 $_FILES 数组有多深,您都应该很高兴。这真的应该是语言本身的一部分,因为 $_FILES 数组的格式绝对是荒谬的。
回答by woodgate
Maybe:
也许:
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++;
}
If you have to loop through specific file fields.
如果您必须遍历特定的文件字段。
回答by carrucha
PHP's choice of how to handle $_FILES wastes a lot of developer time. Based on @Lendrick's answer, here is a similar OO approach.
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);
}
}
回答by tvanc
I'm way late to the game for this answer but I got tired of solving the problem of dealing with the PHP files array over and over, so I wrote a composer package so I'd never have to again. Maybe someone googling will find my answer and be happy.
对于这个答案,我已经迟到了,但是我厌倦了一遍又一遍地解决 PHP 文件数组的问题,所以我编写了一个 composer 包,这样我就再也不用了。也许有人谷歌搜索会找到我的答案并感到高兴。
Install tvanc/files-array-organizer
安装 tvanc/files-array-organizer
composer require tvanc/files-array-organizer
Pass $_FILES
to it, and it'll give you back an array that's structured the way you were expecting.
传递$_FILES
给它,它会给你一个按照你期望的方式构造的数组。
<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;
require 'vendor/autoload.php';
if ($_FILES) {
$organizedFiles = FilesArrayOrganizer::organize($_FILES);
// Now you can foreach over your files
foreach($organizedFiles['image'] as $file){
echo $file['name'];
}
}
?>
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[]" />
回答by MacDknife
I have struggled with this dilemma for almost a week! Nothing I found on the net could help me. I knew sort of what to do, but could not figure out how to loop through the $_FILES array properly - until now when I read the edited post of the accepted answer.
我已经在这个困境中挣扎了将近一个星期!我在网上找到的任何东西都无法帮助我。我知道该怎么做,但无法弄清楚如何正确遍历 $_FILES 数组 - 直到现在我阅读已接受答案的编辑帖子。
I made some changes though, in the script as posted, as it did not work properly for me. I wanted to be able to determine if a file was selected at all, so I changed the line "if( !empty( $_FILES[ 'image' ][ 'error' ][ $index ] ) )" to "if( !empty( $_FILES[ 'image' ][ 'size' ][ $index ] ) )" and then instead of "return false;", I put the size into a variable instead: "$Size = $_FILES[ 'upload' ][ 'size' ][ $index ];"
不过,我在发布的脚本中做了一些更改,因为它对我来说不能正常工作。我希望能够确定一个文件是否被选中,所以我将“if(!empty($_FILES['image']['error'][$index]))”改为“if(!empty($_FILES['image']['error'][$index]))”。 empty( $_FILES[ 'image' ][ 'size' ][ $index ] ) )”,然后不是“return false;”,而是将大小放入变量中:“$Size = $_FILES[ 'upload' ][ '大小' ][ $index ];"
This way I could check if the $Size variable was larger than zero. If it was, then a file had been selected and I could continue with counting the number of files and do the actual upload. I did not use any of the "unnecessary" script after "return false;", in the accepted answer. Hope this helps someone.
这样我就可以检查 $Size 变量是否大于零。如果是,那么已经选择了一个文件,我可以继续计算文件数量并进行实际上传。在接受的答案中,我没有在“return false;”之后使用任何“不必要的”脚本。希望这可以帮助某人。
: P /MacD
:P /MacD