$ _Post Large Fieldset - 放入阵列的简单方法

I have a page that basically recreates a database table and allows the user to edit fields for multiple records at a time. When they press save I am submitting a post that keeps all my field names in the correct field name array. i.e one field name is "table_name[name][]" this gives me an array that looks like exactly how I want it

["name"] => array(2) {
      [0]=> "name 1"
      [1]=> "name 2"
 }

And I have a LOT of fields that can be edited. So my question: What is the best way to loop through my post array and create an array that is similar in structure to.

$updates[1] => array{
    id   => id from first record
    name => name from first record
    etc  => remaining info from first record
}
[2] => array{
    id   => id from second record
    name => name from second record
    etc  => remaining info from second record
}

Is there an easy way to do this other than having to write out every single field?

You can see this in action at IDEOne.com by clicking here.

I'm assuming your $_POST looks something like this:

$_POST = array(
    'id' => array(
        0 => 14,
        1 => 15,
        2 => 16
    ),
    'name' => array(
        0 => 'Jill',
        1 => 'Jack',
        2 => 'John'
    )
); //I won't do any other columns because what's the point?

So, your entries are aggregated currently by column. You want to aggregate them by row.

Here's a naive solution. Assuming that every row has to have an id associated with it, find out how many ids were sent back.

$total = sizeof($_POST['id']);

Now, loop over the $_POST array that many times:

$rows = array();
for ($i = 0; $i < $total; $i++) {
    $rows[] = array(
        'id' => $_POST['id'][$i],
        'name' => $_POST['name'][$i]
    );
}

Now, $rows is populated with the information grouped by row instead of column.

For better performance, it might be possible to do this using a callback and a built-in array function.

If you are going to be reusing this logic a lot, consider placing it in a static function, or building a helper class that will perform this logic in a reusable/portable manner.


You can see this in action at this IDEOne.com demonstration by clicking here.

You're saying that you don't want to have to manually specify which fields get entered. That can be accomplished, but first, ask yourself the following question:

Can I reasonably guarantee that only the fields will exist in $_POST?

The answer is no, but I'll answer this as if it's yes first.

Again, we will use id as the field that tells us how many rows there will be:

$total = sizeof($_POST['id']));

$rows = array();
for ($i = 0; $i < $total; $i++) {
    //This part changes.
}

Now, inside of our for loop, we need to loop over the $_POST array, and get the key names:

for ($i = 0; $i < $total; $i++) {
    $array = array(); //Create a blank array.

    foreach ($_POST as $key => $value) {
        $array[$key] = $value[$i]; //Add the key with it's value. Remember $value is an array here too.
    }

    $rows[] = $array;
}

The reason I said the answer is no to the question above is because the user could manipulate the data they send from the client (browser) in an attempt to make the page do things other than it was intended (e.g. SQL Injection, XSS Attacks, feature/server discovery, etc.).

In the above example, if a user submitted the form, but manipulated it by adding a form element such as:

<input type="hidden" name="breakpage" value="true" />

You'll now have an element of the $_POST array that isn't an array itself. When the $_POST array gets iterated over, the page is going to throw an error about an undefined index which will be echo'd out to the user. You can disable the display of the error, but it would still stop the page from functioning.

Assuming you are using prepared statements to actually write to the database, and are checking for XSS attempts in the values, this is probably as bad as it would get.

To combat this, you could setup an array of keys that are accepted in $_POST, and iterate that instead of $_POST itself. However, you explicitly stated that you didn't want to do this.