cdmckay
cdmckay

Reputation: 32240

Stop PHP from creating arrays in $_POST superglobal

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.

Upvotes: 3

Views: 437

Answers (4)

cdmckay
cdmckay

Reputation: 32240

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

Upvotes: 0

goat
goat

Reputation: 31813

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

Upvotes: 2

markus
markus

Reputation: 40675

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.

Upvotes: 9

Sven
Sven

Reputation: 70863

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"
}

Upvotes: 0

Related Questions