2011-03-26 86 views
16

下面是循环我想要的输入,通过

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个元素。

+6

您是否尝试过'的var_dump($ _ FILES)'?通过一些小小的调试,可以很快找出PHP正在做什么。 – Matthew 2011-03-26 20:20:45

回答

38

您的示例表单应该正常工作。这只是你期望的超级全局结构$_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 */) 
); 

THEREFOR count($_FILES[ "fieldname" ])将产生5
但计算更深的维度也不会产生您所期望的结果。以count($_FILES[ "fieldname" ][ "tmp_name" ])为例,计算字段总是会导致文件字段的数量,而不是实际上传的文件数量。您仍然需要遍历元素以确定是否已上传特定文件字段的任何内容。

编辑
因此,通过场循环,你会做类似如下:

// !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? 
     } 
    } 
} 

欲了解更多信息,请参阅the docs

+0

好吧,这是一个很好的解释,如何工作。那么我将如何循环访问每个文件输入?我认为最好的做法是给他们不同的名字(图像1,图像2,图像3)而不是图像[]? – Ben 2011-03-26 21:35:18

+0

@Ben“我认为最好的做法是[..]”不一定。我其实也喜欢用你原来的方法。我会用一个如何循环的例子来更新我的答案。 – 2011-03-26 21:38:29

+0

@Ben,我已经更新了我的答案。祝你好运。 – 2011-03-26 21:51:55

11

只需重命名字段这样

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']; 
} 
+0

如何计数($ _ FILES)不起作用,当字段为空时,结果为1.并且现在您可以通过使用image []输入的文件循环了。 – Ben 2011-03-26 20:14:57

+0

:好的,但是是什么引起了描述的行为? – 2011-03-26 20:15:18

+0

@Tomalak正在填充的方式数组。只需双击print_r($ _ FILES)'并查看。 – 2011-03-26 20:21:20

1

可能:

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

如果您必须遍历特定的文件字段。

2

我想出了一个适用于任意深度的$ _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] 

这是一些实际工作的代码。

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

只需调用$ _FILES sane_files_array,你应该是好去,不管$ _FILES数组有多深。这实际上应该是语言本身的一部分,因为$ _FILES数组的格式非常荒谬。

0

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

简短的函数重建$ _FILES ['文件']到一些更多的预期结构。

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

我已经挣扎了近一个星期的这种困境!我在网上找到的东西可以帮助我。我知道该怎么做,但无法弄清楚如何正确循环$ _FILES数组 - 直到现在,当我阅读已接受的答案的编辑后。

尽管我在发布的脚本中做了一些更改,但因为它无法正常工作。我希望能够确定文件是否被选中,所以我改变了行 “if(!empty($ _FILES ['image'] ['error'] [$ index]))” to “如果(!empty($ _FILES ['image'] ['size'] [$ index]))“ ,然后而不是”返回false“,我把大小放入一个变量: ”$ Size = $ _FILES ['upload'] ['size'] [$ index];“

这样我可以检查$ Size变量是否大于零。如果是,则选择一个文件,然后我可以继续计算文件数量并进行实际上传。在接受的答案中,我没有在“return false;”之后使用任何“不必要”的脚本。希望这可以帮助某人。

:P /霍尔德