【问题标题】:How do you loop through $_FILES array?你如何遍历 $_FILES 数组?
【发布时间】:2011-07-23 14:57:06
【问题描述】:

这是我要循环的输入

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 数组,而当我什至没有上传任何内容时,当它说数组中有 5 个元素时,count() 让我更加困惑。

【问题讨论】:

  • 你试过var_dump($_FILES)吗?一点点调试对于弄清楚 PHP 正在做什么大有帮助。

标签: php loops input foreach form-processing


【解决方案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" />

然后你就可以像往常一样迭代它了:

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

【讨论】:

  • 怎么 count($_FILES) 不起作用,当该字段为空时,结果为 1。并且您无法循环使用 image[] 输入的文件???
  • :好的,但是是什么导致了所描述的行为?
  • @Tomalak 填充数组的方式。只需print_r($_FILES) 两种方式,看看。
  • @Ben 实际上你可以,但只是另一种方式。 count($_FILES) 不起作用,您必须改为检查 error 元素
  • :我的意思是你的回答应该解释它。
【解决方案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" />

$i=1;
while (isset($_FILES['image'.$i])) {
    print_r($_FILES['image'.$i]);
    $i++;
}

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

【讨论】:

    【解决方案3】:

    您的示例表单应该可以正常工作。只是您期望$_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'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

    【讨论】:

    • 好的,这很好地解释了它是如何工作的。那么我将如何遍历每个文件输入呢?我想最好的做法是给他们不同的名字(图像 1、图像 2、图像 3)而不是图像 []?
    • @Ben “我想最好的做法是 [..]” 不一定。我实际上也喜欢使用您的原始方法。我将用一个如何循环的例子来更新我的答案。
    • 我可以看到你要去哪里,我对 php 还是很陌生,两个快速的问题。 !empty($_FILES) 是否考虑所有文件输入?那么如果一个文件是空的,它不会执行代码吗?我很难理解 foreach() 中的条件语句,尤其是 ($index => $tmpName) 部分,你能解释一下这是什么意思吗?非常感谢。
    • @Ben:总是很高兴帮助那些真正想了解代码实际工作原理的人,而不是盲目地复制。 :)
    • 这个示例循环很危险,因为它假设至少有 2 个上传文件。如果是一个文件,$_FILES['attachment']['name'] 是一个字符串,因此 $_FILES['attachment']['name'][0] 将是名称的第一个字符。
    【解决方案4】:

    我想出了一个适用于任意深度的 $_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 数组的格式非常荒谬。

    【讨论】:

      【解决方案5】:

      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['files'] 重建为更多预期结构的短函数。

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

        【讨论】:

          【解决方案7】:

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

          我在发布的脚本中做了一些更改,因为它对我来说不能正常工作。我希望能够确定是否选择了文件,所以我更改了行 “如果(!empty($_FILES['image']['error'][$index]))” 到 “如果(!empty($_FILES['image']['size'][$index]))” 然后不是“return false;”,而是将大小放入一个变量中: "$Size = $_FILES[ '上传' ][ '大小' ][ $index ];"

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

          :P /麦克德

          【讨论】:

            【解决方案8】:

            我迟到了这个答案,但我厌倦了一遍又一遍地解决处理 PHP 文件数组的问题,所以我写了一个作曲家包,所以我再也不用这样做了。也许有人在谷歌上搜索会找到我的答案并很高兴。

            安装tvanc/files-array-organizer

            composer require tvanc/files-array-organizer
            

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

            【讨论】:

              【解决方案9】:

              我喜欢@Lendrick 尝试重建数组。我完全同意原始的 $_FILES 数组在 PHP 中纯粹是疯狂的。

              备选方案 1

              我想出了这个支持&lt;input type="file" name="a[b][c]" /&gt;等多维数组的函数

                /*
                 * Return a sane list of uploaded files
                 * @author tim-international.net
                 */
                function get_uploaded_files() {
              
                  $result = [];
                  foreach (preg_split('#&#', http_build_query($_FILES, '&'), -1, PREG_SPLIT_NO_EMPTY) as $pair) {
                    list($key, $value) = explode('=', $pair);
                    $key = urlencode(preg_replace('#^([^\[]+)\[(name|tmp_name|type|size|error)\](.*)$#', '$1$3[$2]', urldecode($key)));
                    $result[] = $key .'='. $value;
                  }
              
                  parse_str(implode('&', $result), $result);
              
                  return $result;
                }
              

              &lt;input type="file" name="image[]" multiple /&gt; 的示例输出:

              array(1) {
                ["image"]=>
                array(1) {
                  [0]=>
                  array(5) {
                    ["name"]=>
                    string(20) "My uploaded file1.png"
                    ["type"]=>
                    string(9) "image/png"
                    ["tmp_name"]=>
                    string(27) "C:\Windows\Temp\php6A8E1.tmp"
                    ["error"]=>
                    int(0)
                    ["size"]=>
                    int(26570)
                  }
                  [1]=>
                  array(5) {
                    ["name"]=>
                    string(20) "My uploaded file2.png"
                    ["type"]=>
                    string(9) "image/png"
                    ["tmp_name"]=>
                    string(27) "C:\Windows\Temp\php6A8E2.tmp"
                    ["error"]=>
                    int(0)
                    ["size"]=>
                    int(26570)
                  }
                }
              }
              

              使用示例:

              $uploaded = get_uploaded_files();
              foreach ($uploaded['image'] as $i => $file) {
                move_uploaded_file($uploaded[$i]['tmp_name'], ...);
              }
              

              备选方案 2

              另一个可以方便地提供更扁平数组的变体是:

                function get_uploaded_files() {
              
                  $result = [];
              
                  foreach (preg_split('#&#', http_build_query($_FILES, '&'), -1, PREG_SPLIT_NO_EMPTY) as $pair) {
                    list($key, $value) = explode('=', $pair);
                    
                    if (preg_match('#^([^\[]+)\[(name|tmp_name|type|size|error)\](.*)$#', urldecode($key), $matches)) {
                      $result[$matches[1].$matches[3]][$matches[2]] = urldecode($value);
                    }
                  }
              
                  return $result;
                }
              

              它为&lt;input type="file" name="foo[bar][]" multiple /&gt; 返回以下内容:

              array(1) {
                ["foo[bar][0]"]=>
                  array(5) {
                    ["name"]=>
                    string(20) "My uploaded file1.png"
                    ["type"]=>
                    string(9) "image/png"
                    ["tmp_name"]=>
                    string(27) "C:\Windows\Temp\php6A8E1.tmp"
                    ["error"]=>
                    int(0)
                    ["size"]=>
                    int(26570)
                  }
                  ["foo[bar][1]"]=>
                  array(5) {
                    ["name"]=>
                    string(20) "My uploaded file2.png"
                    ["type"]=>
                    string(9) "image/png"
                    ["tmp_name"]=>
                    string(27) "C:\Windows\Temp\php6A8E2.tmp"
                    ["error"]=>
                    int(0)
                    ["size"]=>
                    int(26570)
                  }
                }
              }
              

              使用示例:

              foreach (get_uploaded_files() as $field => $file) {
                move_uploaded_file($file['tmp_name'], ...);
              }
              

              【讨论】:

                【解决方案10】:

                如果你不能加入他们就打败他们。

                https://gist.github.com/noorwachid/fce70a3a2d96502c2805248c46fc23f9

                <?php
                
                class UploadedFile 
                {
                    public static function walk(&$originalPath, &$path, &$contentType, &$size, &$errorCode)
                    {
                        if (is_array($originalPath)) {
                            foreach ($originalPath as $key => &$value)
                                self::walk($value, $path[$key], $contentType[$key], $size[$key], $errorCode[$key]);
                        } else {
                            $originalPath = [
                                'originalPath' => $originalPath,
                                'path' => $path,
                                'contentType' => $contentType,
                                'size' => $size,
                                'errorCode' => $errorCode,
                            ];
                        }
                    }
                
                    public static function build()
                    {
                        // swap second keys
                        $rootNode = [];
                        foreach ($_FILES as $key => $value) {
                            foreach ($value as $key2 => $value2) {
                                $rootNode[$key2][$key] = $value2;
                            }
                        }
                
                        // swap first and last keys
                        self::walk($rootNode['name'], $rootNode['tmp_name'], $rootNode['type'], $rootNode['size'], $rootNode['error']);
                        
                        // remove unused keys
                        unset($rootNode['tmp_name']);
                        unset($rootNode['type']);
                        unset($rootNode['size']);
                        unset($rootNode['error']);
                        
                        return $rootNode['name'];
                    }
                }
                
                // original
                print_r($_FILES);
                
                // restructured
                print_r(UploadedFile::build());
                
                // original
                Array
                (
                    [one] => Array
                        (
                            [name] => ss_break.png
                            [type] => image/png
                            [tmp_name] => /tmp/phppY8lSV
                            [error] => 0
                            [size] => 43582
                        )
                
                    [multiple] => Array
                        (
                            [name] => Array
                                (
                                    [0] => LeleBreeder.png
                                )
                
                            [type] => Array
                                (
                                    [0] => image/png
                                )
                
                            [tmp_name] => Array
                                (
                                    [0] => /tmp/php6GSj1X
                                )
                
                            [error] => Array
                                (
                                    [0] => 0
                                )
                
                            [size] => Array
                                (
                                    [0] => 14284
                                )
                
                        )
                
                    [crazy] => Array
                        (
                            [name] => Array
                                (
                                    [nested] => Array
                                        (
                                            [keys] => PlainUbuntu.png
                                        )
                
                                )
                
                            [type] => Array
                                (
                                    [nested] => Array
                                        (
                                            [keys] => image/png
                                        )
                
                                )
                
                            [tmp_name] => Array
                                (
                                    [nested] => Array
                                        (
                                            [keys] => /tmp/php4boHkj
                                        )
                
                                )
                
                            [error] => Array
                                (
                                    [nested] => Array
                                        (
                                            [keys] => 0
                                        )
                
                                )
                
                            [size] => Array
                                (
                                    [nested] => Array
                                        (
                                            [keys] => 25668
                                        )
                
                                )
                
                        )
                
                )
                
                // restructured
                Array
                (
                    [one] => Array
                        (
                            [originalPath] => ss_break.png
                            [path] => /tmp/phppY8lSV
                            [contentType] => image/png
                            [size] => 43582
                            [errorCode] => 0
                        )
                
                    [multiple] => Array
                        (
                            [0] => Array
                                (
                                    [originalPath] => LeleBreeder.png
                                    [path] => /tmp/php6GSj1X
                                    [contentType] => image/png
                                    [size] => 14284
                                    [errorCode] => 0
                                )
                
                        )
                
                    [crazy] => Array
                        (
                            [nested] => Array
                                (
                                    [keys] => Array
                                        (
                                            [originalPath] => PlainUbuntu.png
                                            [path] => /tmp/php4boHkj
                                            [contentType] => image/png
                                            [size] => 25668
                                            [errorCode] => 0
                                        )
                
                                )
                
                        )
                
                )
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-03-07
                  • 1970-01-01
                  • 2011-10-30
                  • 2022-06-18
                  • 2018-10-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多