Advanced Form Processing with PHP and Javascript
Intended Audience
Prerequisites
Introduction
What Is Javascript, and What Is Not
Utilizing Javascript to Reduce Traffic
What if Javascript has Gone Away?
Passing Data From PHP To Javascript
Using Regular Expressions
Tips & Tricks (Processing)
Tips & Tricks (Designing Form)
Sample Codes
Conclusion
Intended Audience
This article is intended for intermediate level PHP programmers, who know how to use web forms to gather data, and how to communicate with database systems or filesystem to store the data, but are unaware or uninformed about the inspection process between these two steps.Prerequisites
- Basic understanding of HTTP.
- Basic command of Javascript.
- Experience with HTML form elements.
Introduction
When building a web site, sooner or later you will need a form. Forms are the best way of gathering data from visitors. Your forms can be as small as a login form, or as large as a membership subscription form asking for lots of input. Obviously, the bigger the form, the more information there is to process, and the greater the challenge.When inspecting form data, the two most important issues you have to worry about are intrusion,and gathering as much useful data as possible from your visitors. Although these issues appear to lay on just opposite sides - you want to collect lots of data, but you have to put restrictions against intruders - it is actually possible to do both. By taking a few precautions you can eliminate 95% of intruders while forcing visitors to supply the data you want.
You have tools for optimization of form’s inspection process, both client side and server side. Client side, the most important of themtools are scripting languages, particularly Javascript. Utilizing Javascript, you can limit and check form data while it’s still on the client side.
On the server side, you need nothing but PHP. But, you should be aware that some common coding mistakes in PHP may become deadly. Have a look at zend.com’s articles titled Coding Mistakes Part I, II, III for more details.
What Is Javascript, and What Is Not?
Javascript is popular client side scripting language used for controlling objects on the web page. It’s code is embedded and sent to the client’s browser in the HTML. As long as the client does not make a new request from the server, Javascript will stay and run on the client. In the same way, Javascript’s effects stay on the client side until submission to the server. That’s why it’s client-side. And you cannot access client machine’s resources like filesystem or data sources. That’s why it’s called scripting language, not programming. Javascript deals with objects on the web page only.Javascript is NOT a security tool. Since your source is sent to the client, who can talk about security? Javascript is used simply to save server bandwidth. “Client-side scripting” and “security” are a contradiction in terms.
Rules are well and fine so long as people obey them. Javascript sets rules for users without any evil intention. But, an unscrupulous and knowledgeable intruder won’t mind breaking a few rules in an effort to find a gate which you forgot to close.
Utilizing Javascript to Reduce Traffic
Javascript is capable of controlling HTML objects on a page, including form objects. You can minimize network traffic between server and client by utilizing Javascript as a pioneer.Consider this case: You have a web page including a form with username and password fields, and both cannot be shorter than 6 characters. You have two alternatives: Let Javascript check this constraint first, client side, then have PHP take over, server side; or have everything dealt with by PHP server side. Evaluate the pseudo alternatives when user entered 5 characters in username field:
Javascript + PHP
|
PHP
|
There are two steps (1,5) causing traffic between server and client when Javascript is utilized before PHP, while there are four (1,3,5,7) with PHP only. (See sample code 4 for this example’s source.)
Does server workload matter when utilizing Javascript? As for
PHP’s CGI nature, every time your script called, an instance of
php’s executable is created, using up memory and processor resources. As
the execution finishes, the file dies and resources get freed. Executing a few
PHP script won’t usually overload the server unless there are huge numbers
of php instances running at the same time. The time taken to execute PHP scripts
is measured in miliseconds, and you can observe resource consumption using Task
Manager (on Windows platforms), or the command
ps –ef | grep php (on Unix platforms).
You should take server performance into account,
- When you’re expecting hundreds of visitors online at the same time
- When you have very limited server resources (for hardware, hosting etc. reasons)
What if Javascript has Gone Away?
Although it’s can’t be claimed that Javascript is available on every browser, certainly every modern browser supports it. However, even with modern browsers, scripting can be manually disabled for security reasons. What happens if Javascript is not enabled, or is circumvented in any way, or if someone sent data by hand instead of filling out your form?When coping with form processing, you have to ensure that,
- the form is displayed on the client browser and filled out,
- Javascript has gone over the form, and checked that no error occured.
A second thing to remember: Do not use a SUBMIT type for the button which submits the form:
<INPUT TYPE="submit" VALUE="OK" onClick="check_form(this);">
<INPUT TYPE="button" VALUE="OK" onClick="check_form(this);">
To ensure that the form is ‘really’ filled out, rather than sent by another application or manually, you may use a noisy image created online as a form checking technique. (See the sign-up page on hotmail.com). Zend.com has a tutorial on Securing Forms with Noisy Images.
|
Passing Data From PHP To Javascript
Sometimes you may need to use some data back on client side. There are 2 ways of passing data from PHP to Javascript. The first way is directly adding PHP code in the <SCRIPT> tag, appropriate to Javascript syntax:
<?php
$user_id = $_GET["uid"];
?>
font color="#007700"><SCRIPT LANGUAGE="Javascript1.2">
var user_id =
<?php echo($user_id);?>
;
alert("Your user ID is:" + user_id);
</SCRIPT>
<?php
$user_id = $_GET["uid"];
?>
<SCRIPT LANGUAGE="Javascript1.2">
//You can directly access an object's value with id.
alert("Your user ID is:" + p2j.value);
</SCRIPT>
<BODY BGCOLOR=
"#FFFFFF">
<INPUT TYPE=
"hidden" ID=
"p2j" VALUE="<?php echo(
$user_id);?>
">
Using Regular Expressions
When processing form input, you often have to perform complicated operations on strings. Regular expressions, or regexp in short, are a powerful way of specifying complex string search and modifications. Regular expressions are available in almost every environment. From PHP to Javascript, or MySQL to Unix itself. Though regular expressions have different implementations, their general logic is similar. For further information about using regular expressions in different environments, consult related documentation.Normally regular expressions need more resources to run, but they let you easily check and modify very complex strings in just a couple of lines, which would otherwise require lots of flow control blocks (if..else, switch etc.) to perform the same actionYeap.. That’s why it’s logical to use them. On the other hand, excessive usage of regular expressions overburdens your server. Thus, determining when to choose regexp is important.
In PHP, two types of regular expression are available: Perl compatible and POSIX 1003.2. Perl compatible regular expressions have number of advantages over POSIX. (Refer to related documentation for further information on regular expressions.)
In Javascript, creating regexp objects is very similar to creating string variable definitions. If you begin and end with slashes, then the variable will be stored as a regexp object and will be eligible for regexp methods like compile, exec, match, test, replace. Another way is creating an instance of theYes, it’s a specific class name in Javascript. RegExp object.
The syntax of string testing in Javascript is like
regexp.test(string);
Where regexp represents the regular expression, and
string is the string that this test is going to made on. The test method
checks to see if a pattern exists within a string and returns Ttrue if it does,
and false otherwise. (See sample code 3.)
Tips & Tricks (Processing)
When evaluating a user’s input, length is not the only criterium you have to check. Remember that a space is also counted as a character. For better auditing;- Replace multiple spaces with a single space using replace regexp . This is even more important when you explode the input into an array, using space as delimiter. Multiple spaces will result in keys with empty values on the resulting array. (See sample code 1 and 2.)
- Trim string inputs before using them in comparisons. Javascript has no trim function. See function below. (See sample code 5.)
- Check the data types of fields. PHP has very useful functions for this purpose: is_numeric(), is_string(), is_integer() etc.
- Quotes and some other special characters (percent sign, underscore, semicolon etc.) may cause problems
on SQL commands. Since JS has no similar function, you’d better use PHP’s
addslashes()function before querying SQLs. This function adds slashes as an escape character for those special characters, including null. Not only characters, but some keywords are reserved and meaningful for databases systems. Like CREATE, DROP, ALTER, DELETE, GRANT, REVOKE. - As a global programming rule, try to handle all exceptions in code and never let PHP show an error message. Some error messages may reveal key information (like physical paths) to intruders. You can also display messages like different system messages to confuse novice intruders, such as:
$db_conn = @mysql_query('localhost', 'u', 'p') or die('ADO Connection Error 0x80000922: Microsoft Jet Engine couldn\'t be started'); // What the heck ADO is doing there J?
$recs = @mysql_query($sql, $db_conn) or die ('ADO Recordset Error 0x800A0BCD: Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.');
- Receiving data with a method that you don’t expect indicates an intrusion attempt.
Unexpected variables are not funny either. Prefer using
$_POST[‘Variable’]syntax instead of$Variableor$_REQUEST[‘Variable’]. Specify which method are you expecting data in. Occasionally you may actually expect more than one. If that is the case, put them in order:
// If POST data is set, use it, otherwise use GET data.
$name = isset($_POST['name']) ? trim($_POST['name']) : trim($_GET['name']);
- If a checkbox is not checked, the
isset()function will return false when processing. Therefore, before checking the value of a checkbox, always check if it’s set.
if (isset($_POST['read_licence_aggreement'])) {
if($_POST['read_licence_aggreement']== "Y") {
echo "User has accepted licence aggreement.";
}
}
Tips & Tricks (Designing Form)
- Always include MAXLENGTH attribute in text fields to limit the size of field. This will save your script from an unexpected error.
- If you want a field’s value to be displayed but without allowing the user to change it, use READONLY boolean attribute set and also set it’s TABINDEX attribute’s value to -1. (Using HIDDEN type of input will not display this field on form.)
<INPUT TYPE="text" NAME="price" READONLY TABINDEX="-1">
- If you place multiple checkboxes on a form with the same name, PHP will accept only the value of the last check box (in source order). In case you need all the values as an array, put brackets “[]” (without quotes) after NAME attributes of each one. (See sample code 6.)
Sample Codes
- Replacing strings using regular expressions in PHP.
<?php
// This command will replace multiple spaces with a space.
$result = ereg_replace("\s+", " ", $_POST['sentence']);
echo('Old String:'.$_POST['sentence'].'\n');
echo('New String:'.$result.'\n');
?> - Replacing strings using regular expressions in Javascript.
Note: Do not forget to add “g” (global search) after the regular expression’s closing slash, if you want to replace ALL matches. Otherwise, the<SCRIPT LANGUAGE="Javascript1.2">
var r, re;
//String to be checked.
var s = "23th University Summer Olympic Games is going to be organized by city of Izmir in 2005.";
// Regular expression. Masks at least 1 space on global scope.
re = /\s+/g;
// Replace space(s) with a space.
r = s.replace(re, " ");
//See the results
alert("Old string:\n"+s);
alert("New string:\n"+r);
</SCRIPT>replacefunction will only replace the first match. - Matching strings with regular expressions in Javascript.
<SCRIPT LANGUAGE="Javascript1.2">
// First way of defining regular expressions
// See parameters after second slash?
// i: ignore case g:global search
// This regexp means exact 5 numeric characters
var re_zip1 = /[0-9]{5}/ig;
// ...and second.
var re_zip2 = new RegExp("/[0-9]{5}/", "ig");
// Testing. Attention please.
alert(re_zip1.test("35140")); // true. All numeric and 5 digits
alert(re_zip1.test("3510")); // false. All numeric but 4 digits.
alert(re_zip2.test("a5140")); // false. 5 digits but not all numeric.
</SCRIPT> - Common HTML and Javascript source checking the form before submission.
<HTML>
<HEAD>
<TITLE>Sample Form</TITLE>
</HEAD>
<SCRIPT LANGUAGE="JavaScript1.2">
// Form object
var f=document.forms(0);
// Boolen to track if error found
var foundErr;
// Form element index number which the first error occured.
var focusOn;
function check_form() {
foundErr = false; focusOn = -1;
// Username field must be at least 6 chars.
if (f.user.value.length<6) {
alert ("Username too short.");
foundErr = true; focusOn = 0;
}
// Password field must be at least 6 chars.
if (f.pass.value.length<6) {
alert("Password too short");
foundErr = true;
if (focusOn==-1) focusOn=1;
}
//Has any error occured?
if (foundErr) {
//Yes. Focus on which the first occurred.
f.elements.focus(focusOn);
} else {
// No. Submit the form.
f.submit();
}
}
</SCRIPT>
<BODY BGCOLOR="#FFFFFF">
<FORM ACTION="check.php" METHOD="post">
<TABLE BORDER="0" WIDTH="100%" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD WIDTH="30%" ALIGN="right">Username</TD>
<TD WIDTH="70%">: <INPUT TYPE="text" NAME="user"></TD>
</TR>
<TR>
<TD ALIGN="right">Password</TD>
<TD>: <INPUT TYPE="password" NAME="pass"></TD>
</TR>
<TR>
<TD> </TD>
<TD><INPUT TYPE="button" VALUE="Submit" onClick="check_form();"></TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML> - Sample trim function in Javascript.
<SCRIPT LANGUAGE="Javascript1.2">
function trimmer(pVal) {
TRs=0;
for (i=0; i<pVal.length; i++) {
if (pVal.substr(i,1)==" ") {TRs++;} else {break;}
}
TRe=pVal.length-1;
for (i=TRe; i>TRs-1;i--) {
if (pVal.substr(i,1)==" ") {TRe--;} else {break;}
}
return (pVal.substr(TRs, TRe-TRs+1));
}
</SCRIPT> - Retrieving Multiple Checkbox Values As An Array
If brackets are missing on names;
processing script...
<INPUT TYPE="checkbox" NAME="s" VALUE="A" CHECKED>Checkbox 1<BR>
<INPUT TYPE="checkbox" NAME="s" VALUE="B">Checkbox 2<BR>
<INPUT TYPE="checkbox" NAME="s" VALUE="C">Checkbox 3<BR>
...
will produce:<?php
echo '<PRE>('.(gettype($_POST['s']).') ';
print_r($_POST['s']);
?>
(string) A
But if you add [] after each element’s name,
the same PHP code will produce the output below:...
<INPUT TYPE="checkbox" NAME="s[]" VALUE="A" CHECKED>Checkbox 1<BR>
<INPUT TYPE="checkbox" NAME="s[]" VALUE="B">Checkbox 2<BR>
<INPUT TYPE="checkbox" NAME="s[]" VALUE="C">Checkbox 3<BR>
...
from which we can see that all three boxes are checked.(array)
Array (
[0] => A
[1] => B
[2] => C
)
Conclusion
One of the most important mistakes you could ever make is processing form data without any inspection for errors. Errors fall into two categories:- Vulgar errors, that occurred as a result of inattentiveness, carelessness or oversight. If you know that 2 by 2 is equal to 4, but wrote down “5” on exam sheet, this is a vulgar error.
- Logical errors, occurred as a result of ignorance, absence of information or malice. If you think 2 by 2 is equal to 5, this is a logical error.
The methods, tips and tricks we have mentioned in this article are introductory to advanced level of form processing. As you design complex forms, you will need and develop more methods of inspection. Don’t forget to share them with others!

Comments
<INPUT TYPE="checkbox" NAME="s" VALUE="A" CHECKED>Checkbox 1<BR>
<INPUT TYPE="checkbox" NAME="s" VALUE="B">Checkbox 2<BR>
<INPUT TYPE="checkbox" NAME="s" VALUE="C">Checkbox 3<BR>
looping through the checkboxes with JavaScript is no problem:
var elements=document.formName.s;
for (var i=0; i<elements.count;i++){
myElement=elements[i];
// code for each myElement;
}
However when using the second method of naming the elements (the [] manner) :
<INPUT TYPE="checkbox" NAME="s[]" VALUE="A" CHECKED>Checkbox 1<BR>
<INPUT TYPE="checkbox" NAME="s[]" VALUE="B">Checkbox 2<BR>
<INPUT TYPE="checkbox" NAME="s[]" VALUE="C">Checkbox 3<BR>
you cannot use JavaScript in the same way because simply typing
var elements=document.formName.s[];
will throw out an error.
In this case you will have to loop through all alements of the form and search for the elements named 's[]', instead.
Here is a way to do it:
var elms=document.formName.elements;
for(var i=0;i<elms.length;i++)
if(elms[i].name=='s[]'){
myElement=elms[i];
//code for myElement
}
It's not an array either in the DOM or in Javascript and that's why document.formname.s[] doesn't work.
Having several controls (that aren't radio buttons anyway) with the same name/id is a problem though.
So, to correct the article example, just make the names unique by adding a numerator. PHP will interpret say name="s[3]" as an array with the specified index, eg $myarr=$_POST["s"]; $val=$myarr[3];
For javascript then "s[3]" becomes a unique name which is then accessible using document.formname["s[3]"] or document.getElementById("s[3]") if you prefer, assuming the ID is set to that value.
There are several ways to validate, using Javascript, an arbitrary number of fields, not the least of which would be just to use a while loop and test for the existence of "s[i]", assuming a sequential order. Alternately, if validation is initiated from the element itself, say on blur, then just pass the 'this' object along to your validator function (eg validate(this)) and your function can access the id, value, etc, no problem.
But, for ANY control in the DOM, it's always name="value" or id="value" and only for radio buttons is the value considered to be the name of an array holding multiple values thus forming a tuple.
What's cool with this construct though is that you can create logical and distinct form records all in the same form.
So, if you have, say, many people displayed in a form and want to process them all after a submit, just name each textbox as name="persons[0][fullname]", name="persons[2][fullname]", etc.
In php, just grab all the records as an array with $persons = $_POST["persons"]; ...and process as with any data set.
You want to know how many people were submitted?
$rows = count($_POST["persons"]);
What's the name of person 4?
$name = $_POST["persons"][4]["fullname"];
Why PHP does this is beyond me and not well documented AFAIK. But it is cool!