views:

258

answers:

1

At work I've been dealing with some complex forms (publish pages of Symphony) that contain multiple image upload fields. I need a way to quickly merge $_FILES with $_POST, unfortunately you cannot simply merge the two with array_merge because they don't follow the same structure.

Basically if you have $_POST[a][b] it would be $_FILES[a][*][b]. Replace * with one of name, type, tmp_name, error or size.

The content of the $_FILES array as standard:

array
  'image-a' => array
      'name' => string '' (length=0)
      'type' => string '' (length=0)
      'tmp_name' => string '' (length=0)
      'error' => int 4
      'size' => int 0
  'image-b' => array
      'name' => string '' (length=0)
      'type' => string '' (length=0)
      'tmp_name' => string '' (length=0)
      'error' => int 4
      'size' => int 0
  'image' => array
      'name' => array
          'sub' => array
              'c' => string '' (length=0)
      'type' => array
          'sub' => array
              'c' => string '' (length=0)
      'tmp_name' => array
          'sub' => array
              'c' => string '' (length=0)
      'error' => array
          'sub' => array
              'c' => int 4
      'size' => array
          'sub' => array
              'c' => int 0

And the desired array after merging with $_POST:

array
  'MAX_FILE_SIZE' => string '5242880' (length=7)
  'image-a' => array
      'name' => string '' (length=0)
      'type' => string '' (length=0)
      'tmp_name' => string '' (length=0)
      'error' => int 4
      'size' => int 0
  'image-b' => array
      'name' => string '' (length=0)
      'type' => string '' (length=0)
      'tmp_name' => string '' (length=0)
      'error' => int 4
      'size' => int 0
  'image' => array
      'sub' => array
          'c' => array
              'name' => string '' (length=0)
              'type' => string '' (length=0)
              'tmp_name' => string '' (length=0)
              'error' => int 4
              'size' => int 0
+1  A: 

This is the solution I came up with, calling get_file_post_data returns the merged array:

<?php

    if (!empty($_POST)) {
        header('content-type: text/plain');

        function merge_file_post_data($type, $file, &$post) {
            foreach ($file as $key => $value) {
                if (!isset($post[$key])) $post[$key] = array();
                if (is_array($value)) merge_file_post_data($type, $value, $post[$key]);
                else $post[$key][$type] = $value;
            }
        }

        function get_file_post_data() {
            $files = array(
                'name'        => array(),
                'type'        => array(),
                'tmp_name'    => array(),
                'error'        => array(),
                'size'        => array()
            );
            $post = $_POST;

            // Flip the first level with the second:
            foreach ($_FILES as $key_a => $data_a) {
                foreach ($data_a as $key_b => $data_b) {
                    $files[$key_b][$key_a] = $data_b;
                }
            }

            // Merge and make the first level the deepest level:
            foreach ($files as $type => $data) {
                merge_file_post_data($type, $data, $post);
            }

            return $post;
        }

        var_dump(get_file_post_data());
    }

    else echo '
        <form action="" method="post" enctype="multipart/form-data">
            <input name="MAX_FILE_SIZE" type="hidden" value="5242880">
            <div><label class="file">Image A <input name="image-a" type="file"></label></div>
            <div><label class="file">Image B <input name="image-b" type="file"></label></div>
            <div><label class="file">Image C <input name="image[sub][c]" type="file"></label></div>
            <div><button type="submit">Send</button></div>
        </form>
    ';

?>
Rowan Lewis