简体   繁体   中英

How can I iterate PHP $_FILES array?

This might be stupid question, but PHPs array $_FILES has very odd format, which I have never used before. Can somebody tell me how can I iterate this array in sane way ? I have used to iterate objects or object like arrays, but this format is very odd for me. Is there any way to iterate this array like object array?

( [attachments] => 
    Array ( 
        [name] => Array ( 
            [0] => test1.png 
            [1] => test2.png 
        ) 
        [type] => Array ( 
            [0] => image/png 
            [1] => image/png 
        ) 
        [tmp_name] => Array ( 
            [0] => /tmp/phpmFkEUe 
            [1] => /tmp/phpbLtZRw 
        )
        [error] => Array ( 
            [0] => 0 
            [1] => 0 
        ) 
        [size] => Array ( 
            [0] => 9855 
            [1] => 3002 
        ) 
    ) 
)

Wow, that indeed is odd, are you using <input type="file" name="attachments[]" /> in your markup? If you could afford to change those using unique name= , you won't have that odd format...

To directly answer your question, try:

$len = count($_FILES['attachments']['name']);

for($i = 0; $i < $len; $i++) {
   $fileSize = $_FILES['attachments']['size'][$i];
   // change size to whatever key you need - error, tmp_name etc
}

I always thought that this structure was nonsense. So whenever I use a multiple input file field, I do this:

$files = array_map('RemapFilesArray'
    (array) $_FILES['attachments']['name'],
    (array) $_FILES['attachments']['type'],
    (array) $_FILES['attachments']['tmp_name'],
    (array) $_FILES['attachments']['error'],
    (array) $_FILES['attachments']['size']
);

function RemapFilesArray($name, $type, $tmp_name, $error, $size)
{
    return array(
        'name' => $name,
        'type' => $type,
        'tmp_name' => $tmp_name,
        'error' => $error,
        'size' => $size,
    );
}

Then you will have an array that you can iterate and each item in it will be an associative array of the same structure that you would get with a normal, single file input. So, if you already have some function for handling those, you can just pass each of these items to it and it will not require any modification.

By the way, the reason to cast all inputs as array is so that this will work even if you forgot to put the [] on the name of your file input (of course you will only get one file in that case, but it's better than breaking).

The simplest way is:

$files = $_FILES['attachments']['name'];
$count = 0;
foreach ($files as $file) {
     $file_name = $file;
     $file_type = $_FILES['attachments']['type'][$count];
     $file_size = $_FILES['attachments']['size'][$count];
     ...
     ...

     ++$count;
}

This is the only way to iterate $_FILES.

foreach ($_FILES['attachments']['tmp_name'] as $k => $v) {
  echo $_FILES['attachments']['name'][$k];
  echo $_FILES['attachments']['type'][$k];
}

this way?

foreach((array)$_FILES["attachments"] as $val) {
   foreach((array)$val["name"] as $name) {
      // $name = "test1.png",...
   }
   foreach((array)$val["type"] as $type) {
      // $type = "imagepng",...
   }   
}

I had the same problem while doing multipart forms. Basically I needed to check if theres any file uploads first with 'isset' and then go through every file and do all necessary conditionals.

The fastest way is just to pick one array index element, like ['tmp_name'] and loop that with foreach:

if(isset($_FILES['attachments']) {
   foreach($_FILES['attachments']['tmp_name'] as $key => $value) {
      //do stuff you need/like
   }
}

The main reason to use arrays for multiple file uploads, is that in the end it's much easier to process and iterate. If you use unique names like attachment 1, attachment 2 you run into many problems in more complex situations. I for example, had other upload fields for different attachment categories.

Of course you can do a method, as mentioned before, that fixes the $_FILES array into more clever form, if you find the whole array problematic.

I have tried small demonstration , have a look

<html>
<body>
<form enctype="multipart/form-data" method="post">
<input type="file" name="file[]" />
<input type="file" name="file[]" />

<input type="submit" name="submit" />
</form>
<body>
</html>
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
    foreach ($_FILES as $k=>$v){
   if(is_array($v)){
       foreach ($v as $sk=>$sv){ 
                $arr[$sk][$k]=$sv;
        }
       }
    }
  echo "<pre>";
  print_r($arr);
 }
?>

Output

Array
(
    [name] => Array
        (
            [file] => Array
                (
                    [0] => 4_Milestone text (1).doc
                    [1] => 2x5 ko condolence ad.jpg
                )

        )

    [type] => Array
        (
            [file] => Array
                (
                    [0] => application/msword
                    [1] => image/jpeg
                )

        )

    [tmp_name] => Array
        (
            [file] => Array
                (
                    [0] => C:\xampp\tmp\php15EF.tmp
                    [1] => C:\xampp\tmp\php163E.tmp
                )

        )

    [error] => Array
        (
            [file] => Array
                (
                    [0] => 0
                    [1] => 0
                )

        )

    [size] => Array
        (
            [file] => Array
                (
                    [0] => 20480
                    [1] => 56642
                )

        )

)

Here you go: Below function will help you simplify the file upload in a way that you will be able to process it similar to single upload of the file instead of multiple file upload.

HTML: (form.html)

<form method="post" action="post.php" enctype="multipart/form-data">
<input type="file" name="attachment[]" />
<input type="file" name="attachment[]" />
<input type="file" name="attachment[]" />
<input type="submit" value="Upload" />

PHP: (post.php)

<?php
function simplifyMultiFileArray($files = array())
{
    $sFiles = array();
    if(is_array($files) && count($files) > 0)
    {
        foreach($files as $key => $file)
        {
            foreach($file as $index => $attr)
            {
                $sFiles[$index][$key] = $attr;
            }
        }
    }
    return $sFiles;
}

$sFiles = simplifyMultiFileArray($_FILES['attachment']);
echo '<pre>';
print_r($sFiles);
?>

There are many ways to clean up the $_FILES array and make it more sensible. Here's my prefered way:

foreach ($_FILES as $fieldname => $keys)
{
    foreach ($keys as $key => $list)
    {
        foreach ($list as $no => $value)
        {
            $files[$fieldname][$no][$key] = $value;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM