Question

PHP will automatically convert

<input type="text" name="foo[0]" value="x" />
<input type="text" name="foo[1]" value="y" />

into

$_POST['foo'] = array(
    0 => 'x', 
    1 => 'y'
);

Which is what you want most of the time. However, in this case I would like this not to happen. Is there anyway to tell PHP to not do this?

I realize I could parse php://input myself, but I'd rather not do that if I can avoid it.

I also don't have the option of renaming the input names.

Was it helpful?

Solution

By using the brackets [] you explicitly tell PHP to create an array, just don't use the brackets:

<input type="text" name="foo_0" value="x" />
<input type="text" name="foo_1" value="y" />

The fields will be available in the $_POST array as $_POST['foo_0'] and $_POST['foo_1'].

If you don't have influence on the markup (which is weird, since you could always change them client side) you need to flatten the array.

$post = array();

foreach ($_POST as $key => $value) {
    if (!is_array($value)) {
        $post[$key] = $value;
    } else {
        foreach ($value as $foo => $item) {
            $post[$foo] = $item;
        }
    }
}

Or read some great input on array flattening.

OTHER TIPS

I don't think you can disable this feature without recompiling php.

I want to warn you about reconstructing the original variable names by walking the multi dim array. You can't fully reconstruct the names because php renames certain characters. For example, php doesnt allow certain characters in a top-level array key in $_POST/$_GET/etc... and so it replaces the char with an underscore. This makes it impossible to differentiate between a.b a b a[b as they all show up as a_b. In addition, there's longstanding bugs related to parsing the array syntax of request variables that causes this behavior. Here's a bug report I filed a few years ago https://bugs.php.net/bug.php?id=48597 which is unlikely to ever be fixed.

In addition, magic_quotes_gpc has sunk its talons into the array keys if that setting is enabled.

But if you're ok with these aforementioned edge cases failing, then you could reconstruct the array as follows:

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($_POST));
$result = array();
foreach ($ritit as $k => $leafValue) {
    if ($ritit->getDepth() > 0) {
        $path = array($ritit->getSubIterator(0)->key());
        foreach (range(1, $ritit->getDepth()) as $depth) {
            $path[] = sprintf('[%s]', $ritit->getSubIterator($depth)->key());
        }
        $result[ join('', $path) ] = $leafValue;
    } else {
        $result[$k] = $leafValue;
    }
}


print_r($result);

Reverting the array conversion should be done like this:

$POST = array('foo' => array('bar', 'baz'));

foreach ($POST['foo'] as $key => $value) {
    $POST['foo['.$key.']'] = $value;
}
unset($POST['foo']);

var_dump($POST);

Output:

array(2) {
  'foo[0]' =>
  string(3) "bar"
  'foo[1]' =>
  string(3) "baz"
}

I ended up going with the flattening approach suggested by markus-tharkun. For those interested, here's the code I ended up using:

function flatten($model) {
    $repeat = false;
    foreach ($model as $name => $value) {
        if (is_array($value)) {
            $repeat = true;
            foreach ($value as $sub_name => $sub_value) {
                $model["{$name}[$sub_name]"] = $sub_value;
            }
            unset($model[$name]);
        }
    }
    if ($repeat) {
        $model = flatten($model);
    }
    return $model;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top