Form processing
Form basics
This is a basic HTML form.
<form action="register.php" method="post">
<input type="text" name="first_name" value="" />
<input type="text" name="last_name" value="" /><br />
<input type="text" name="email" value="" /><br />
<input type="text" name="username" value="" /><br />
<input type="password" name="password" value="" /><br />
<br />
<input type="submit" value="Submit" />
</form>
This form will submit the values of its input fields to “register.php” using the request method “POST”.
The values will be packaged up and sent as “POST data”. We don’t see POST data in the URL like we do with GET data, and POST data does not need to be encoded or decoded like GET data does.
Even though POST data is not as prominently visible, do not be fooled into thinking they are private. Anyone who can see the request will see the POST data in plaintext.
Retrieving form values
PHP is helpful for processing form values. PHP automatically assigns the form data to the associative array in superglobal $_POST. Those values can be accessed using their key names.
<?php
$first_name = $_POST['first_name'];
$last_name = $_POST['last_name'];
?>
It is a good practice to make sure that values are set for variables before using them, and to set default values if they are not set.
<?php
$first_name = isset($_POST['first_name']) ? $_POST['first_name'] : '';
$last_name = isset($_POST['last_name']) ? $_POST['last_name'] : '';
?>
The boolean ? true\_result : false\_result syntax is called a ternary operator and is handy for writing an if-else statement on one line. PHP 7 added a new null coalesce operator (??) to make it even shorter and easier.
<?php // PHP 7.0+ only
$first_name = $_POST['first_name'] ?? '';
$last_name = $_POST['last_name'] ?? '';
?>
Detecting form submission
A common form-processing technique is to have a page which responds differently depending on whether a form has been submitted to it. Check $_SERVER['REQUEST_METHOD'] — it reflects the actual HTTP method of the current request and does not depend on the form’s markup, on the submit button being named, or on how the form was submitted.
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST') {
// is a POST request
} else {
// is not a POST request
}
?>
This can be packaged up as an easy-to-remember function.
<?php
function is_post_request() {
return $_SERVER['REQUEST_METHOD'] == 'POST';
}
if(is_post_request()) {
// is a POST request
}
?>
You may encounter an older pattern that names the submit button (e.g. <input type="submit" name="submit" value="Submit">) and detects submission with isset($_POST['submit']). Avoid this idiom in new code:
- It silently fails when a form is submitted programmatically via JavaScript with
form.submit(). MDN’s reference forHTMLFormElement.submit()notes that<input type="submit">“will not be submitted with the form” in that path, so$_POST['submit']is never set and the request is misread as “not submitted” even though it clearly was. name="submit"(orid="submit") on any control inside the form shadows the form element’s ownsubmit()method. MDN: “A form control (such as a submit button) with anameoridofsubmitwill mask the form’ssubmitmethod. Trying to callmyForm.submit();throws an error ‘submit is not a function’.” Any inline JavaScript that tries to submit the form will break.
Checking REQUEST_METHOD has neither problem and is the canonical way to detect a POST.
Form submitting to itself
Another common form-processing technique is for a form to submit back to its own page. The first request for the page (GET, when the URL is entered) shows the form. The second request for the page (POST, when the form is submitted) will process the form. This has the advantage of making it easy to redisplay the form again if there are errors and to re-populate its input fields with the recently submitted values.
Handling form errors
If something goes wrong during form processing, then the error needs to be communicated to the user so they can fix the data and try again.
Here is a code example which will take an array of errors and output them as a list inside a div for display on the form page.
<?php
function display_errors($errors=[]) {
$output = '';
if (!empty($errors)) {
$output .= "<div class=\"errors\">";
$output .= "Please fix the following errors:";
$output .= "<ul>";
foreach ($errors as $error) {
$output .= "<li>" . htmlspecialchars($error, ENT_QUOTES, 'UTF-8') . "</li>";
}
$output .= "</ul>";
$output .= "</div>";
}
return $output;
}
?>
Listing all errors above the form is the easiest approach. More complex code could be written which would highlight each input field that has an error.
Redisplaying the form
If there are form errors, then the form should be redisplayed to the user and be pre-populated with the recently submitted data. It would be very frustrating to the user if they had to fill out the entire form again.
To add the values, the HTML form seen earlier will be modified to include values output by PHP. The submitted values originate from user input, so they must be HTML-escaped before being placed into an attribute value — otherwise an attacker can break out of the attribute and inject markup or script (a stored or reflected XSS bug). Use htmlspecialchars() with ENT_QUOTES and an explicit UTF-8 encoding to escape both single and double quotes (see PHP: Encoding for HTML).
Password fields are a deliberate exception: do not redisplay the submitted password. Echoing a password back into the page exposes it to browser autofill, screen-reading tools, browser/extension history, and any client-side script that walks the DOM, and there is no usability benefit because <input type="password"> masks the value anyway. Always require the user to retype the password.
<form action="register.php" method="post">
<input type="text" name="first_name" value="<?php echo htmlspecialchars($first_name, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="text" name="last_name" value="<?php echo htmlspecialchars($last_name, ENT_QUOTES, 'UTF-8'); ?>" /><br />
<input type="text" name="email" value="<?php echo htmlspecialchars($email, ENT_QUOTES, 'UTF-8'); ?>" /><br />
<input type="text" name="username" value="<?php echo htmlspecialchars($username, ENT_QUOTES, 'UTF-8'); ?>" /><br />
<input type="password" name="password" value="" /><br />
<br />
<input type="submit" value="Submit" />
</form>
Make sure that all variables being used either have a $_POST value or have a default value set.