newbie
newbie

Reputation: 24635

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

Upvotes: 4

Views: 17676

Answers (9)

Ozair Kafray
Ozair Kafray

Reputation: 13539

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

Upvotes: 4

Andreas Frank
Andreas Frank

Reputation: 81

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

Upvotes: 0

art2
art2

Reputation: 425

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.

Upvotes: 2

Okonomiyaki3000
Okonomiyaki3000

Reputation: 3696

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).

Upvotes: 5

deej
deej

Reputation: 2564

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

Upvotes: 0

sumit
sumit

Reputation: 15464

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
                )

        )

)

Upvotes: 1

user1299518
user1299518

Reputation:

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",...
   }   
}

Upvotes: 2

flowfree
flowfree

Reputation: 16462

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

Upvotes: 3

Andreas Wong
Andreas Wong

Reputation: 60516

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
}

Upvotes: 13

Related Questions