Coding with Jesse

Use Arrays in HTML Form Variables

November 3rd, 2008

When you're dealing with processing forms, a lot of the time you have a one-to-one mapping of form fields and database columns, with perhaps an extra submit button or some fields that need special processing (eg. passwords).

Although many frameworks like CodeIgniter make this easier, you can still easily come up with code like this:

$this->db->insert('accounts', array(
    'first_name' => $this->input->post('first_name'),
    'last_name' => $this->input->post('last_name'),
    'email' => $this->input->post('email'),
    'address1' => $this->input->post('address1'),
    'address2' => $this->input->post('address2'),
    'city' => $this->input->post('city'),
    'state' => $this->input->post('state'),
    'zip' => $this->input->post('zip'),
    'phone' => $this->input->post('phone'),
    'fax' => $this->input->post('fax')
));

See all that repetition? Whenever you see a group of lines that look almost the same, you know there is probably an opportunity to clean things up. Well luckily, there's a really neat one.

You can create arrays in form fields using square brackets. That means you can name fields like account[first_name] and account[last_name] and in most server-side languages, you will end up with an 'account' array.

In HTML, PHP and CodeIgniter, that might look something like this:

<input type="text" name="account[first_name]"/>
<input type="text" name="account[last_name]"/>
<!-- etc... -->
<input type="text" name="account[fax]"/>
<input type="submit" name="submit"/> <!-- note the lack of 'account' -->

// meanwhile, on the server...
$account = $this->input->post('account');

// VERY IMPORTANT: unset any fields that shouldn't be edited
unset($account['id']);

$this->db->insert('accounts', $account);

See? Much cleaner. Yes, you do open a slight security hole potential, so be very careful when doing this on tables that have security implications, ie. user data. If you have an 'admin' column on your 'users' table, someone could maliciously add <input type="hidden" name="users[admin]" value="1"/> to your form using Firebug and grant themselves administration access. You can solve this by adding something like unset($user['admin']); to the incoming data. If you wanted to be really safe, you could have an array of the keys you want to allow and filter against that using something like PHP's array_intersect_key with array_flip:

$user = $this->input->post('user');

// only allow keys in $user to match the values in $columns
$columns = array('first_name', 'last_name', /* etc.. */ );
$user = array_intersect_key($user, array_flip($columns)));

You can even do this with checkboxes and multiple select boxes, and alternatively leave out the key in the array to create a regular array (ie. not associative) of values:

<label><input type="checkbox" name="choice[]" value="1"/> 1</label>
<label><input type="checkbox" name="choice[]" value="2"/> 2</label>
<!-- etc... -->

// meanwhile, on the server...
$choice = $this->input->post('choice');

print_r($choice); // Array ( [0] => 1 [1] => 2 )

This "trick" can really clean your code up. I used it recently to drastically simplify a form that had a shipping address and billing address. If the user checked a box saying "My shipping and billing are the same", I was able to simply do something like this:

$shipping = $_POST['shipping'];
$shipping_billing_same = $_POST['shipping_billing_same'];

if ($shipping_billing_same) {
    $billing = $shipping;
} else {
    $billing = $_POST['billing'];
}

Much nicer than that 24 form fields that were hard-coded previously.

I've given examples here in PHP and CodeIgniter. Does anyone else want to give examples in other server-side languages and frameworks?


Comments

1 . Peter Baumgartner on November 4th, 2008

Peter Baumgartner

f = ArticleForm(request.POST)
if f.is_valid():
    new_article = f.save()

This is an area where Django shines: Django Model Forms

2 . Susie on November 4th, 2008

Susie

For anyone starting out with PHP, its worth mentioning that its also important to do some checking / stripping of malicious code to the variables input by a user form before you put them in your database.

3 . Frank on November 4th, 2008

Frank

Susie,

The great thing about CodeIgniter is that it offers the ability to automatically strip any unsafe input from forms.

4 . Thai Bui on November 16th, 2008

Thai Bui

It's nice, I've used it with Zend Framework, but it make another issue, you face with it when trying to validate form using Javascript, can't access to a form named like "account[address] by document.form_name.account[address].value.
Do you have any ideal?!?

5 . Jesse Skinner on November 16th, 2008

Jesse Skinner

@Thai - I'm not sure, but I'd suppose you'd do it like:

document.form_name["account[address]"].value

Of course you could just add an ID and use

document.getElementById('account_address');

6 . Thai Bui on November 16th, 2008

Thai Bui

yup, I haven't try it either, I just remember another issue is when you submit a form using GET method, at that time your url is abc.com?account=Array, and then in PHP you received it

$account = $_GET['account']; // $account = 'Array';

feeling confuse? ^_^

7 . Dave H on December 1st, 2008

Dave H

I wrote a function that gets and cleans specific $_POST keys, so you can be sure you're only inserting what you want into the database.

Eg something like
$data = cleanRequest(array('id_i', 'name', 'email'));
$db->insert('people', $data);

I also give all user input that I want validated for the DB a _type suffix, eg _i for integer as above. That way I don't have to worry about bad user data.

Using document.form_name["account[address]"].value in JavaScript seems to work fine.

8 . Roshan Bhattarai on December 13rd, 2008

Roshan Bhattarai

yes much cleaner but you can use this cleaner approach without using array in form as well ... here is the snippet of what I do in my projects.

the model function will be called like this
$this->Modelproducts->insertProcuct($_POST);

and here is modal function

function insertProduct($data)
{
unset($data['submit']); unset($data['id']);
$this->db->insert('product', $data);
}

9 . john on January 5th, 2009

john

Nice article, I also give all user input that I want validated for the DB a _type suffix, eg _i for integer as above. That way I don't have to worry about bad user data.
http://www.cyberdesignz.com/

10 . Thorpe Obazee on March 3rd, 2009

Thorpe Obazee

Doesn't this approach just make it longer to code? I think the first approach is quite clean and will stick to it.

Still, nice approach.

11 . Stacy on April 20th, 2009

Stacy

great spider! I'm biulding asite for a small company. They need spiders to crawl certain sites. Considering I never did anythin with spiders. This takes a big load of my shoulders.... thank you!!!

My guestion is, how to i get all of the...


Use Arrays in HTML Form Variables....
Array ( [0] => Array ( [0] =>

not to show?? thank you

12 . Rukesh on May 14th, 2009

Rukesh

This tutorial is really great!!
I want to learn from this website more

13 . [email protected] Marketing Blog on June 29th, 2009

ZK@Web Marketing Blog

Python is for developpers not endusers. A developper does not want an all-in-one install package that only allows you to install a package in the one true fashion. That’s why I like tarballs, because I can install it where and how I want without disturbing any other parts of my system that I don’t want to disturb.

14 . roed on July 29th, 2009

roed

tang ina mo kupal ka punta ka dito tondo manila suntukan tayo alang wenta paghihilod mo

15 . Raúl Amaya on October 14th, 2009

Raúl Amaya

Hi, I want it to know something ... I need you help... Where in the w3c can see the description of this trick... I know that work!.. I'm not doubt about your post... I've already try it... But I can not find anything in the specification... that work in which browsers, dtd, web servers... you know what i mean... in html 4 w3c specification I cannot found anything about name attribute can pass array.... please help me... I need to know what justified this ! .. it's a bug, a feuteured... By the way... sorry abour my english... right now I'm a little bit lazy for use a translator.... thanks in advanced

16 . Jesse Skinner on October 14th, 2009

Jesse Skinner

@Raúl - there is nothing in the HTML spec about this, because it is all handled on the server side.

It depends on the language you are using on the server side. PHP, for example, will turn all the arr[val] type values and convert them into an array, as specified here:

http://www.php.net/manual/en/language.variables.external.php
http://www.php.net/manual/en/faq.html.php#faq.html.arrays

Other languages may not support this.

17 . Raúl Amaya on October 14th, 2009

Raúl Amaya

@Jesse thanks for you quick answer... Ok the second link I've already see and indeed generate my question... because doesn't explain how let or how support this "feature"...

So don't look me bad... but I want to keep this clear in my mind... PHP IS who let this happens right?...that sort, kind of syntax is supported by php... so I always program in php, it's very useful .. that's nice... but wait a minute... what happen with html validator? fail about the use in name ? ...

Ok help me with this... so http://www.w3.org/TR/html401/interact/forms.html#On checkbox name attribute must be the control name ( http://www.w3.org/TR/html401/interact/forms.html#control-name) ... so what I wasn't understood it's just that.. in the spec... they say... "Several checkboxes in a form may share the same control name" and depends of the server side implement that "may"... I'm right..?? so what you say it's that php implement that "may" y square bracket form... but I just do not understand yet... how implement html is not apache?? or something else

18 . Jesse Skinner on October 14th, 2009

Jesse Skinner

@Raúl - Yes the spec allows multiple inputs to have the same name, like checkboxes. This isn't really related to the array syntax, though.

Apache doesn't care what PHP (or another language) does with the POST and GET data, Apache just tells PHP that the POST or GET data looks like "val1=a&arr[val2]=b&arr[val3]=c" and it's up to PHP to parse that and turn it into something useful, like variables and arrays in $_GET and $_POST.

Actually, there's nothing to stop you from inventing and using your own syntax for GET and POST data and parse it yourself if you wanted.

19 . lnlin on March 17th, 2010

lnlin

Hi, I want it to know something more about the jQuery!

20 . Markus Diersbock on May 2nd, 2011

Markus Diersbock

You can clean up variables with my function:

http://www.swingnote.com/downloads/mysql_safe.txt

21 . tony on May 25th, 2011

tony

this tutorial is cool, and since this deals with form element arrays, i just want to ask if how to handle form array elements like this in codeigniter:

<?=form_input('txtName[]',set_value('txtName[]'));?>
<?=form_input('txtName[]',set_value('txtName[]'));?>
<?=form_input('txtName[]',set_value('txtName[]'));?>

how to set back the value when POSTed?thanks!!!

22 . Dorian on September 5th, 2011

Dorian

Love it... Thanks.

23 . frank on September 28th, 2011

frank

i like it .good

24 . Bitch on November 6th, 2012

Bitch

:<

Comments are closed, but I'd still love to hear your thoughts.