lethalMango
lethalMango

Reputation: 4491

Processing multi-dimensional $_FILES array

I have the following $_FILES array past through for processing from a support form

Array
(
    [file] => Array
        (
            [name] => Array
                (
                    [0] => Test.jpg
                    [1] => Test.doc
                    [2] => Test.php
                    [3] => 
                )

            [type] => Array
                (
                    [0] => image/jpeg
                    [1] => image/jpeg
                    [2] => image/jpeg
                    [3] => 
                )

            [tmp_name] => Array
                (
                    [0] => /tmp/phpCO0vSD
                    [1] => /tmp/phpEFpp3Q
                    [2] => /tmp/phpwN4Iwc
                    [3] => 
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                    [2] => 0
                    [3] => 4
                )

            [size] => Array
                (
                    [0] => 1305787
                    [1] => 339773
                    [2] => 480098
                    [3] => 0
                )

        )

)

My main problem is understanding the logic required in order to process the array, check each file is valid (which I already have a list of valid extensions) then rename and store the file appropriately.

The solutions on Google and SO are both rather complex for my simple requirements.

Upvotes: 6

Views: 2903

Answers (5)

Sagive
Sagive

Reputation: 1817

This would work - tested!

if( !empty($_FILES['SOME_INPUT_NAME'] ) {
    $multimgs   = $_FILES['SOME_INPUT_NAME'];
    $imgs_arr   = array();

    // first build into working array
    foreach($multimgs as $key => $value) {
        foreach($pimgs[$key] as $subkey => $subvalue) {
            $imgs_arr[$subkey][$key] = $subvalue;
        }
    }
}

Then you can loop through $imgs_arr - images array. those would be in a normal,
FILE structure which you can use to upload etc.

Upvotes: 0

Swayok
Swayok

Reputation: 463

Another variant of recursive reordering based on clamcrusher's solution from here

function getFixedFilesArray() {
    $walker = function ($arr, $fileInfokey, callable $walker) {
        $ret = array();
        foreach ($arr as $k => $v) {
            if (is_array($v)) {
                $ret[$k] = $walker($v, $fileInfokey, $walker);
            } else {
                $ret[$k][$fileInfokey] = $v;
            }
        }
        return $ret;
    };

    $files = array();
    foreach ($_FILES as $name => $values) {
        // init for array_merge
        if (!isset($files[$name])) {
            $files[$name] = array();
        }
        if (!is_array($values['error'])) {
            // normal syntax
            $files[$name] = $values;
        } else {
            // html array feature
            foreach ($values as $fileInfoKey => $subArray) {
                $files[$name] = array_replace_recursive($files[$name], $walker($subArray, $fileInfoKey, $walker));
            }
        }
    }

    return $files;
}

The main difference from the original solution is that I replaced array_merge_recursive with array_replace_recursive so that indexed arrays in a tree will not produce invalid result (array_merge_recursive for indexed arrays adds new indexes instead of merging with existing indexes). I've tested this on several quite difficult situations and it worked as expected

Upvotes: 2

Magnar Myrtveit
Magnar Myrtveit

Reputation: 2740

Here is a more general solution to seoguru's answer. It works with file input fields whose name contains any level of nested arrays, for example file, file[] (the case for this question), file[english], file[english][], etc.

function rearrangeUploadArray(array $array) {
   if(!is_array(reset($array)))
      return $array;

   $rearranged = [];
   foreach($array as $property => $values)
      foreach($values as $key => $value)
         $rearranged[$key][$property] = $value;

   foreach($rearranged as &$value)
      $value = rearrangeUploadArray($value);

   return $rearranged;
}

I realize that this answer is more complicated than it has to be for this question, but maybe it can be useful for someone sometime. An example use case is a localized upload form, where multiple files can be uploaded for different languages. Then it would make sense to have one file input field for each language, named for example file[english][], file[german][], file[spanish][], etc. rearrangeUploadArray($_FILES['file']) will then return an array on the form

Array
(
    [english] => Array
        (
            [0] => Array
                (
                    [name] => ...
                    [type] => ...
                    [tmp_name] => ...
                    [error] => ...
                    [size] => ...
                )

            [1] => Array
                (
                    [name] => ...
                    [type] => ...
                    [tmp_name] => ...
                    [error] => ...
                    [size] => ...
                )

            [...]
        )
    [german] => Array
        (
            [0] => Array
                (
                    [name] => ...
                    [type] => ...
                    [tmp_name] => ...
                    [error] => ...
                    [size] => ...
                )

            [...]
        )
    [spanish] => Array
        (
            [0] => Array
                (
                    [name] => ...
                    [type] => ...
                    [tmp_name] => ...
                    [error] => ...
                    [size] => ...
                )

            [...]
        )
)

Upvotes: 4

seoguru
seoguru

Reputation: 51

I love foreach() so much, I always go with this...

$files = array();
foreach ($_FILES['files']['name'] as $num_key => $dummy) {
    foreach ($_FILES['files'] as $txt_key => $dummy) {
        $files[$num_key][$txt_key] = $_FILES['files'][$txt_key][$num_key];
    }
}

...and then I use foreach($files as $file) again to work with data nicely. :)

Of course that answer from zerkms is faster, but this is general aproach to reorder array logic for any case - you have to walk it twice (x*y).

Upvotes: 5

zerkms
zerkms

Reputation: 254886

Here is how you would traverse your array:

foreach ($_FILES['file']['name'] as $key => $name) {
    echo $name;
    echo $_FILES['file']['type'][$key];
    echo $_FILES['file']['tmp_name'][$key];
}

Having this loop you can do what you want easily.

Upvotes: 6

Related Questions