Posting arrays and finding names

Google will tell you how to post arrays, but what if you need to determine the name of the variable that was posted?

First we’ll briefly cover the practice of posting arrays. For the sake of example, imagine you have checkboxes that are somehow grouped (e.g. wines by region or musicians by genre) and it would be convenient if that grouping were represented on the other side of the form.

Markup for posting arrays

The HTML for arrays is similar to PHP’s, except you don’t need a dollar sign nor quotes around keys:

<form method="post">
  <input type="checkbox" name="foo[fizz]">
  <input type="checkbox" name="foo[buzz]">
  <input type="checkbox" name="bar[fizzbuzz][foo]">
  <input type="checkbox" name="bar[fizzbuzz][bar]">
  <input type="submit" name="submit" value="Submit">
</form>

If we check all the inputs and var_dump($POST) we get:

array (size=4)
  'foo' =>
    array (size=2)
      'fizz' => string 'on' (length=2)
      'buzz' => string 'on' (length=2)
  'bar' =>
    array (size=1)
     'fizzbuzz' =>
        array (size=2)
          'foo' => string 'on' (length=2)
          'bar' => string 'on' (length=2)
  '2t' => string 'on' (length=2)
  'submit' => string 'Submit' (length=6)

Remember PHP is dynamically-typed, so even though names are in quotes, 2 would be an integer and 2a would be a string.

Tell me your name!

What if, for the sake of argument, you wanted to determine the values of the name attributes of the posted data? I can’t think of a contrived example for this one (let me know if you can!) but I’m sure someone somewhere at some point in time will want to know how it’s done.

We’ll need two functions that I wrote years ago, probably plagiarised from SO and don’t dare to look at critically:

/**
 * post2name
 *
 * Converts a $_POST array to a flat array of the form element `name`s which would have produced it.
 *
 * For example, the PHP array:
 *
 * 'foo' => 'bar',
 * 'baz' => [
 * 'foo' => 'bar',
 * ],
 *
 * would turn into:
 *
 * 'foo' => 'bar',
 * 'baz[foo]' => 'bar',
 *
 * @param array $array Array to be converted
 * @return array Flat array of HTML `name`s
 */

function post2name( $array ) {
  $result = array();
  $array = flatten_array( $array );
  foreach ( $array as $key => $value ) {
    $parts = explode( '.', $key );
    $i = 0;
    $new_key = '';
    foreach ( $parts as $part ) {
      if ( $i !== 0 ) $part = '[' . $part . ']';
      $new_key .= $part;
      $i++;
    }
    $i = 0;
    $result[ $new_key ] = $value;
  }
  return $result;
}

/**
 * flatten_array
 *
 * Turns a multi-dimensional array into a flat one separated by dots
 *
 * @param array $array Array to be flattened
 * @param string $prefix Received previous value from recursive call
 *
 * @return array Flat array
 */

function flatten_array( $array, $prefix = '' ) {
  $result = array();
  foreach( $array as $key => $value ) {
    if ( is_array( $value ) ) {
      $result = $result + flatten_array( $value, $prefix . $key . '.' );
    } else {
      $result[ $prefix . $key ] = $value;
    }
  }
  return $result;
}

When you pass $_POST through post2name() you get:

array (size=6)
  'foo[fizz]' => string 'on' (length=2)
  'foo[buzz]' => string 'on' (length=2)
  'bar[fizzbuzz][foo]' => string 'on' (length=2)
  'bar[fizzbuzz][bar]' => string 'on' (length=2)
  '2t' => string 'on' (length=2)
  'submit' => string 'Submit' (length=6)

What about $_GET?

You can do exactly the same thing with get and PHP will populate $_GET with whatever data structure you throw at it.

Determining the names requires a different approach though, because brackets get encoded:

/**
 * Discerns the form element `names` of each variable in a query string
 *
 * @param string $query_string A query string from a form
 * @return array List of form element `names`
 */
function get2name( $query_string ) {
  $query_string = explode( '&' , $query_string );
  foreach ( $query_string as $key => $value ) {
    $query_string[ $key ] = urldecode( $value );
    $parts = explode( '=', $query_string[ $key ] );
    $names[ $parts[0] ] = $parts[1];
 }
 return $names;
}

Do var_dump(get2name($_GET)) and you’ll get the same result.

Conclusion

Now you know how to turn a string into an array and back again. Sort of. It’s one of those things that sounds silly and useless but you can almost guarantee that at some point you’ll be glad you know about it.

Leave a Reply

Your email address will not be published. Required fields are marked *