你如何循环$ _FILES数组?

Ben*_*Ben 19 php foreach loops input form-processing

以下是我想要循环的输入

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[]" />
Run Code Online (Sandbox Code Playgroud)

发生了一些奇怪的事情,当我上传任何我使用的东西时 count($_FILES['image']),我回显了该函数,并返回值5.该数组中应该没有元素.当我只有4个文件开始时,为什么还有一个额外的输入?

现在实际循环,我尝试使用foreach循环,但它不起作用.

foreach($_FILES['image'] as $files){echo $files['name']; }
Run Code Online (Sandbox Code Playgroud)

什么都没有出现,我想最终做的是遍历所有图像,确保它们是正确的格式,大小,并重命名它们.但是这个简单的foreach()循环显示,我甚至无法循环遍历$ _FILES数组,并且当我甚至没有上传任何内容时,当它说数组中有5个元素时,count()会让我更加困惑.

Dec*_*ler 42

您的示例表单应该可以正常工作 $_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 */ )
);
Run Code Online (Sandbox Code Playgroud)

因此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?
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅文档.

  • 此示例循环很危险,因为它假设至少有 2 个上传的文件。如果是一个文件,$_FILES['attachment']['name'] 是一个字符串,因此 $_FILES['attachment']['name'][0] 将是名称的第一个字符。 (2认同)

You*_*nse 10

只需这样重命名你的字段

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" />
Run Code Online (Sandbox Code Playgroud)

然后你就可以通常的方式迭代它:

foreach($_FILES as $file){
  echo $file['name']; 
}
Run Code Online (Sandbox Code Playgroud)


小智 8

将$ _FILES ['files']重建为更多预期结构的简短函数.

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


Len*_*ick 5

我想出了一个适用于任意深度的 $_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]
Run Code Online (Sandbox Code Playgroud)

这是一些实际有效的代码。

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

只需对 $_FILES 调用 sane_files_array 就可以了,无论 $_FILES 数组有多深。这确实应该是语言本身的一部分,因为 $_FILES 数组的格式绝对是荒谬的。