PHP Form Processing: A Complete Guide
PHP is a powerful scripting language used for web development and server-side processing. One of its key features is the ability to handle forms, allowing user
Handling forms is one of the most common jobs in any web application: a sign-up page, a contact form, a search box, or a checkout flow all send user input to the server, where PHP reads it, checks it, and acts on it. This guide walks through the full round trip — from the HTML form in the browser to the PHP that receives, validates, and safely re-uses the submitted data.
By the end you will understand how $_POST and $_GET work, how to validate input on the server, how to keep the form "sticky" after an error, and how to avoid the two classic security holes (XSS and SQL injection).
How a form submission works
A form submission is a single HTTP request from the browser to the server:
- The user fills in fields and clicks Submit.
- The browser packages the field values according to the form's
methodand sends them to the URL in the form'saction. - PHP on the server receives the values in a superglobal array —
$_POSTor$_GET— and your script processes them.
Because the data comes from the user's browser, you can never trust it. Anyone can change field values, remove fields, or send the request without using your form at all. Server-side validation is therefore not optional — client-side required and type="email" attributes are only a convenience.
Creating an HTML form
Every form starts in HTML. The form contains input fields — text boxes, email fields, radio buttons, checkboxes — and a submit button. Two attributes drive everything:
action— the URL that receives the data (omit it to post back to the same page).method—postorget(see the comparison below).
<form action="form_processing.php" method="post">
<p>
<label for="name">Name:</label>
<input type="text" id="name" name="name" />
</p>
<p>
<label for="email">Email:</label>
<input type="email" id="email" name="email" />
</p>
<input type="submit" value="Submit" />
</form>The name attribute of each input is the key you read on the server: name="email" becomes $_POST['email']. An input with no name is never submitted. Always pair every field with a <label> for accessibility.
POST vs. GET
The method attribute decides how the data travels and which array receives it.
method="post" | method="get" | |
|---|---|---|
| Data location | HTTP request body | Appended to the URL as a query string |
| PHP array | $_POST | $_GET |
| Visible in URL | No | Yes (?name=Ann&email=...) |
| Bookmarkable / shareable | No | Yes |
| Good for | Passwords, anything that changes data | Search filters, pagination — read-only requests |
Use POST for anything that creates, updates, or deletes data, or that contains sensitive values. Use GET for searches and filters you want users to be able to bookmark. Both arrive in the matching superglobal; the rest of this guide uses POST.
Reading the submitted data
When the form posts, PHP fills $_POST with the field names as keys and the submitted text as values. Read each field, but guard against missing keys with the null coalescing operator ?? so a missing field gives an empty string instead of a warning:
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';Check $_SERVER['REQUEST_METHOD'] so the processing code only runs on an actual submission, not when the page is first opened:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
// ...validate and use the values
}Validating the input
Validation answers one question: is this value acceptable? Collect every problem into an $errors array so you can show the user all the mistakes at once, instead of stopping at the first one. Use filter_var() with FILTER_VALIDATE_EMAIL to check the email format properly:
$errors = [];
if (trim($name) === '') {
$errors[] = "Name is required";
}
if (trim($email) === '') {
$errors[] = "Email is required";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email format";
}
if (!empty($errors)) {
foreach ($errors as $error) {
echo htmlspecialchars($error) . "<br>";
}
}We use trim() so a field containing only spaces still counts as empty, then filter_var() to confirm the email looks like [email protected]. If $errors is non-empty, the messages are printed; otherwise the data is clean and ready to use. For deeper coverage of required fields and email/URL rules, see PHP form validation and validating required fields.
Escaping output: prevent XSS
Notice the htmlspecialchars() call above. Whenever you echo a value that came from the user, you must escape it, or an attacker can submit <script> tags that run in other visitors' browsers — a cross-site scripting (XSS) attack. htmlspecialchars() converts <, >, &, and quotes into harmless HTML entities:
$dangerous = '<script>alert("xss")</script>';
echo htmlspecialchars($dangerous);
// <script>alert("xss")</script>The browser now displays the text literally instead of executing it. Escape on output, every time.
Keeping the form sticky
If validation fails, re-display the form with the user's values still filled in — re-typing everything is frustrating. Echo each value back into its value attribute, escaped:
<input
type="text"
name="name"
value="<?php echo htmlspecialchars($name ?? ''); ?>"
/>Because the same page both renders the form and processes it, set action="" (post back to itself) and the field repopulates automatically after a failed submit.
Putting it together
Here is a single self-processing page that renders the form, validates on POST, shows errors, keeps the form sticky, and confirms success — the pattern most real contact forms follow:
<?php
$name = $email = '';
$errors = [];
$success = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
if ($name === '') {
$errors[] = 'Name is required';
}
if ($email === '') {
$errors[] = 'Email is required';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email format';
}
if (!$errors) {
$success = true; // here you would save to a database or send an email
}
}
?>
<?php if ($success): ?>
<p>Thanks, <?php echo htmlspecialchars($name); ?>!</p>
<?php else: ?>
<?php foreach ($errors as $e): ?>
<p style="color:red"><?php echo htmlspecialchars($e); ?></p>
<?php endforeach; ?>
<form action="" method="post">
Name:
<input type="text" name="name"
value="<?php echo htmlspecialchars($name); ?>"><br>
Email:
<input type="email" name="email"
value="<?php echo htmlspecialchars($email); ?>"><br>
<input type="submit" value="Submit">
</form>
<?php endif; ?>Storing data safely: prevent SQL injection
Once the data is valid you often save it to a database. Never drop user input straight into an SQL string — that opens the door to SQL injection. Use a prepared statement so the database treats the values as data, never as commands:
$mysqli = new mysqli('localhost', 'user', 'pass', 'app');
$stmt = $mysqli->prepare(
'INSERT INTO contacts (name, email) VALUES (?, ?)'
);
$stmt->bind_param('ss', $name, $email);
$stmt->execute();The ? placeholders and bind_param() keep the values separate from the query, so an input like '; DROP TABLE contacts; -- is stored as harmless text instead of being executed.
Security checklist
A safe form-processing script follows a short, repeatable routine:
- Validate every field on the server — never rely on browser checks alone.
- Escape on output with
htmlspecialchars()to stop XSS. - Use prepared statements for every database query to stop SQL injection.
- Hash passwords with
password_hash()before storing them — never store plain text. - Add a CSRF token to state-changing forms so requests can't be forged from other sites.
- Add CAPTCHA to public forms to cut down automated spam submissions.
Related chapters
- PHP form handling — the basics of receiving form data.
- PHP $_POST — the superglobal in depth.
- PHP form validation — full validation patterns.
- PHP superglobals —
$_POST,$_GET,$_SERVER, and more.