Forms are how websites listen. Search boxes, contact forms, sign-in pages, checkouts and comment boxes all collect information from visitors and send it to the server. On the server, PHP receives that information and decides what to do with it: search a database, send an email or save an order.
You already know how to build forms with HTML from the HTML forms lesson. This lesson is about the other side: reading the submitted values in PHP. They arrive in two special arrays, $_GET and $_POST, depending on how the form was sent.
You'll learn when to use GET and when to use POST, how to read text fields, checkboxes and select boxes, how to show values back safely, how to keep a form filled in when something needs correcting, and how to avoid the "resubmit form?" warning with a redirect.
From HTML form to PHP
<form action="search.php" method="get">
<input name="q">
<button>Search</button>
</form>actionis the PHP file that receives the data. Leave it out, or use an empty value, to send the form to the same page.methodis how the data is sent:getorpost.- The
nameattribute of each field becomes the key in PHP. An input withname="q"arrives as$_GET['q'].
A field without a name isn't sent at all, which is one of the most common reasons a value seems to be "missing".
GET versus POST
| GET | POST | |
|---|---|---|
| Where the data goes | In the address: search.php?q=lamp | In the request body, not the address |
| Bookmarkable and shareable | Yes | No |
| Good for | Searches, filters, page numbers | Sign-ups, orders, messages, anything that changes data |
| PHP array | $_GET | $_POST |
Use GET for requests that only read data and that people might want to bookmark. Use POST for anything that creates, changes or deletes data, or contains private information, so it doesn't end up in browser history and server logs.
Reading values safely
A form field might be missing, for example when the page is first opened. Read values with the null coalescing operator and trim stray spaces:
$name = trim($_POST['name'] ?? '');To check whether the form has been submitted at all, look at the request method:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// handle the submitted form
}Whenever you print a submitted value back into the page, wrap it in htmlspecialchars(). Otherwise a visitor could type HTML or JavaScript into a field and have it run in other people's browsers, an attack called cross-site scripting (XSS).
Checkboxes, selects and sticky forms
- A checkbox is only sent when it's ticked, so test it with
isset($_POST['newsletter']). - A select sends the
valueof the chosen option. - Several checkboxes with the same name ending in
[], such asname="toppings[]", arrive in PHP as an array.
A sticky form puts the submitted values back into the fields, so people don't have to retype everything when one field needs fixing: value="<?= htmlspecialchars($name) ?>". For a select, add selected to the option that matches, and for a checkbox, add checked when it was ticked.
PHP Forms Syntax
Form handling pattern
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim($_POST['email'] ?? '');
$agree = isset($_POST['agree']);
// validate and save...
header('Location: thanks.php');
exit;
}
$q = $_GET['q'] ?? '';
?>
<input name="email" value="<?= htmlspecialchars($email ?? '') ?>">PHP Forms Summary
- A field's
nameattribute becomes its key in$_GETor$_POST. - Use GET for reading and searching, POST for changing data or private information.
- Read values with
$_POST['field'] ?? '', and check$_SERVER['REQUEST_METHOD']. - Always escape output with
htmlspecialchars()to prevent XSS. - Checkboxes are only sent when ticked;
name="x[]"gives an array; redirect after a successful POST.
PHP Forms Examples
Each example shows the code, the output it produces and what each part does.
A search form with GET
The visitor typed desk lamp and pressed Search, so the address is search.php?q=desk+lamp.
<?php
$products = ['Desk lamp', 'Floor lamp', 'Notebook', 'Pen'];
$q = trim($_GET['q'] ?? '');
$results = [];
if ($q !== '') {
foreach ($products as $p) {
if (stripos($p, $q) !== false) $results[] = $p;
}
}
?>
<form method="get">
<input name="q" value="<?= htmlspecialchars($q) ?>">
<button>Search</button>
</form>
<p><?= count($results) ?> result(s) for "<?= htmlspecialchars($q) ?>"</p>
<?php foreach ($results as $r): ?>
<li><?= htmlspecialchars($r) ?></li>
<?php endforeach; ?><form method="get">
<input name="q" value="desk lamp">
<button>Search</button>
</form>
<p>1 result(s) for "desk lamp"</p>
<li>Desk lamp</li>Line-by-line explanation
- Line 3Read the search term from the address, or an empty string on first visit.
- Line 6stripos searches without caring about capital letters. It returns false when there's no match, so compare with !== false.
- Line 12Keeping the term in the box makes the form sticky.
A contact form with POST
The visitor filled in Sam and Hello there!, ticked the copy box and pressed Send.
<?php
$sent = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$message = trim($_POST['message'] ?? '');
$copy = isset($_POST['copy']);
$sent = $name !== '' && $message !== '';
}
?>
<?php if ($sent): ?>
<p>Thanks, <?= htmlspecialchars($name) ?>! We got your <?= strlen($message) ?>-character message.</p>
<p><?= $copy ? 'A copy is on its way to you.' : 'No copy requested.' ?></p>
<?php endif; ?> <p>Thanks, Sam! We got your 12-character message.</p>
<p>A copy is on its way to you.</p>Line-by-line explanation
- Line 3Only process the form when it was submitted with POST.
- Line 6A ticked checkbox is present in $_POST; an unticked one is missing, so isset gives true or false.
- Line 10Escape the name before printing it.
Several checkboxes as an array
The visitor ticked Cheese and Olives.
<?php
// <input type="checkbox" name="toppings[]" value="cheese">
// <input type="checkbox" name="toppings[]" value="ham">
// <input type="checkbox" name="toppings[]" value="olives">
$toppings = $_POST['toppings'] ?? [];
$allowed = ['cheese', 'ham', 'olives'];
$chosen = array_values(array_intersect($toppings, $allowed));
echo count($chosen) . " toppings: " . implode(', ', $chosen) . "\n";
echo "Price: £" . number_format(8 + count($chosen) * 1.5, 2);2 toppings: cheese, olives
Price: £11.00Line-by-line explanation
- Lines 2 to 4The [] in the name tells PHP to collect the ticked values into an array.
- Line 5If nothing is ticked, the key is missing, so default to an empty array.
- Line 7Keep only values from the allowed list, in case someone sends something unexpected.
Common PHP Forms Mistakes
A field without a name
<input id="email" type="email"><input id="email" name="email" type="email">Without name, the field isn't sent, and $_POST['email'] doesn't exist.
Printing input without escaping
echo "Hello " . $_GET['name'];echo "Hello " . htmlspecialchars($_GET['name'] ?? '');A name like <script>...</script> would otherwise run as code in the page.
Using GET for actions that change data
<a href="delete.php?id=5">Delete</a><form method="post" action="delete.php">
<input type="hidden" name="id" value="5">
<button>Delete</button>
</form>Browsers and link previewers may load GET links automatically, deleting things nobody chose to delete.
PHP Forms in Real Projects
Forms on real websites
Every login, registration, checkout and comment box runs through code like this. Frameworks such as Laravel and Symfony add helpers for reading input, but underneath they still read $_GET and $_POST. Searches use GET so results can be shared, and payment and account forms use POST with a redirect so refreshing never charges twice.
PHP Forms FAQ
How do I upload files with a PHP form?
Set method="post" and enctype="multipart/form-data" on the form and add an <input type="file" name="photo">. PHP puts the upload's details in $_FILES['photo'], including a temporary path; move it with move_uploaded_file() after checking its size and real type. The upload security lesson covers the checks.
Why is $_POST empty after submitting a large form?
If a request exceeds post_max_size in php.ini, PHP discards the whole body, so both $_POST and $_FILES arrive empty. Uploads are also limited by upload_max_filesize. Check both settings, and the web server's own request size limit, when large forms fail silently.
Should I use $_REQUEST?
Usually not. $_REQUEST mixes GET, POST and sometimes cookie values, so you can't tell where a value came from, and a value in the URL can override one you expected from the form body. Read from $_GET or $_POST explicitly.
How do I protect a form against CSRF?
Store a random token in the session, add it to the form as a hidden field, and reject the POST request if the submitted token doesn't match. This stops another website from silently submitting the form using a logged-in visitor's browser. Frameworks such as Laravel and Symfony add these tokens automatically.
How do I validate form input?
Check every field on the server, even if the browser already checks it: required values, length, format and allowed options. Collect error messages per field and show the form again with sticky values. The form validation lesson builds a complete example.
PHP Forms Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the code that reads the "email" field from a POST form.
$email = $['email'] '';
Which method should a search form use?
How do you check whether an unticked checkbox named "terms" was ticked?
The address is page.php?colour=red&size=M. What does this output?
echo $_GET['size'] . '-' . ($_GET['qty'] ?? 1);
Why redirect after successfully handling a POST form?
PHP Forms Quiz
5 questions to check what you learned.
Which attribute decides the key a field's value arrives under?
- id
- class
- value
- name
Where does GET data appear?
- In the page address after a question mark
- Only in cookies
- In the request body
- In a hidden file
What does
htmlspecialchars()protect against?- SQL injection
- Slow pages
- Cross-site scripting, by turning characters like < into safe codes
- Missing fields
What does
name="colours[]"do for a group of checkboxes?- Only the first value is sent
- PHP collects all ticked values into an array
- It creates a list of fields
- It's invalid HTML
How can PHP tell that a form was submitted with POST?
- Check isset($_GET)
- Check the page's file name
- Check $_SERVER['REQUEST_METHOD'] === 'POST'
- Check count($_POST) > 100