Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging File and Post data in PHP

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 Answers

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

?>

Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!