Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Clever Forms With Php

Rated 3.71 (Ratings: 7)

Want more?

  • More articles in Code
 
Picture of codepo8

Chris Heilmann

Member info

User since: 29 Jul 2002

Articles written: 17

The form problem

Forms have always been a nuisance in Web Development. They need HTML and

backend code, render differently on each browser and stubbornly refuse to

use styles consistently on browsers. Furthermore their elements

send different data and need to be initialised differently depending

on what they are.

When checking a form for mandatory entries, you often have to re-display

the form with the previously entered data, and a highlighted version of

the missing form elements. This is hard work, which is why a lot of lazier

developers use a Javascript "back" button instead of a scripting solution

that highlights the missing mandatory elements.

Repopulating forms with PHP

In PHP it is rather easy to repopulate a textual form element:

<input type="text"

id="Name" name="Name"

value="<?PHP echo $_POST['Name']==''?'':$_POST['Name'];?>" />

It is trickier with checkboxes:

<input type="checkbox"

id="Name" name="Name"

value="<?PHP echo $_POST['Name']=='on'?'':'checked="checked"';?>" />

Radio buttons and select boxes need a check for each of their options or some

Javascript to highlight them. In any case, it is a drag.

Bobby watches you

This whole dilemma increases when you need to adhere to accessibility

standards. Although not really an accessibility problem, online tools

such as title="Link to Bobby, the online accessibility test tool"

target="_blank">Bobby
moan about form elements that don't have an initial

value. To avoid this, designers add a dummy value, that has to be

stripped again from the data once the form is submitted.

The wishlist

You want a function that displays a form element. The element should

get a meaningful initial value that does not get submitted in the end.

As an extra for Javascript-enabled browsers, text elements should get

emptied when you click on them if they contain the initial value.

If the element is a mandatory field and is empty, or

contains the initial value, it should get highlighted. If the form has to

be re-displayed due to some other element missing, the element should display

the last submitted value.

The function should do that for text boxes, text areas, checkboxes,

radio buttons, and select boxes. Also, it should not change any additional

elements and attributes like accesskey, taborder, classes or colgroups.

Function 1: Displaying, initialising and highlighting the form

function add($f){

global $errorindicator,$errorclass,$Javascript;

$tocheck=explode(',',','.$_POST['required']);

preg_match('/id="(.*?)"/i',$f,$i);

preg_match('/name="(.*?)"/i',$f,$n);

preg_match('/type="(.*?)"/i',$f,$t);

preg_match('/value="(.*?)"/i',$f,$iv);

$n=$n[1];$iv=$iv[1];$i=str_replace('_',' ',$i[1]);

if(preg_match('/<textarea/',$f)){

$v=$_POST[$n]==''?$i:$_POST[$n];

$f=preg_replace('/<textarea(.*?)>(.*?)<\/textarea>/',

'<textarea\\1>'.stripslashes(htmlentities($v)).'</textarea>',$f);

if($Javascript){$f=preg_replace('/<textarea/',

'<textarea onfocus="this.value=this.value==\''.

$i.'\'?\'\':this.value"',$f);}

}

if(preg_match('/<select/',$f)){

preg_match('/<select.*?>/',$f,$st);

preg_match_all('/<option value="(.*?)">(.*?)<\/option>/',$f,$allopt);

foreach ($allopt[0] as $k=>$a){

if($_POST[$n]==$allopt[1][$k]

($_POST[$n]=='' && $k==0)){

$preg='/<option value="';

$preg.=$allopt[1][$k].'">'.$allopt[2][$k].

'<\/option>/si';

$rep='<option selected="selected" value="';

$rep.=$allopt[1][$k].'">'.$allopt[2][$k].

'</option>';

$f=preg_replace($preg,$rep,$f);

}

}

}else{

switch ($t[1]){

case 'text':

$v=$_POST[$n]==''?'value="'.$i.'"':'value="'.

stripslashes(htmlentities($_POST[$n])).'"';

$f=preg_replace('/<input/','<input '.$v,$f);

if($Javascript){$f=preg_replace('/<input/',

'<input onfocus="this.value=this.value==\''

.$i.'\'?\'\':this.value"',$f);}

break;

case 'checkbox':

$v=$_POST[$n]=='on'?' checked="checked"':'';

$f=preg_replace('/<input/','<input'.$v,$f);

break;

case 'radio':

$f=preg_replace('/checked.*?\s/','',$f);

$v=$_POST[$n]==$iv?' checked="checked"':'';

$f=preg_replace('/<input/','<input'.$v,$f);

break;

}

}

$f.='<input type="hidden" name="'.$n.'initvalue" value="'.$i.'" />';

if (array_search($n,$tocheck) and ($_POST[$n]=='' or $_POST[$n]==$i)){

if($errorindicator!=''){$f=$errorindicator.$f;}

if($errorclass!=''){$f=preg_replace('/name=/i','class="'.

$errorclass.'" name=',$f);}

}

return $f;

}

You can strip the Javascript that automatically clears the initial value when

the element gets the focus by not defining the global variable $Javascript.

The global variable $errorindicator can be a text or any

HTML, for example an image.

The content of this variable will be displayed before each missing mandatory element.

The CSS class added to each

missing field is defined in the global variable $errorclass.

Mandatory elements get defined separated by a comma in a hidden field called

"required":

<input type="hidden"

name="required"

value="Name,SurName,live,message" />

The initial value of the form element is defined by its ID. As IDs cannot

contain spaces, you need to replace them with underscores. The function

removes them automatically. If, for example, you want to display

"Please enter your first name" as the initial value in a text box,

use the corresponding ID:

<input type="text"

name="name"

id="Please_enter_your_first_name" />

The function adds hidden fields with the initial values

to the form. For the "name" example, this would be:

<input type="hidden"

name="nameinitvalue"

value="Please_enter_your_first_name" />

The add() function takes care of the form drawing, the

highlighting, and the setting of the initial value.

To use it in a PHP document, you wrap your form elements in it:

<form method="post" action="<?=$_SERVER['PHP_SELF']?>">

<input type="hidden" name="required" value="Name,SurName,live,message" />

<fieldset>

<legend>Identification</legend>

<label for="your_name">Name:</label>

<?=add('<input type="text" name="Name"

id="Your_Name" />')?><br />

<label for="your_surname">Surname:</label>

<?=add('<input type="text" name="SurName"

id="Your_Surname" />')?>

</fieldset>

<fieldset>

<legend>Gender and age</legend>

<label for="Age">Age:</label>

<?=add('

<select name="Age">

<optgroup label="Non­Teen">

<option value="5">Under 5</option>

<option value="9">Five to Ten</option>

</optgroup>

<optgroup label="Teen">

<option value="10">Aspiring Teen</option>

<option value="15">Mid Teen</option>

<option value="19">End Teen</option>

</optgroup>

<optgroup label="Twen">

<option value="20">Aspiring Twen</option>

<option value="25">Mid Twen</option>

<option value="29">End Twen</option>

</optgroup>

<optgroup label="Above">

<option value="30">30ies</option>

<option value="40">40ies</option>

<option value="over50">Above</option>

</optgroup>

</select>

')?>

<strong>Gender:</strong>

<?=add('<input type="radio" name="Gender" id="Male"

checked="checked" value="Male" />')?>

<label for="Male">Male</label>

<?=add('<input type="radio" name="Gender" id="Female"

value="Female" />')?>

<label for="Female">Female</label>

</fieldset>

<fieldset>

<legend>Enter your message</legend>

<p><?=add('<input type="checkbox" name="live"

id="live" />')?>

<label for="live">Publish to live</label></p>

<p><label for="your_message">Your Message:</label></p>

<?=add('<textarea name="message" id="Your_message"

cols="30" rows="10"></textarea>')?>

</fieldset>

<p align="right"><input type="submit" value="Send" /></p>

</form>

You need another function to strip these initial values once the form is filled and each

mandatory field is filled with something else than its initial value.

Function 2: Checking the form

function check(){

if ($_POST!=''){

$sentarray=array();

$tocheck=explode(',',$_POST['required']);

$error[0]="Errors:";

foreach ($tocheck as $t){if(!array_key_exists($t,$_POST)){

$error[]=$t;}}

foreach (array_keys($_POST) as $p){

if(!preg_match('/initvalue/',$p) and

!preg_match('/required/',$p)){

$sentarray[$p]=$_POST[$p]==

$_POST[$p.'initvalue']?'':$_POST[$p];

}

foreach ($tocheck as $c){

if ($p==$c and $sentarray[$p]==''){

$error[]=$_POST[$p.'initvalue'];

}

}

}

return $error[1]==''?$sentarray:$error;

}

}

This function checks the required elements. If all have a value

that is different from the initial value, it'll return an array containing

only the necessary fields. All the generated initial value fields and

the "required" field are stripped out.

If there was a mandatory field that is empty or still has the initial

value, the resulting array will have a first element with the value

"Errors:", and a list of all the missing fields as the other array

elements.

To use the function, you could do something like this:

<?PHP

$errorindicator='<img src="alert.gif" width="20" height="20"

alt="Alert" title="Indicator for missing form element" border="0" />';

$errorclass="error";

$Javascript=true;

$results=check();

if($results[0]=='Errors:'){

?>

<h2>There has been an error:</h2>

<p>You forgot to enter the following field(s)</p>

<ul>

<?PHP foreach ($results as $i=>$e){if ($i>0){

echo "<li>$e</li>";

}}?>

</ul>

<?PHP

}else{

// Add send functionality here

}

?>

That's it. To see the functions in all their glory, and download them with

an example, go to the title="To the form example homepage" target="_blank">homepage. Updates and

fixes will happen there and be announced in the comments below.

Currently employed in London as a Lead Front End Developer, Chris has been bouncing around the globe working for several agencies and companies. A web enthusiast from 1997 on workplaces include Munich, London, Santa Monica and San Francisco. More of Chris' writings can be found at http://icant.co.uk and he blogs at http://wait-till-i.com

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.org Evolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.