Main Page Content
Clever Forms With Php
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 lazierdevelopers 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:
It is trickier with checkboxes:
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 toolssuch 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 displaythe 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":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:The function adds hidden fields with the initial values
to the form. For the "name" example, this would be: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="NonTeen"> <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 containingonly 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.