- Remembering the Basics
- Validating Form Data
- Using PECL Filter
- Authentication with PEAR Auth
- Using MCrypt
Using PECL Filter
New in PHP 5 and quite promising is the Filter library of PECL code. Being developed by PHP's creator and other major contributors, the future of Filter looks bright, even though it's still in beta form (at the time of this writing). The Filter package provides two types of security:
- Data validation by type
- Data sanitization
What Filter offers is a unified interface for performing common types of validation and sanitization. For example, I might commonly use code like this:
if (isset($_GET['id'])) { if (is_numeric($_GET['id'])) { $id = (int) $_GET['id']; if ($id > 0) { // Do whatever. } } }
I could instead do this:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, array('options'=>array('min_range'=>1))); if ($id) { ...
That might look like jabberwocky, but once you get the hang of Filter, the amount of work you can do in just a line of code will be worth the learning curve.
To filter individual variables, there are two functions you'll use: filter_input() and filter_var(). The first one is for working with variables coming from an outside source, like forms, cookies, sessions, and the server. The second is for variables within your own code. I'll focus on filter_input() here. Its syntax is:
$var = filter_input($variable_source, $variable_name, $filter, $options);
The sources, which the PHP manual calls "types," are: INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV, INPUT_SESSION, and INPUT_REQUEST. As you can probably guess, each of these corresponds to a global variable ($_GET, $_POST, etc.). For example, if a page receives data in the URL, you'd use INPUT_GET (not $_GET).
The second argument—the variable name—is the specific variable within the source that should be addressed. The $filter argument indicates the filter to apply, using the constants in Table 4.2. This argument is optional, as a default filter will be used if none is specified. Some filters also take options, like the FILTER_VALIDATE_INT in the preceding example (which can take a range).
Table 4.2. These constants represent some of the filters that can be applied to data. For a complete list, see the PHP manual or invoke the filter_list() function.
Filters by Name |
|
Constant Name |
Action |
FILTER_VALIDATE_INT |
Confirms an integer, optionally in a range |
FILTER_VALIDATE_FLOAT |
Confirms a float |
FILTER_ VALIDATE_REGEXP |
Matches a PCRE pattern |
FILTER_ VALIDATE_URL |
Matches a URL |
FILTER_ VALIDATE_EMAIL |
Matches an email address |
FILTER_SANITIZE_STRING |
Strips tags |
FILTER_SANITIZE_ENCODED |
URL-encodes a string |
The filter_input() function will return the filtered variable if the filtration or validation was successful, the Boolean FALSE if the filter didn't apply to the data, or the value NULL if the named variable didn't exist in the given input. Thus you have multiple levels of validation in just one step.
There's really a lot of information packed into just a few functions here, but I want to present a sample of how you would use the Filter library. To do so, I'll create a modified version of the registration form (Figure 4.4). Note that as of PHP 5.2, Filter is built into PHP. If you're using an earlier version, you may need to install it using the pecl installer (see the PHP manual for more).
Figure 4.4 This new registration form lacks the password and date of birth inputs.
To use PECL Filter
- Begin a new PHP script in your text editor or IDE, starting with the HTML (Script 4.2).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <title>Filter</title> <style type="text/css" title="text/css" media="all"> .error { color: #F30; } </style> </head> <body> <?php # Script 4.2 - filter.php
The script has one CSS class for printing errors in a different color.Script 4.2. With this minimalist registration form, the Filter library is used to perform data validation and sanitization.
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 4 <head> 5 <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> 6 <title>Filter</title> 7 <style type="text/css" title="text/css" media="all"> 8 .error { 9 color: #F30; 10 } 11 </style> 12 </head> 13 <body> 14 <?php # Script 4.2 - filter.php 15 16 /* This page uses the Filter functions 17 * to validate form data. 18 * This page will print out the filtered data. 19 */ 20 21 if (isset($_POST['submitted'])) { // Handle the form. 22 23 // Sanitize the name: 24 $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 25 if ($name) { 26 echo "<p>Name: $name<br />\$_POST['name']: {$_POST['name']}</p>\n"; 27 } else { 28 echo '<p class="error">Please enter your name.</p>'; 29 } 30 31 // Validate the email address using FILTER_VALIDATE_EMAIL: 32 $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); 33 if ($email) { 34 echo "<p>Email Address: $email</p>\n"; 35 } else { 36 echo '<p class="error">Please enter your email address.</p>'; 37 } 38 39 // Validate the ICQ number using FILTER_VALIDATE_INT: 40 $icq = filter_input(INPUT_POST, 'icq', FILTER_VALIDATE_INT); 41 if ($icq) { 42 echo "<p>ICQ Number: $icq</p>\n"; 43 } else { 44 echo '<p class="error">Please enter your ICQ number.</p>'; 45 } 46 47 // Strip tags but don't encode quotes: 48 $comments = filter_input(INPUT_POST, 'comments', FILTER_SANITIZE_STRING); 49 if ($comments) { 50 echo "<p>Comments: $comments<br />\$_POST['comments']: {$_POST['comments']}</p>\n"; 51 } else { 52 echo '<p class="error">Please enter your comments.</p>'; 53 } 54 55 } // End of $_POST['submitted'] IF. 56 57 // Show the form. 58 ?> 59 <form method="post" action="filter.php"> 60 <fieldset> 61 <legend>Registration Form</legend> 62 <p>Name: <input type="text" name="name" /></p> 63 <p>Email Address: <input type="text" name="email" /></p> 64 <p>ICQ Number: <input type="text" name="icq" /></p> 65 <p>Comments: <textarea name="comments" rows="5" cols="40"></textarea></p> 66 67 <input type="hidden" name="submitted" value="true" /> 68 <input type="submit" name="submit" value="Submit" /> 69 </fieldset> 70 </form> 71 72 </body> 73 </html>
- Check for the form submission.
if (isset($_POST['submitted'])) {
- Filter the name data.
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
For the name field, there's no type to validate against, but it can be filtered to remove any HTML tags. The FILTER_SANITIZE_STRING filter will accomplish that. The last argument, FILTER_FLAG_NO_ENCODE_QUOTES, says that any quotation marks in the name (e.g., O'Toole) shouldn't be turned into an HTML entity equivalent. - Print the name value or an error.
if ($name) { echo "<p>Name: $name<br/>\$_POST['name']: {$_POST['name']}</p>\n"; } else { echo '<p class="error">Please enter your name.</p>'; }
The conditional if ($name) will be true if the $_POST['name'] variable was set and passed the filter. In that case, I'll print the filtered version and the original version, just for comparison. - Validate the email address.
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); if ($email) { echo "<p>Email Address: $email</p>\n"; } else { echo '<p class="error">Please enter your email address.</p>'; }
The FILTER_VALIDATE_EMAIL filter is perfect here. If the submitted email address has a valid format, it will be returned. Otherwise, $email will equal either FALSE or NULL. - Validate the ICQ number.
$icq = filter_input(INPUT_POST, 'icq', FILTER_VALIDATE_INT); if ($icq) { echo "<p>ICQ Number: $icq</p>\n"; } else { echo '<p class="error">Please enter your ICQ number.</p>'; }
This is validated as an integer. - Filter the comments field.
$comments = filter_input(INPUT_POST, 'comments', FILTER_SANITIZE_STRING); if ($comments) { echo "<p>Comments: $comments<br/>\$_POST['comments']: {$_POST['comments']}</p>\n"; } else { echo '<p class="error">Please enter your comments.</p>'; }
For the comments, any tags will be stripped (as with the name), but the quotation marks will also be encoded. - Complete the main conditional and the PHP code.
} // End of $_POST['submitted'] IF. ?>
- Create the HTML form.
<form method="post" action="filter.php"> <fieldset> <legend>Registration Form</legend> <p>Name: <input type="text" name="name" /></p> <p>Email Address: <input type="text" name="email" /></p> <p>ICQ Number: <input type="text" name="icq" /></p> <p>Comments: <textarea name="comments" rows="5" cols="40"></textarea></p> <input type="hidden" name="submitted" value="true" /> <input type="submit" name="submit" value="Submit" /> </fieldset> </form>
- Complete the page.
</body> </html>
- Save the file as filter.php, place it in your Web directory, and test in your Web browser (Figures 4.5 and
4.6).
Figure 4.5 These values will be submitted, then filtered, resulting in Figure 4.6.
Figure 4.6 At the top of the form the filtered values are displayed.
- View the HTML source of the page to see how the name and comments fields were treated (Figure 4.7).
Figure 4.7 The HTMLsource code shows how all tags are stripped from the name and comments fields, plus how quotation marks in the comments are encoded.