<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>PHP Cookbook/Forms - Revision history</title>
		<link>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Forms&amp;action=history</link>
		<description>Revision history for this page on the wiki</description>
		<language>en</language>
		<generator>MediaWiki 1.11.0</generator>
		<lastBuildDate>Wed, 19 Jun 2013 09:41:12 GMT</lastBuildDate>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Forms&amp;diff=7321&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:36, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:36:04 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:PHP_Cookbook/Forms</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Forms&amp;diff=3121&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:30, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:30:05 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:PHP_Cookbook/Forms</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Forms&amp;diff=3120&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{PHP Cookbook/TOC}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The genius of PHP is its seamless integration of form variables into your programs. It makes web programming smooth and simple, from web form to PHP code to HTML output.&lt;br /&gt;
&lt;br /&gt;
There's no built-in mechanism in HTTP to allow you to save information from one page so you can access it in other pages. That's because HTTP is a stateless protocol. [[PHP Cookbook/Forms#Processing Form Input|Recipe 9.2]], [[PHP Cookbook/Forms#Working with Multipage Forms|Recipe 9.4]], [[PHP Cookbook/Forms#Redisplaying Forms with Preserved Information and Error Messages|Recipe 9.5]], and [[PHP Cookbook/Forms#Guarding Against Multiple Submission of the Same Form|Recipe 9.6]] all show ways to work around the fundamental problem of figuring out which user is making which requests to your web server.&lt;br /&gt;
&lt;br /&gt;
Processing data from the user is the other main topic of this chapter. You should never trust the data coming from the browser, so it's imperative to always validate all fields, even hidden form elements. Validation takes many forms, from ensuring the data match certain criteria, as discussed in [[PHP Cookbook/Forms#Validating Form Input|Recipe 9.3]], to escaping HTML entities to allow the safe display of user entered data, as covered in [[PHP Cookbook/Forms#Escaping Control Characters from User Data|Recipe 9.9]]. Furthermore, [[PHP Cookbook/Forms#Securing PHP's Form Processing|Recipe 9.8]] tells how to protect the security of your web server, and [[PHP Cookbook/Forms#Processing Uploaded Files|Recipe 9.7]] covers how to process files uploaded by a user.&lt;br /&gt;
&lt;br /&gt;
Whenever PHP processes a page, it checks for GET and POST form variables, uploaded files, applicable cookies, and web server and environment variables. These are then directly accessible in the following arrays: &amp;lt;tt&amp;gt;$_GET&amp;lt;/tt&amp;gt; , &amp;lt;tt&amp;gt;$_POST&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$_FILES&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$_COOKIE&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$_SERVER&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$_ENV&amp;lt;/tt&amp;gt;. They hold, respectively, all variables set by GET requests, POST requests, uploaded files, cookies, the web server, and the environment. There's also &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt; , which is one giant array that contains the values from the other six arrays.&lt;br /&gt;
&lt;br /&gt;
When placing elements inside of &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt;, if two arrays both have a key with the same name, PHP falls back upon the &amp;lt;tt&amp;gt;variables_order&amp;lt;/tt&amp;gt; configuration directive. By default, &amp;lt;tt&amp;gt;variables_order&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;EGPCS&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;GPCS&amp;lt;/tt&amp;gt;, if you're using the ''php.ini-recommended'' configuration file). So, PHP first adds environment variables to &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt; and then adds GET, POST, cookie, and web server variables to the array, in this order. For instance, since &amp;lt;tt&amp;gt;C&amp;lt;/tt&amp;gt; comes after &amp;lt;tt&amp;gt;P&amp;lt;/tt&amp;gt; in the default order, a cookie named &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; overwrites a POST variable named &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you don't have access to PHP's configuration files, you can use &amp;lt;tt&amp;gt;ini_get( )&amp;lt;/tt&amp;gt; to check a setting:&lt;br /&gt;
&lt;br /&gt;
 print ini_get('variables_order');&lt;br /&gt;
 '''EGPCS'''&lt;br /&gt;
          &lt;br /&gt;
&lt;br /&gt;
You may need to do this because your ISP doesn't let you view configuration settings or because your script may run on someone else's server. You can also use &amp;lt;tt&amp;gt;phpinfo( )&amp;lt;/tt&amp;gt; to view settings. However, if you can't rely on the value of &amp;lt;tt&amp;gt;variables_order&amp;lt;/tt&amp;gt;, you should directly access &amp;lt;tt&amp;gt;$_GET&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$_POST&amp;lt;/tt&amp;gt; instead of using &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The arrays containing external variables, such as &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt;, are superglobals. As such, they don't need to be declared as &amp;lt;tt&amp;gt;global&amp;lt;/tt&amp;gt; inside of a function or class. It also means you probably shouldn't assign anything to these variables, or you'll overwrite the data stored in them.&lt;br /&gt;
&lt;br /&gt;
Prior to PHP 4.1, these superglobal variables didn't exist. Instead there were regular arrays named &amp;lt;tt&amp;gt;$HTTP_COOKIE_VARS&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$HTTP_ENV_VARS&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$HTTP_GET_VARS&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$HTTP_POST_VARS&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$HTTP_POST_FILES&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$HTTP_SERVER_VARS&amp;lt;/tt&amp;gt;. These arrays are still available for legacy reasons, but the newer arrays are easier to work with. These older arrays are populated only if the &amp;lt;tt&amp;gt;track_vars&amp;lt;/tt&amp;gt; configuration directive is &amp;lt;tt&amp;gt;on&amp;lt;/tt&amp;gt;, but, as of PHP 4.0.3, this feature is always enabled.&lt;br /&gt;
&lt;br /&gt;
Finally, if the &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; configuration directive is &amp;lt;tt&amp;gt;on&amp;lt;/tt&amp;gt;, all these variables are also available as variables in the global namespace. So, &amp;lt;tt&amp;gt;$_GET['password']&amp;lt;/tt&amp;gt; is also just &amp;lt;tt&amp;gt;$password&amp;lt;/tt&amp;gt;. While convenient, this introduces major security problems because malicious users can easily set variables from the outside and overwrite trusted internal variables. Starting with PHP 4.2, &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; defaults to &amp;lt;tt&amp;gt;off&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
With this knowledge, here is a basic script to put things together. The form asks the user to enter his first name, then replies with a welcome message. The HTML for the form looks like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;form action=&amp;quot;/hello.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
 What is your first name?&lt;br /&gt;
 &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;first_name&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Say Hello&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;/form&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; of the text &amp;lt;tt&amp;gt;input&amp;lt;/tt&amp;gt; element inside the form is &amp;lt;tt&amp;gt;first_name&amp;lt;/tt&amp;gt;. Also, the &amp;lt;tt&amp;gt;method&amp;lt;/tt&amp;gt; of the form is &amp;lt;tt&amp;gt;post&amp;lt;/tt&amp;gt;. This means that when the form is submitted, &amp;lt;tt&amp;gt;$_POST['first_name']&amp;lt;/tt&amp;gt; will hold whatever string the user typed in. (It could also be empty, of course, if he didn't type anything.)&lt;br /&gt;
&lt;br /&gt;
For simplicity, however, let's assume the value in the variable is valid. (The term &amp;quot;valid&amp;quot; is open for definition, depending on certain criteria, such as not being empty, not being an attempt to break into the system, etc.) This allows us to omit the error checking stage, which is important but gets in the way of this simple example. So, here is a simple ''hello.php'' script to process the form:&lt;br /&gt;
&lt;br /&gt;
 echo 'Hello ' . $_POST['first_name'] . '!';&lt;br /&gt;
&lt;br /&gt;
If the user's first name is Joe, PHP prints out:&lt;br /&gt;
&lt;br /&gt;
 Hello Joe!&lt;br /&gt;
&lt;br /&gt;
== Processing Form Input ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to use the same HTML page to emit a form and then process the data entered into it. In other words, you're trying to avoid a proliferation of pages that each handle different steps in a transaction.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use a hidden field in the form to tell your program that it's supposed to be processing the form. In this case, the hidden field is named &amp;lt;tt&amp;gt;stage&amp;lt;/tt&amp;gt; and has a value of &amp;lt;tt&amp;gt;process&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 if (isset($_POST['stage']) &amp;amp;&amp;amp; ('process' == $_POST['stage'])) {&lt;br /&gt;
     process_form();&lt;br /&gt;
 } else {&lt;br /&gt;
     print_form();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
During the early days of the Web, when people created forms, they made two pages: a static HTML page with the form and a script that processed the form and returned a dynamically generated response to the user. This was a little unwieldy, because ''form.html'' led to ''form.cgi'' and if you changed one page, you needed to also remember to edit the other, or your script might break.&lt;br /&gt;
&lt;br /&gt;
Forms are easier to maintain when all parts live in the same file and context dictates which sections to display. Use a hidden form field named &amp;lt;tt&amp;gt;stage&amp;lt;/tt&amp;gt; to track your position in the flow of the form process; it acts as a trigger for the steps that return the proper HTML to the user. Sometimes, however, it's not possible to design your code to do this; for example, when your form is processed by a script on someone else's server.&lt;br /&gt;
&lt;br /&gt;
When writing the HTML for your form, however, don't hardcode the path to your page directly into the &amp;lt;tt&amp;gt;action&amp;lt;/tt&amp;gt;. This makes it impossible to rename or relocate your page without also editing it. Instead, PHP supplies a helpful variable:&lt;br /&gt;
&lt;br /&gt;
 $_SERVER['PHP_SELF'] &lt;br /&gt;
&lt;br /&gt;
This variable is an alias to the URL of the current page. So, set the value of the &amp;lt;tt&amp;gt;action&amp;lt;/tt&amp;gt; attribute to that value, and your form always resubmits, even if you've moved the file to a new place on the server.&lt;br /&gt;
&lt;br /&gt;
So, the example in the introduction of this chapter is now:&lt;br /&gt;
&lt;br /&gt;
 if (isset($_POST['stage']) &amp;amp;&amp;amp; ('process' == $_POST['stage'])) {&lt;br /&gt;
     process_form();&lt;br /&gt;
 } else {&lt;br /&gt;
     print_form();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function print_form() {&lt;br /&gt;
     echo &amp;lt;&amp;lt;&amp;lt;END&lt;br /&gt;
         &amp;lt;form action=&amp;quot;$_SERVER[PHP_SELF]&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
         What is your first name?&lt;br /&gt;
         &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;first_name&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;stage&amp;quot; value=&amp;quot;process&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Say Hello&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;/form&amp;gt;&lt;br /&gt;
 END;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function process_form() {&lt;br /&gt;
     echo 'Hello ' . $_POST['first_name'] . '!';&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If your form has more than one step, just set &amp;lt;tt&amp;gt;stage&amp;lt;/tt&amp;gt; to a new value for each step.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Forms#Working with Multipage Forms|Recipe 9.4]] for handling multipage forms.&lt;br /&gt;
&lt;br /&gt;
== Validating Form Input ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to ensure data entered from a form passes certain criteria.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Create a function that takes a string to validate and returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the string passes a check and &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; if it doesn't. Inside the function, use regular expressions and comparisons to check the data. For example, [[PHP Cookbook/Forms#phpckbk-CHP-9-EX-1|Example 9-1]] shows the &amp;lt;tt&amp;gt;pc_validate_zipcode( )&amp;lt;/tt&amp;gt; function, which validates a U.S. Zip Code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-9-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 9-1. pc_validate_zipcode( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_validate_zipcode($zipcode) {&lt;br /&gt;
     return preg_match('/^[0-9]{5}([- ]?[0-9]{4})?$/', $zipcode);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here's how to use it:&lt;br /&gt;
&lt;br /&gt;
 if (pc_validate_zipcode($_REQUEST['zipcode'])) {&lt;br /&gt;
     // U.S. Zip Code is okay, can proceed&lt;br /&gt;
     process_data();&lt;br /&gt;
 } else {&lt;br /&gt;
     // this is not an okay Zip Code, print an error message&lt;br /&gt;
     print &amp;quot;Your ZIP Code is should be 5 digits (or 9 digits, if you're &amp;quot;;&lt;br /&gt;
     print &amp;quot;using ZIP+4).&amp;quot;;&lt;br /&gt;
     print_form();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Deciding what constitutes valid and invalid data is almost more of a philosophical task than a straightforward matter of following a series of fixed steps. In many cases, what may be perfectly fine in one situation won't be correct in another.&lt;br /&gt;
&lt;br /&gt;
The easiest check is making sure the field isn't blank. The &amp;lt;tt&amp;gt;empty( )&amp;lt;/tt&amp;gt; function best handles this problem.&lt;br /&gt;
&lt;br /&gt;
Next come relatively easy checks, such as the case of a U.S. Zip Code. Usually, a regular expression or two can solve these problems. For example:&lt;br /&gt;
&lt;br /&gt;
  /^[0-9]{5}([- ]?[0-9]{4})?$/ &lt;br /&gt;
&lt;br /&gt;
finds all valid U.S. Zip Codes.&lt;br /&gt;
&lt;br /&gt;
Sometimes, however, coming up with the correct regular expression is difficult. If you want to verify that someone has entered only two names, such as &amp;quot;Alfred Aho,&amp;quot; you can check against:&lt;br /&gt;
&lt;br /&gt;
  /^[A-Za-z]+ +[A-Za-z]+$/&lt;br /&gt;
&lt;br /&gt;
However, Tim O'Reilly can't pass this test. An alternative is &amp;lt;tt&amp;gt;/^\S+\s+\S+$/&amp;lt;/tt&amp;gt;; but then Donald E. Knuth is rejected. So think carefully about the entire range of valid input before writing your regular expression.&lt;br /&gt;
&lt;br /&gt;
In some instances, even with regular expressions, it becomes difficult to check if the field is legal. One particularly popular and tricky task is validating an email address, as discussed in [[PHP Cookbook/Regular Expressions#Finding All Lines in a File That Match a Pattern|Recipe 13.7]]. Another is how to make sure a user has correctly entered the name of her U.S. state. You can check against a listing of names, but what if she enters her postal service abbreviation? Will MA instead of Massachusetts work? What about Mass.?&lt;br /&gt;
&lt;br /&gt;
One way to avoid this issue is to present the user with a dropdown list of pregenerated choices. Using a &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt; element, users are forced by the form's design to select a state in the format that always works, which can reduce errors. This, however, presents another series of difficulties. What if the user lives some place that isn't one of the choices? What if the range of choices is so large this isn't a feasible solution?&lt;br /&gt;
&lt;br /&gt;
There are a number of ways to solve these types of problems. First, you can provide an &amp;quot;other&amp;quot; option in the list, so that a non-U.S. user can successfully complete the form. (Otherwise, she'll probably just pick a place at random, so she can continue using your site.) Next, you can divide the registration process into a two-part sequence. For a long list of options, a user begins by picking the letter of the alphabet his choice begins with; then, a new page provides him with a list containing only the choices beginning with that letter.&lt;br /&gt;
&lt;br /&gt;
Finally, there are even trickier problems. What do you do when you want to make sure the user has correctly entered information, but you don't want to tell her you did so? A situation where this is important is a sweepstakes; in a sweepstakes, there's often a special code box on the entry form in which a user enters a string — &amp;lt;tt&amp;gt;AD78DQ&amp;lt;/tt&amp;gt; — from an email or flier she's received. You want to make sure there are no typos, or your program won't count her as a valid entrant. You also don't want to allow her to just guess codes, because then she could try out those codes and crack the system.&lt;br /&gt;
&lt;br /&gt;
The solution is to have two input boxes. A user enters her code twice; if the two fields match, you accept the data as legal and then (silently) validate the data. If the fields don't match, you reject the entry and have the user fix it. This procedure eliminates typos and doesn't reveal how the code validation algorithm works; it can also prevent misspelled email addresses.&lt;br /&gt;
&lt;br /&gt;
Finally, PHP performs server-side validation. Server-side validation requires that a request be made to the server, and a page returned in response; as a result, it can be slow. It's also possible to do client-side validation using JavaScript. While client-side validation is faster, it exposes your code to the user and may not work if the client doesn't support JavaScript or has disabled it. Therefore, you should always duplicate all client-side validation code on the server.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Regular Expressions#Finding All Lines in a File That Match a Pattern|Recipe 13.7]] for a regular expression for validating email addresses; [[PHP Cookbook/Classes and Objects|Chapter 7]], &amp;quot;Validation on the Server and Client,&amp;quot; of ''Web Database Applications with PHP and MySQL'' (Hugh Williams and David Lane, O'Reilly).&lt;br /&gt;
&lt;br /&gt;
== Working with Multipage Forms ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to use a form that displays more than one page and preserve data from one page to the next.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use session tracking:&lt;br /&gt;
&lt;br /&gt;
 session_start();&lt;br /&gt;
 $_SESSION['username'] = $_GET['username'];&lt;br /&gt;
&lt;br /&gt;
You can also include variables from a form's earlier pages as hidden input fields in its later pages:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;username&amp;quot; &lt;br /&gt;
        value=&amp;quot;&amp;lt;?php echo htmlentities($_GET['username']); ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Whenever possible, use session tracking. It's more secure because users can't modify session variables. To begin a session, call &amp;lt;tt&amp;gt;session_start( )&amp;lt;/tt&amp;gt;; this creates a new session or resumes an existing one. Note that this step is unnecessary if you've enabled &amp;lt;tt&amp;gt;session.auto_start&amp;lt;/tt&amp;gt; in your ''php.ini'' file. Variables assigned to &amp;lt;tt&amp;gt;$_SESSION&amp;lt;/tt&amp;gt; are automatically propagated. In the Solution example, the form's username variable is preserved by assigning &amp;lt;tt&amp;gt;$_GET['username']&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;$_SESSION['username']&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To access this value on a subsequent request, call &amp;lt;tt&amp;gt;session_start( )&amp;lt;/tt&amp;gt; and then check &amp;lt;tt&amp;gt;$_SESSION['username']&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 session_start( );&lt;br /&gt;
 $username = htmlentities($_SESSION['username']);&lt;br /&gt;
 print &amp;quot;Hello $username.&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
In this case, if you don't call &amp;lt;tt&amp;gt;session_start( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$_SESSION&amp;lt;/tt&amp;gt; isn't set.&lt;br /&gt;
&lt;br /&gt;
Be sure to secure the server and location where your session files are located (the filesystem, database, etc.); otherwise your system will be vulnerable to identity spoofing.&lt;br /&gt;
&lt;br /&gt;
If session tracking isn't enabled for your PHP installation, you can use hidden form variables as a replacement. However, passing data using hidden form elements isn't secure because anyone can edit these fields and fake a request; with a little work, you can increase the security to a reliable level.&lt;br /&gt;
&lt;br /&gt;
The most basic way to use hidden fields is to include them inside your form.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;form action=&amp;quot;&amp;lt;?php echo $_SERVER['PHP_SELF']; ?&amp;gt;&amp;quot;&lt;br /&gt;
       method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;username&amp;quot; &lt;br /&gt;
        value=&amp;quot;&amp;lt;?php echo htmlentities($_GET['username']); ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this form is resubmitted, &amp;lt;tt&amp;gt;$_GET['username']&amp;lt;/tt&amp;gt; holds its previous value unless someone has modified it.&lt;br /&gt;
&lt;br /&gt;
A more complex but secure solution is to convert your variables to a string using &amp;lt;tt&amp;gt;serialize( )&amp;lt;/tt&amp;gt; , compute a secret hash of the data, and place both pieces of information in the form. Then, on the next request, validate the data and unserialize it. If it fails the validation test, you'll know someone has tried to modify the information.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_encode( )&amp;lt;/tt&amp;gt; encoding function shown in [[PHP Cookbook/Forms#phpckbk-CHP-9-EX-2|Example 9-2]] takes the data to encode in the form of an array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-9-EX-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 9-2. pc_encode( )'''&lt;br /&gt;
&lt;br /&gt;
 $secret = 'Foo25bAr52baZ';&lt;br /&gt;
 &lt;br /&gt;
 function pc_encode($data) {&lt;br /&gt;
   $data = serialize($data);&lt;br /&gt;
   $hash = md5($GLOBALS['secret'] . $data);&lt;br /&gt;
   return array($data, $hash);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In function &amp;lt;tt&amp;gt;pc_encode( )&amp;lt;/tt&amp;gt;, the data is serialized into a string, a validation hash is computed, and those variables are returned.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_decode( )&amp;lt;/tt&amp;gt; function shown in [[PHP Cookbook/Forms#phpckbk-CHP-9-EX-3|Example 9-3]] undoes the work of its counterpart.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-9-EX-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 9-3. pc_decode( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_decode($data, $hash) {&lt;br /&gt;
   if (!empty($data) &amp;amp;&amp;amp; !empty($hash)) {&lt;br /&gt;
     if (md5($GLOBALS['secret'] . $data) == $hash) {&lt;br /&gt;
       return unserialize($data);&lt;br /&gt;
     } else {&lt;br /&gt;
       error_log(&amp;quot;Validation Error: Data has been modified&amp;quot;);&lt;br /&gt;
       return false;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   return false;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_decode( )&amp;lt;/tt&amp;gt; function recreates the hash of the secret word and compares it to the hash value from the form. If they're equal, &amp;lt;tt&amp;gt;$data&amp;lt;/tt&amp;gt; is valid, so it's unserialized. If it flunks the test, the function writes a message to the error log and returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
These functions go together like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 $secret = 'Foo25bAr52baZ';&lt;br /&gt;
 &lt;br /&gt;
 // Load in and validate old data&lt;br /&gt;
 if (! $data = pc_decode($_GET['data'], $_GET['hash'])) {&lt;br /&gt;
   // crack attempt&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // Process form (new form data is in $_GET)&lt;br /&gt;
 &lt;br /&gt;
 // Update $data&lt;br /&gt;
 $data['username'] = $_GET['username'];&lt;br /&gt;
 $data['stage']++;&lt;br /&gt;
 unset($data['password']);&lt;br /&gt;
 &lt;br /&gt;
 // Encode results&lt;br /&gt;
 list ($data, $hash) = pc_encode($data);&lt;br /&gt;
 &lt;br /&gt;
 // Store data and hash inside the form&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
 &amp;lt;form action=&amp;quot;&amp;lt;?php echo $_SERVER['PHP_SELF']; ?&amp;gt;&amp;quot; method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;data&amp;quot; &lt;br /&gt;
        value=&amp;quot;&amp;lt;?php echo htmlentities($data); ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;hash&amp;quot; &lt;br /&gt;
        value=&amp;quot;&amp;lt;?php echo htmlentities($hash); ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;/form&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At the top of the script, we pass &amp;lt;tt&amp;gt;pc_decode( )&amp;lt;/tt&amp;gt; the variables from the form for decoding. Once the information is loaded into &amp;lt;tt&amp;gt;$data&amp;lt;/tt&amp;gt;, form processing can proceed by checking in &amp;lt;tt&amp;gt;$_GET&amp;lt;/tt&amp;gt; for new variables and in &amp;lt;tt&amp;gt;$data&amp;lt;/tt&amp;gt; for old ones. Once that's complete, update &amp;lt;tt&amp;gt;$data&amp;lt;/tt&amp;gt; to hold the new values and then encode it, calculating a new hash in the process. Finally, print out the new form and include &amp;lt;tt&amp;gt;$data&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$hash&amp;lt;/tt&amp;gt; as hidden variables.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Web Basics#Using Session Tracking|Recipe 8.6]] and [[PHP Cookbook/Web Basics#Storing Sessions in a Database|Recipe 8.7]] for information on using the session module; [[PHP Cookbook/Forms#Escaping Control Characters from User Data|Recipe 9.9]] for details on using &amp;lt;tt&amp;gt;htmlentities( )&amp;lt;/tt&amp;gt; to escape control characters in HTML output; [[PHP Cookbook/Encryption and Security#Verifying Data with Hashes|Recipe 14.4]] for information on verifying data with hashes; documentation on session tracking at ''http://www.php.net/session'' and in [[PHP Cookbook/Web Basics#Redirecting to a Different Location|Recipe 8.5]]; documentation on &amp;lt;tt&amp;gt;serialize( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/serialize'' and &amp;lt;tt&amp;gt;unserialize( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/unserialize''.&lt;br /&gt;
&lt;br /&gt;
== Redisplaying Forms with Preserved Information and Error Messages ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
When there's a problem with data entered in a form, you want to print out error messages alongside the problem fields, instead of a generic error message at the top of the form. You also want to preserve the values the user typed into the form the first time.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use an array, &amp;lt;tt&amp;gt;$errors&amp;lt;/tt&amp;gt;, and store your messages in the array indexed by the name of the field.&lt;br /&gt;
&lt;br /&gt;
 if (! pc_validate_zipcode($_REQUEST['zipcode'])) {&lt;br /&gt;
     $errors['zipcode'] = &amp;quot;This is is a bad ZIP Code. ZIP Codes must &amp;quot;&lt;br /&gt;
                        . &amp;quot;have 5 numbers and no letters.&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
When you redisplay the form, you can display each error by its field and include the original value in the field:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;echo $errors['zipcode'];&lt;br /&gt;
$value = isset($_REQUEST['zipcode']) ?&lt;br /&gt;
               htmlentities($_REQUEST['zipcode']) : '';&lt;br /&gt;
echo &amp;quot;&amp;lt;input type=\&amp;quot;text\&amp;quot; name=\&amp;quot;zipcode\&amp;quot; value=\&amp;quot;$value\&amp;quot;&amp;gt;&amp;quot;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
If your users encounter errors when filling out a long form, you can increase the overall usability of your form if you highlight exactly where the errors need to be fixed.&lt;br /&gt;
&lt;br /&gt;
Consolidating all errors in a single array has many advantages. First, you can easily check if your validation process has located any items that need correction; just use &amp;lt;tt&amp;gt;count($errors)&amp;lt;/tt&amp;gt;. This method is easier than trying to keep track of this fact in a separate variable, especially if the flow is complex or spread out over multiple functions. [[PHP Cookbook/Forms#phpckbk-CHP-9-EX-4|Example 9-4]] shows the &amp;lt;tt&amp;gt;pc_validate_form( )&amp;lt;/tt&amp;gt; validation function, which uses an &amp;lt;tt&amp;gt;$errors&amp;lt;/tt&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-9-EX-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 9-4. pc_validate_form( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_validate_form( ) {&lt;br /&gt;
   if (! pc_validate_zipcode($_POST['zipcode'])) {&lt;br /&gt;
      $errors['zipcode'] = &amp;quot;ZIP Codes are 5 numbers&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   if (! pc_validate_email($_POST['email'])) {&lt;br /&gt;
      $errors['email'] = &amp;quot;Email addresses look like user@example.com&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return $errors;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is clean code because all errors are stored in one variable. You can easily pass around the variable if you don't want it to live in the global scope.&lt;br /&gt;
&lt;br /&gt;
Using the variable name as the key preserves the links between the field that caused the error and the actual error message itself. These links also make it easy to loop through items when displaying errors.&lt;br /&gt;
&lt;br /&gt;
You can automate the repetitive task of printing the form; the &amp;lt;tt&amp;gt;pc_print_form()&amp;lt;/tt&amp;gt; function in [[PHP Cookbook/Forms#phpckbk-CHP-9-EX-5|Example 9-5]] shows how.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-9-EX-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 9-5. pc_print_form( )'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;function pc_print_form($errors) {&lt;br /&gt;
    $fields = array('name'   =&amp;gt; 'Name',&lt;br /&gt;
                    'rank'   =&amp;gt; 'Rank', &lt;br /&gt;
                    'serial' =&amp;gt; 'Serial');&lt;br /&gt;
&lt;br /&gt;
    if (count($errors)) { &lt;br /&gt;
        echo 'Please correct the errors in the form below.';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    echo '&amp;lt;table&amp;gt;';&lt;br /&gt;
&lt;br /&gt;
    // print out the errors and form variables&lt;br /&gt;
    foreach ($fields as $field =&amp;gt; $field_name) {&lt;br /&gt;
        // open row&lt;br /&gt;
        echo '&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;';&lt;br /&gt;
&lt;br /&gt;
        // print error&lt;br /&gt;
        if (!empty($errors[$field])) {&lt;br /&gt;
            echo $errors[$field];&lt;br /&gt;
        } else {&lt;br /&gt;
            echo '&amp;amp;amp;nbsp;'; // to prevent odd looking tables&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        echo &amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        // print name and input&lt;br /&gt;
        $value = isset($_REQUEST[$field]) ? &lt;br /&gt;
                       htmlentities($_REQUEST[$field]) : '';&lt;br /&gt;
&lt;br /&gt;
        echo &amp;quot;$field_name: &amp;quot;;&lt;br /&gt;
        echo &amp;quot;&amp;lt;input type=\&amp;quot;text\&amp;quot; name=\&amp;quot;$field\&amp;quot; value=\&amp;quot;$value\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
        echo '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    echo '&amp;lt;/table&amp;gt;';&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complex part of &amp;lt;tt&amp;gt;pc_print_form( )&amp;lt;/tt&amp;gt; comes from the &amp;lt;tt&amp;gt;$fields&amp;lt;/tt&amp;gt; array. The key is the variable name; the value is the pretty display name. By defining them at the top of the function, you can create a loop and use &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt; to iterate through the values; otherwise, you need three separate lines of identical code. This integrates with the variable name as a key in &amp;lt;tt&amp;gt;$errors&amp;lt;/tt&amp;gt;, because you can find the error message inside the loop just by checking &amp;lt;tt&amp;gt;$errors[$field]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you want to extend this example beyond &amp;lt;tt&amp;gt;input&amp;lt;/tt&amp;gt; fields of type &amp;lt;tt&amp;gt;text&amp;lt;/tt&amp;gt;, modify &amp;lt;tt&amp;gt;$fields&amp;lt;/tt&amp;gt; to include more meta-information about your form fields:&lt;br /&gt;
&lt;br /&gt;
 $fields = array('name' =&amp;gt; array('name' =&amp;gt; 'Name', 'type' =&amp;gt; 'text'),&lt;br /&gt;
                 'rank' =&amp;gt; array('name' =&amp;gt; 'Rank', 'type' =&amp;gt; 'password'),&lt;br /&gt;
                 'serial' =&amp;gt; array('name' =&amp;gt; 'Serial', 'type' =&amp;gt; 'hidden')&lt;br /&gt;
                );&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Forms#Validating Form Input|Recipe 9.3]] for simple form validation.&lt;br /&gt;
&lt;br /&gt;
== Guarding Against Multiple Submission of the Same Form ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to prevent people from submitting the same form multiple times.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Generate a unique identifier and store the token as a hidden field in the form. Before processing the form, check to see if that token has already been submitted. If it hasn't, you can proceed; if it has, you should generate an error.&lt;br /&gt;
&lt;br /&gt;
When creating the form, use &amp;lt;tt&amp;gt;uniqid( )&amp;lt;/tt&amp;gt; to get a unique identifier:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 $unique_id = uniqid(microtime(),1);&lt;br /&gt;
 ...&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;unique_id&amp;quot; value=&amp;quot;&amp;lt;?php echo $unique_id; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;/form&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, when processing, look for this ID:&lt;br /&gt;
&lt;br /&gt;
 $unique_id  = $dbh-&amp;gt;quote($_GET['unique_id']);&lt;br /&gt;
 $sth = $dbh-&amp;gt;query(&amp;quot;SELECT * FROM database WHERE unique_id = $unique_id&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 if ($sth-&amp;gt;numRows( )) {&lt;br /&gt;
     // already submitted, throw an error&lt;br /&gt;
 } else {&lt;br /&gt;
    // act upon the data&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
For a variety of reasons, users often resubmit a form. Usually it's a slip-of-the-mouse: double-clicking the Submit button. They may hit their web browser's Back button to edit or recheck information, but then they re-hit Submit instead of Forward. It can be intentional: they're trying to stuff the ballot box for an online survey or sweepstakes. Our Solution prevents the nonmalicious attack and can slow down the malicious user. It won't, however, eliminate all fraudulent use: more complicated work is required for that.&lt;br /&gt;
&lt;br /&gt;
The Solution does prevent your database from being cluttered with too many copies of the same record. By generating a token that's placed in the form, you can uniquely identify that specific instance of the form, even when cookies is disabled. When you then save the form's data, you store the token alongside it. That allows you to easily check if you've already seen this form and record the database it belongs to.&lt;br /&gt;
&lt;br /&gt;
Start by adding an extra column to your database table — &amp;lt;tt&amp;gt;unique_id&amp;lt;/tt&amp;gt; — to hold the identifier. When you insert data for a record, add the ID also. For example:&lt;br /&gt;
&lt;br /&gt;
 $username  = $dbh-&amp;gt;quote($_GET['username']);&lt;br /&gt;
 $unique_id = $dbh-&amp;gt;quote($_GET['unique_id']);&lt;br /&gt;
 &lt;br /&gt;
 $sth = $dbh-&amp;gt;query(&amp;quot;INSERT INTO members ( username,  unique_id)&lt;br /&gt;
                                  VALUES ($username, $unique_id)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
By associating the exact row in the database with the form, you can more easily handle a resubmission. There's no correct answer here; it depends on your situation. In some cases, you'll want to ignore the second posting all together. In others, you'll want to check if the record has changed, and, if so, present the user with a dialog box asking if they want to update the record with the new information or keep the old data. Finally, to reflect the second form submission, you could update the record silently, and the user never learns of a problem.&lt;br /&gt;
&lt;br /&gt;
All these possibilities should be considered given the specifics of the interaction. Our opinion is there's no reason to allow the deficits of HTTP to dictate the user experience. So, while the third choice, silently updating the record, isn't what normally happens, in many ways this is the most natural option. Applications we've developed with this method are more user friendly; the other two methods confuse or frustrate most users.&lt;br /&gt;
&lt;br /&gt;
It's tempting to avoid generating a random token and instead use a number one greater then the number of records already in the database. The token and the primary key will thus be the same, and you don't need to use an extra column. There are (at least) two problems with this method. First, it creates a race condition. What happens when a second person starts the form before the first person has completed it? The second form will then have the same token as the first, and conflicts will occur. This can be worked around by creating a new blank record in the database when the form is requested, so the second person will get a number one higher than the first. However, this can lead to empty rows in the database if users opt not to complete the form.&lt;br /&gt;
&lt;br /&gt;
The other reason not do this is because it makes it trivial to edit another record in the database by manually adjusting the ID to a different number. Depending on your security settings, a fake GET or POST submission allows the data to be altered without difficulty. A long random token, however, can't be guessed merely by moving to a different integer.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Encryption and Security#Verifying Data with Hashes|Recipe 14.4]] for more details on verifying data with hashes; documentation on &amp;lt;tt&amp;gt;uniqid( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/uniqid''.&lt;br /&gt;
&lt;br /&gt;
== Processing Uploaded Files ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to process a file uploaded by a user.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use the &amp;lt;tt&amp;gt;$_FILES&amp;lt;/tt&amp;gt; array:&lt;br /&gt;
&lt;br /&gt;
 // from &amp;lt;input name=&amp;quot;event&amp;quot; type=&amp;quot;file&amp;quot;&amp;gt;&lt;br /&gt;
 if (is_uploaded_file($_FILES['event']['tmp_name'])) {&lt;br /&gt;
     readfile($_FILES['event']['tmp_name']); // print file on screen&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Starting in PHP 4.1, all uploaded files appear in the &amp;lt;tt&amp;gt;$_FILES&amp;lt;/tt&amp;gt; superglobal array. For each file, there are four pieces of information:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The name assigned to the form input element&lt;br /&gt;
;&amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The MIME type of the file&lt;br /&gt;
;&amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The size of the file in bytes&lt;br /&gt;
;&amp;lt;tt&amp;gt;tmp_name&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The location in which the file is temporarily stored on the server.&lt;br /&gt;
&lt;br /&gt;
If you're using an earlier version of PHP, you need to use &amp;lt;tt&amp;gt;$HTTP_POST_FILES&amp;lt;/tt&amp;gt; instead.&lt;br /&gt;
&lt;br /&gt;
After you've selected a file from that array, use &amp;lt;tt&amp;gt;is_uploaded_file( )&amp;lt;/tt&amp;gt; to confirm that the file you're about to process is a legitimate file resulting from a user upload, then process it as you would other files on the system. Always do this. If you blindly trust the filename supplied by the user, someone can alter the request and add names such as ''/etc/passwd'' to the list for processing.&lt;br /&gt;
&lt;br /&gt;
You can also move the file to a permanent location; use &amp;lt;tt&amp;gt;move_uploaded_file( )&amp;lt;/tt&amp;gt; to safely transfer the file:&lt;br /&gt;
&lt;br /&gt;
 // move the file: move_uploaded_file() also does a check of the file's&lt;br /&gt;
 // legitimacy, so there's no need to also call is_uploaded_file()&lt;br /&gt;
 move_uploaded_file($_FILES['event']['tmp_name'], '/path/to/file.txt');&lt;br /&gt;
&lt;br /&gt;
Note that the value stored in &amp;lt;tt&amp;gt;tmp_name&amp;lt;/tt&amp;gt; is the complete path to the file, not just the base name. Use &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt; to chop off the leading directories if needed.&lt;br /&gt;
&lt;br /&gt;
Be sure to check that PHP has permission to read and write to both the directory in which temporary files are saved (see the &amp;lt;tt&amp;gt;upload_tmp_dir&amp;lt;/tt&amp;gt; configuration directive to check where this is) and the location in which you're trying to copy the file. This can often be user &amp;lt;tt&amp;gt;nobody&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;apache&amp;lt;/tt&amp;gt;, instead of your personal username. Because of this, if you're running under &amp;lt;tt&amp;gt;safe_mode&amp;lt;/tt&amp;gt;, copying a file to a new location will probably not allow you to access it again.&lt;br /&gt;
&lt;br /&gt;
Processing files can often be a subtle task because not all browsers submit the same information. It's important to do it correctly, however, or you open yourself up to a possible security hole. You are, after all, allowing strangers to upload any file they choose to your machine; malicious people may see this as an opportunity to crack into or crash the computer.&lt;br /&gt;
&lt;br /&gt;
As a result, PHP has a number of features that allow you to place restrictions on uploaded files, including the ability to completely turn off file uploads all together. So, if you're experiencing difficulty processing uploaded files, check that your file isn't being rejected because it seems to pose a security risk.&lt;br /&gt;
&lt;br /&gt;
To do such a check first, make sure &amp;lt;tt&amp;gt;file_uploads&amp;lt;/tt&amp;gt; is set to &amp;lt;tt&amp;gt;On&amp;lt;/tt&amp;gt; inside your configuration file. Next, make sure your file size isn't larger than &amp;lt;tt&amp;gt;upload_max_filesize&amp;lt;/tt&amp;gt;; this defaults to 2 MB, which stops someone trying to crash the machine by filling up the hard drive with a giant file. Additionally, there's a &amp;lt;tt&amp;gt;post_max_size&amp;lt;/tt&amp;gt; directive, which controls the maximum size of all the POST data allowed in a single request; its initial setting is 8 MB.&lt;br /&gt;
&lt;br /&gt;
From the perspective of browser differences and user error, if you can't get &amp;lt;tt&amp;gt;$_FILES&amp;lt;/tt&amp;gt; to populate with information, make sure you add &amp;lt;tt&amp;gt;enctype=&amp;quot;multipart/form-data&amp;quot;&amp;lt;/tt&amp;gt; to the form's opening tag; PHP needs this to trigger processing. If you can't do so, you need to manually parse &amp;lt;tt&amp;gt;$HTTP_RAW_POST_DATA&amp;lt;/tt&amp;gt;. (See RFCs 1521 and 1522 for the MIME specification at ''http://www.faqs.org/rfcs/rfc1521.html'' and ''http://www.faqs.org/rfcs/rfc1522.html''.)&lt;br /&gt;
&lt;br /&gt;
Also, if no file is selected for uploading, versions of PHP prior to 4.1 set &amp;lt;tt&amp;gt;tmp_name&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;none&amp;lt;/tt&amp;gt;; newer versions set it to the empty string. PHP 4.2.1 allows files of length 0. To be sure a file was uploaded and isn't empty (although blank files may be what you want, depending on the circumstances), you need to make sure &amp;lt;tt&amp;gt;tmp_name&amp;lt;/tt&amp;gt; is set and &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; is greater than 0. Last, not all browsers necessarily send the same MIME type for a file; what they send depends on their knowledge of different file types.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on handling file uploads at ''http://www.php.net/features.file-upload'' and on &amp;lt;tt&amp;gt;basename()&amp;lt;/tt&amp;gt; at ''http://www.php.net/basename''.&lt;br /&gt;
&lt;br /&gt;
== Securing PHP's Form Processing ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to securely process form input variables and not allow someone to maliciously alter variables in your code.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Disable the &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; configuration directive and access variables only from the &amp;lt;tt&amp;gt;$_REQUEST&amp;lt;/tt&amp;gt; array. To be even more secure, use &amp;lt;tt&amp;gt;$_GET&amp;lt;/tt&amp;gt; , &amp;lt;tt&amp;gt;$_POST&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$_COOKIE&amp;lt;/tt&amp;gt; to make sure you know exactly where your variables are coming from.&lt;br /&gt;
&lt;br /&gt;
To do this, make sure this line appears in your ''php.ini'' file:&lt;br /&gt;
&lt;br /&gt;
 register_globals = Off&lt;br /&gt;
&lt;br /&gt;
As of PHP 4.2, this is the default configuration.&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; is set &amp;lt;tt&amp;gt;on&amp;lt;/tt&amp;gt;, external variables, including those from forms and cookies, are imported directly into the global namespace. This is a great convenience, but it can also open up some security holes if you're not very diligent about checking your variables and where they're defined. Why? Because there may be a variable you use internally that isn't supposed to be accessible from the outside but has its value rewritten without your knowledge.&lt;br /&gt;
&lt;br /&gt;
Here is a simple example. You have a page in which a user enters a username and password. If they are validated, you return her user identification number and use that numerical identifier to look up and print out her personal information:&lt;br /&gt;
&lt;br /&gt;
 // assume magic_quotes_gpc is set to Off&lt;br /&gt;
 $username = $dbh-&amp;gt;quote($_GET['username']);&lt;br /&gt;
 $password = $dbh-&amp;gt;quote($_GET['password']);&lt;br /&gt;
 &lt;br /&gt;
 $sth = $dbh-&amp;gt;query(&amp;quot;SELECT id FROM users WHERE username = $username AND&lt;br /&gt;
                     password = $password&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 if (1 == $sth-&amp;gt;numRows( )) { &lt;br /&gt;
     $row = $sth-&amp;gt;fetchRow(DB_FETCHMODE_OBJECT);&lt;br /&gt;
     $id = $row-&amp;gt;id;&lt;br /&gt;
 } else {&lt;br /&gt;
     &amp;quot;Print bad username and password&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (!empty($id)) {&lt;br /&gt;
     $sth = $dbh-&amp;gt;query(&amp;quot;SELECT * FROM profile WHERE id = $id&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Normally, &amp;lt;tt&amp;gt;$id&amp;lt;/tt&amp;gt; is set only by your program and is a result of a verified database lookup. However, if someone alters the GET string, and passes in a value for &amp;lt;tt&amp;gt;$id&amp;lt;/tt&amp;gt;, with &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; enabled, even after a bad username and password lookup, your script still executes the second database query and returns results. Without &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$id&amp;lt;/tt&amp;gt; remains unset because only &amp;lt;tt&amp;gt;$_REQUEST['id']&amp;lt;/tt&amp;gt; (and &amp;lt;tt&amp;gt;$_GET['id']&amp;lt;/tt&amp;gt;) are set.&lt;br /&gt;
&lt;br /&gt;
Of course, there are other ways to solve this problem, even when using &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt;. You can restructure your code not to allow such a loophole.&lt;br /&gt;
&lt;br /&gt;
 $sth = $dbh-&amp;gt;query(&amp;quot;SELECT id FROM users WHERE username = $username AND&lt;br /&gt;
                     password = $password&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
 if (1 == $sth-&amp;gt;numRows( )) { &lt;br /&gt;
     $row = $sth-&amp;gt;fetchRow(DB_FETCHMODE_OBJECT);&lt;br /&gt;
     $id = $row-&amp;gt;id;&lt;br /&gt;
     if (!empty($id)) {&lt;br /&gt;
         $sth = $dbh-&amp;gt;query(&amp;quot;SELECT * FROM profile WHERE id = $id&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 } else {&lt;br /&gt;
     &amp;quot;Print bad username and password&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now you use &amp;lt;tt&amp;gt;$id&amp;lt;/tt&amp;gt; only when it's been explicitly set from a database call. Sometimes, however, it is difficult to do this because of how your program is laid out. Another solution is to manually &amp;lt;tt&amp;gt;unset( )&amp;lt;/tt&amp;gt; or initialize all variables at the top of your script:&lt;br /&gt;
&lt;br /&gt;
 unset($id);&lt;br /&gt;
&lt;br /&gt;
This removes the bad &amp;lt;tt&amp;gt;$id&amp;lt;/tt&amp;gt; value before it gets a chance to affect your code. However, because PHP doesn't require variable initialization, it's possible to forget to do this in one place; a bug can then slip in without a warning from PHP.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; at ''http://www.php.net/security.registerglobals.php''.&lt;br /&gt;
&lt;br /&gt;
== Escaping Control Characters from User Data ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to securely display user-entered data on an HTML page.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
For HTML you wish to display as plain text, with embedded links and other tags, use &amp;lt;tt&amp;gt;htmlentities( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 echo htmlentities('&amp;amp;lt;p&amp;gt;O'Reilly &amp;amp; Associates&amp;amp;lt;/p&amp;gt;');&lt;br /&gt;
 '''&amp;amp;amp;lt;p&amp;amp;amp;gt;O'Reilly &amp;amp; Associates&amp;amp;amp;lt;/p&amp;amp;amp;gt;'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
PHP has a pair of functions to escape characters in HTML. The most basic is &amp;lt;tt&amp;gt;htmlspecialchars( )&amp;lt;/tt&amp;gt; , which escapes four characters: &amp;lt;tt&amp;gt;&amp;lt;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt;. Depending on optional parameters, it can also translate ' instead of or in addition to &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt;. For more complex encoding, use &amp;lt;tt&amp;gt;htmlentities( )&amp;lt;/tt&amp;gt;; it expands on &amp;lt;tt&amp;gt;htmlspecialchars( )&amp;lt;/tt&amp;gt; to encode any character that has an HTML entity.&lt;br /&gt;
&lt;br /&gt;
 $html = &amp;quot;&amp;lt;a href='fletch.html'&amp;gt;Stew's favorite movie.&amp;lt;/a&amp;gt;\n&amp;quot;;&lt;br /&gt;
 print htmlspecialchars($html);                // double-quotes&lt;br /&gt;
 print htmlspecialchars($html, ENT_QUOTES);    // single- and double-quotes&lt;br /&gt;
 print htmlspecialchars($html, ENT_NOQUOTES);  // neither&lt;br /&gt;
 '''&amp;amp;amp;lt;a href=&amp;amp;amp;quot;fletch.html&amp;amp;amp;quot;&amp;amp;amp;gt;Stew's favorite movie.&amp;amp;amp;lt;/a&amp;amp;amp;gt;'''&lt;br /&gt;
                '''&amp;amp;amp;lt;a href=&amp;amp;amp;quot;fletch.html&amp;amp;amp;quot;&amp;amp;amp;gt;Stew&amp;amp;amp;#039;s favorite movie.&amp;amp;amp;lt;/a&amp;amp;amp;gt;'''&lt;br /&gt;
                '''&amp;amp;amp;lt;a href=&amp;quot;fletch.html&amp;quot;&amp;amp;amp;gt;Stew's favorite movie.&amp;amp;amp;lt;/a&amp;amp;amp;gt;'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
Both functions allow you to pass in a character encoding table that defines what characters map to what entities. To retrieve either table used by the previous functions, use &amp;lt;tt&amp;gt;get_html_translation_table( )&amp;lt;/tt&amp;gt; and pass in &amp;lt;tt&amp;gt;HTML_ENTITIES&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;HTML_SPECIALCHARS&amp;lt;/tt&amp;gt;. This returns an array that maps characters to entities; you can use it as the basis for your own table.&lt;br /&gt;
&lt;br /&gt;
 $copyright = &amp;quot;Copyright © 2003 O'Reilly &amp;amp; Associates\n&amp;quot;;&lt;br /&gt;
 $table = get_html_translation_table(); // get &amp;lt;, &amp;gt;, &amp;quot;, and &amp;amp;&lt;br /&gt;
 $table[©] = '&amp;amp;amp;copy;'                   // add ©&lt;br /&gt;
 print strtr($copyright, $table);&lt;br /&gt;
 '''Copyright &amp;amp;amp;copy; 2003 O'Reilly &amp;amp;amp;amp; Associates'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Regular Expressions#Escaping Special Characters in a Regular Expression|Recipe 13.9]], [[PHP Cookbook/Files#Escaping Shell Metacharacters|Recipe 18.21]], and [[PHP Cookbook/Database Access#Repeating Queries Efficiently|Recipe 10.8]]; documentation on &amp;lt;tt&amp;gt;htmlentities( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/htmlentities'' and &amp;lt;tt&amp;gt;htmlspecialchars( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/htmlspecialchars''.&lt;br /&gt;
&lt;br /&gt;
== Handling Remote Variables with Periods in Their Names ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to process a variable with a period in its name, but when a form is submitted, you can't find the variable.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Replace the period in the variable's name with an underscore. For example, if you have a form input element named &amp;lt;tt&amp;gt;foo.bar&amp;lt;/tt&amp;gt;, you access it inside PHP as the variable &amp;lt;tt&amp;gt;$_REQUEST['foo_bar']&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Because PHP uses the period as a string concatenation operator, a form variable called &amp;lt;tt&amp;gt;animal.height&amp;lt;/tt&amp;gt; is automatically converted to &amp;lt;tt&amp;gt;animal_height&amp;lt;/tt&amp;gt;, which avoids creating an ambiguity for the parser. While &amp;lt;tt&amp;gt;$_REQUEST['animal.height']&amp;lt;/tt&amp;gt; lacks these ambiguities, for legacy and consistency reasons, this happens regardless of your &amp;lt;tt&amp;gt;register_globals&amp;lt;/tt&amp;gt; settings.&lt;br /&gt;
&lt;br /&gt;
You usually deal with automatic variable name conversion when you process an image used to submit a form. For instance: you have a street map showing the location of your stores, and you want people to click on one for additional information. Here's an example:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;input type=&amp;quot;image&amp;quot; name=&amp;quot;locations&amp;quot; src=&amp;quot;locations.gif&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user clicks on the image, the x and y coordinates are submitted as &amp;lt;tt&amp;gt;locations.x&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;locations.y&amp;lt;/tt&amp;gt;. So, in PHP, to find where a user clicked, you need to check &amp;lt;tt&amp;gt;$_REQUEST['locations_x']&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$_REQUEST['locations_y']&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It's possible, through a series of manipulations, to create a variable inside PHP with a period:&lt;br /&gt;
&lt;br /&gt;
 ${&amp;quot;a.b&amp;quot;} = 123; // forced coercion using {}&lt;br /&gt;
 &lt;br /&gt;
 $var = &amp;quot;c.d&amp;quot;;   // indirect variable naming&lt;br /&gt;
 $$var = 456;       &lt;br /&gt;
 &lt;br /&gt;
 print ${&amp;quot;a.b&amp;quot;} . &amp;quot;\n&amp;quot;;&lt;br /&gt;
 print $$var . &amp;quot;\n&amp;quot;;&lt;br /&gt;
 '''123'''&lt;br /&gt;
                '''456'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
This is generally frowned on because of the awkward syntax.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on variables from outside PHP at ''http://www.php.net/language.variables.external.php''.&lt;br /&gt;
&lt;br /&gt;
== Using Form Elements with Multiple Options ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You have a form element with multiple values, such as a &amp;lt;tt&amp;gt;checkbox&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt; element, but PHP sees only one value.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Place brackets (&amp;lt;tt&amp;gt;[ ]&amp;lt;/tt&amp;gt;) after the variable name:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;boroughs[]&amp;quot; value=&amp;quot;bronx&amp;quot;&amp;gt; The Bronx&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;boroughs[]&amp;quot; value=&amp;quot;brooklyn&amp;quot;&amp;gt; Brooklyn&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;boroughs[]&amp;quot; value=&amp;quot;manhattan&amp;quot;&amp;gt; Manhattan&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;boroughs[]&amp;quot; value=&amp;quot;queens&amp;quot;&amp;gt; Queens&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;boroughs[]&amp;quot; value=&amp;quot;statenisland&amp;quot;&amp;gt; Staten Island&lt;br /&gt;
&lt;br /&gt;
Inside your program, treat the variable as an array:&lt;br /&gt;
&lt;br /&gt;
 print 'I love ' . join(' and ', $boroughs) . '!';&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
By placing &amp;lt;tt&amp;gt;[ ]&amp;lt;/tt&amp;gt; after the variable name, you tell PHP to treat it as an array instead of a scalar. When it sees another value assigned to that variable, PHP auto-expands the size of the array and places the new value at the end. If the first three boxes in the Solution were checked, it's as if you'd written this code at the top of the script:&lt;br /&gt;
&lt;br /&gt;
 $boroughs[ ] = &amp;quot;bronx&amp;quot;;&lt;br /&gt;
 $boroughs[ ] = &amp;quot;brooklyn&amp;quot;;&lt;br /&gt;
 $boroughs[ ] = &amp;quot;manhattan&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
You can use this to return information from a database that matches multiple records:&lt;br /&gt;
&lt;br /&gt;
 foreach ($_GET['boroughs'] as $b) {&lt;br /&gt;
   $boroughs[ ] = strtr($dbh-&amp;gt;quote($b),array('_' =&amp;gt; '\_', '%' =&amp;gt; '\%'));&lt;br /&gt;
 }&lt;br /&gt;
 $locations = join(',', $boroughs);&lt;br /&gt;
 &lt;br /&gt;
 $dbh-&amp;gt;query(&amp;quot;SELECT address FROM locations WHERE borough IN ($locations)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
This syntax also works with multidimensional arrays:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;population[NY][NYC]&amp;quot; value=&amp;quot;8008278&amp;quot;&amp;gt;New York...&lt;br /&gt;
&lt;br /&gt;
If checked, this form element sets &amp;lt;tt&amp;gt;$population['NY']['NYC']&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;8008278&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Placing a &amp;lt;tt&amp;gt;[ ]&amp;lt;/tt&amp;gt; after a variable's name can cause problems in JavaScript when you try to address your elements. Instead of addressing the element by its name, use the numerical ID. You can also place the element name inside single quotes. Another way is to assign the element an ID, perhaps the name without the &amp;lt;tt&amp;gt;[ ]&amp;lt;/tt&amp;gt;, and use that ID instead. Given:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;form&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;myName[]&amp;quot; value=&amp;quot;myValue&amp;quot; id=&amp;quot;myName&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;/form&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the following three refer to the same form element:&lt;br /&gt;
&lt;br /&gt;
 document.forms[0].elements[0];            // using numerical IDs&lt;br /&gt;
 document.forms[0].elements['myName[ ]'];   // using the name with quotes&lt;br /&gt;
 document.forms[0].elements['myName'];     // using ID you assigned&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
The introduction to [[PHP Cookbook/Arrays|Chapter 4]] for more on arrays.&lt;br /&gt;
&lt;br /&gt;
== Creating Dropdown Menus Based on the Current Date ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to create a series of dropdown menus that are based automatically on the current date.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;date( )&amp;lt;/tt&amp;gt; to find the current time in the web server's time zone and loop through the days with &amp;lt;tt&amp;gt;mktime( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The following code generates &amp;lt;tt&amp;gt;option&amp;lt;/tt&amp;gt; values for today and the six days that follow. In this case, &amp;quot;today&amp;quot; is January 1, 2002.&lt;br /&gt;
&lt;br /&gt;
 list($hour, $minute, $second, $month, $day, $year) = &lt;br /&gt;
                                   split(':', date('h:i:s:m:d:Y'));&lt;br /&gt;
 &lt;br /&gt;
 // print out one week's worth of days&lt;br /&gt;
 for ($i = 0; $i &amp;lt; 7; ++$i) {&lt;br /&gt;
     $timestamp = mktime($hour, $minute, $second, $month, $day + $i, $year); &lt;br /&gt;
     $date = date(&amp;quot;D, F j, Y&amp;quot;, $timestamp);&lt;br /&gt;
                 &lt;br /&gt;
     print &amp;quot;&amp;lt;option value=\&amp;quot;$timestamp\&amp;quot;&amp;gt;$date&amp;lt;/option&amp;gt;\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 '''&amp;lt;option value=&amp;quot;946746000&amp;quot;&amp;gt;Tue, January 1, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;946832400&amp;quot;&amp;gt;Wed, January 2, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;946918800&amp;quot;&amp;gt;Thu, January 3, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;947005200&amp;quot;&amp;gt;Fri, January 4, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;947091600&amp;quot;&amp;gt;Sat, January 5, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;947178000&amp;quot;&amp;gt;Sun, January 6, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;947264400&amp;quot;&amp;gt;Mon, January 7, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
In the Solution, we set the &amp;lt;tt&amp;gt;value&amp;lt;/tt&amp;gt; for each date as its Unix timestamp representation because we find this easier to handle inside our programs. Of course, you can use any format you find most useful and appropriate.&lt;br /&gt;
&lt;br /&gt;
Don't be tempted to eliminate the calls to &amp;lt;tt&amp;gt;mktime( )&amp;lt;/tt&amp;gt;; dates and times aren't as consistent as you'd hope. Depending on what you're doing, you might not get the results you want. For example:&lt;br /&gt;
&lt;br /&gt;
 $timestamp = mktime(0, 0, 0, 10, 24, 2002); // October 24, 2002&lt;br /&gt;
 $one_day = 60 * 60 * 24; // number of seconds in a day&lt;br /&gt;
 &lt;br /&gt;
 // print out one week's worth of days&lt;br /&gt;
 for ($i = 0; $i &amp;lt; 7; ++$i) {&lt;br /&gt;
     $date = date(&amp;quot;D, F j, Y&amp;quot;, $timestamp);&lt;br /&gt;
                 &lt;br /&gt;
     print &amp;quot;&amp;lt;option value=\&amp;quot;$timestamp\&amp;quot;&amp;gt;$date&amp;lt;/option&amp;gt;&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     $timestamp += $one_day;&lt;br /&gt;
 }&lt;br /&gt;
 '''&amp;lt;option value=&amp;quot;972619200&amp;quot;&amp;gt;Fri, October 25, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;972705600&amp;quot;&amp;gt;Sat, October 26, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;972792000&amp;quot;&amp;gt;Sun, October 27, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;972878400&amp;quot;&amp;gt;Sun, October 27, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;972964800&amp;quot;&amp;gt;Mon, October 28, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;973051200&amp;quot;&amp;gt;Tue, October 29, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
                '''&amp;lt;option value=&amp;quot;973137600&amp;quot;&amp;gt;Wed, October 30, 2002&amp;lt;/option&amp;gt;'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
This script should print out the month, day, and year for a seven-day period starting October 24, 2002. However, it doesn't work as expected.&lt;br /&gt;
&lt;br /&gt;
Why are there two &amp;quot;Sun, October 27, 2002&amp;quot;s? The answer: daylight saving time. It's not true that the number of seconds in a day stays constant; in fact, it's almost guaranteed to change. Worst of all, if you're not near either of the change-over dates, you're liable to miss this bug during testing.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Dates and Times|Chapter 3]], particularly [[PHP Cookbook/Dates and Times#Accounting for Daylight Saving Time|Recipe 3.13]], but also [[PHP Cookbook/Dates and Times#Finding the Current Date and Time|Recipe 3.2]], [[PHP Cookbook/Dates and Times#Converting Time and Date Parts to an Epoch Timestamp|Recipe 3.3]], [[PHP Cookbook/Dates and Times#Printing a Date or Time in a Specified Format|Recipe 3.5]], [[PHP Cookbook/Dates and Times#Adding to or Subtracting from a Date|Recipe 3.11]], and [[PHP Cookbook/Dates and Times#Generating a High-Precision Time|Recipe 3.14]]; documentation on &amp;lt;tt&amp;gt;date( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/date'' and &amp;lt;tt&amp;gt;mktime( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/mktime''.&lt;/div&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:28:45 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:PHP_Cookbook/Forms</comments>		</item>
	</channel>
</rss>