PHP Form Handling

Ma Mariya Vinciya Updated 21 Oct 2026
8 min read ·Lesson 175 of 177
In this post

What Is Form Handling? In simple terms: Form handling is everything that happens between a user clicking "Submit" and seeing the result: the browser sends the entered data to the server, PHP reads it,

What Is Form Handling?

In simple terms: Form handling is everything that happens between a user clicking "Submit" and seeing the result: the browser sends the entered data to the server, PHP reads it, checks it, does something useful with it (saves it, sends an email, searches), and responds with a page.

Technically: An HTML <form> makes the browser send an HTTP request — GET with the data in the URL, or POST with the data in the request body. PHP parses the request into the superglobals $_GET, $_POST, and $_FILES, and your script processes those values and generates a response.

Why It Matters

Forms are how users interact with web applications: logging in, registering, searching, placing orders, sending messages, uploading files. Handling them correctly means:

  • accepting valid input and giving clear feedback on invalid input,
  • protecting the application from malicious input,
  • never losing what the user typed, and
  • never processing the same submission twice by accident.

This lesson explains the complete flow. The following lessons cover each part in depth: PHP Form Validation, PHP Form Required, PHP Form URL/E-mail, Form Input Sanitizing, Escaping Output (htmlspecialchars), Checkbox, Radio and Select Inputs, Sticky Forms, and PHP Form Complete.


How a Form Submission Works

1. Browser shows the form (GET /contact.php)
2. User fills in fields and clicks Submit
3. Browser sends: POST /contact.php   body: name=Asha&email=asha%40example.com
4. PHP fills $_POST = ['name' => 'Asha', 'email' => 'asha@example.com']
5. Your script validates and processes the data
6. Response: redirect to a success page, or show the form again with errors

 


The Form Element

<form action="/welcome.php" method="post">
    <label for="name">Name</label>
    <input type="text" id="name" name="name">

    <label for="email">Email</label>
    <input type="email" id="email" name="email">

    <button type="submit">Submit</button>
</form>

 

AttributeMeaning
actionURL that receives the data. Empty (action="") or omitted means the current URL.
methodget or post (default: get)
enctypeHow the data is encoded; multipart/form-data is required for file uploads
name (on inputs)The key under which the value is sent — fields without name are not sent
id + <label for>Connects labels to inputs for accessibility; not sent to the server

 


A Simple Form Handler

welcome.php

<?php
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
?>
<p>Welcome, <?= htmlspecialchars($name) ?>!</p>
<p>Your email address is: <?= htmlspecialchars($email) ?></p>

 

Output After Submitting "Asha" and "asha@example.com"

<p>Welcome, Asha!</p>
<p>Your email address is: asha@example.com</p>

 

What This Example Already Does Right

  • ?? '' provides defaults if a field is missing.
  • trim() removes accidental spaces.
  • htmlspecialchars() escapes the values before printing. If someone submits <script>...</script> as their name, it is displayed as harmless text instead of being executed.

What It Still Lacks

This minimal handler accepts anything: an empty name, an invalid email, or a request sent without the form. Real handlers must validate input, report errors, and protect against attacks — covered below.


GET Forms for Searching and Filtering

Forms that only retrieve information should use GET, so the resulting page can be bookmarked and shared:

<?php
// search.php
$query = is_string($_GET['q'] ?? null) ? trim($_GET['q']) : '';
?>
<form action="/search.php" method="get">
    <input type="search" name="q" value="<?= htmlspecialchars($query) ?>">
    <button type="submit">Search</button>
</form>

<?php if ($query !== ''): ?>
<p>Results for "<?= htmlspecialchars($query) ?>"</p>
<?php endif; ?>

 

After searching for php arrays, the URL becomes /search.php?q=php+arrays. The search box is filled with the current query, so the user can refine it. See \$_GET.

Use GET WhenUse POST When
Searching, filtering, sorting, paginatingCreating, updating, or deleting data
The result should be bookmarkableSubmitting passwords or personal data
Repeating the request is harmlessUploading files or large amounts of text

 


The Self-Processing Form Pattern

A common structure keeps the form and its processing in the same file:

contact.php
├── PHP at the top:  if the request is POST → read, validate, process
└── HTML below:      display the form (with errors and previous values)

 

<?php
$errors = [];
$values = ['name' => ''];

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    $values['name'] = is_string($_POST['name'] ?? null) ? trim($_POST['name']) : '';

    if ($values['name'] === '') {
        $errors['name'] = 'Please enter your name.';
    }

    if ($errors === []) {
        // process the data, then redirect (see Post/Redirect/Get below)
        header('Location: /thank-you.php', true, 303);
        exit;
    }
}
?>
<form method="post" action="">
    <input name="name" value="<?= htmlspecialchars($values['name']) ?>">
    <?php if (isset($errors['name'])): ?>
        <span class="error"><?= htmlspecialchars($errors['name']) ?></span>
    <?php endif; ?>
    <button type="submit">Send</button>
</form>

 

Why This Structure Works

  1. First visit (GET): the processing block is skipped; the empty form is shown.
  2. Invalid submission (POST): errors are collected, and the same page shows the form again — with the user's input preserved and error messages next to the fields.
  3. Valid submission (POST): the data is processed, and the browser is redirected.

Because all logic for one form lives in one place, it is easy to follow. In larger applications, frameworks split this into a controller (processing) and a view (template), but the flow is the same.


The Processing Steps

StepWhat to DoLesson
1. Check the methodProcess only POST submissions\$_SERVER
2. Verify the CSRF tokenReject forged submissions(below)
3. Read inputUse defaults and type checks\$_POST
4. ValidateRequired fields, formats, ranges, allowed valuesPHP Form Validation
5. ProcessSave to the database, send email, etc.—
6. RespondRedirect on success; re-display with errors on failureSticky Forms
7. Escape outputhtmlspecialchars() for every displayed valueEscaping Output

 

Keep Validation Testable

Putting validation in a function that receives an array (instead of reading $_POST directly) makes it easy to test and reuse:

<?php
function inputString(array $input, string $key): string
{
    $value = $input[$key] ?? '';
    return is_string($value) ? trim($value) : '';
}

function validateFeedback(array $input): array
{
    $data = [
        'name' => inputString($input, 'name'),
        'rating' => filter_var($input['rating'] ?? null, FILTER_VALIDATE_INT, [
            'options' => ['min_range' => 1, 'max_range' => 5],
        ]),
        'comment' => inputString($input, 'comment'),
    ];

    $errors = [];

    if ($data['name'] === '') {
        $errors['name'] = 'Name is required.';
    }

    if ($data['rating'] === false) {
        $errors['rating'] = 'Choose a rating from 1 to 5.';
    }

    if (mb_strlen($data['comment']) < 10) {
        $errors['comment'] = 'Comment must be at least 10 characters.';
    }

    return [$data, $errors];
}

[$data, $errors] = validateFeedback(['name' => '  Asha ', 'rating' => '5', 'comment' => 'Great PHP lessons!']);
var_dump($errors === []);
echo "{$data['name']} rated {$data['rating']}\n";

[, $errors] = validateFeedback(['name' => '', 'rating' => '9', 'comment' => 'Bad']);
print_r($errors);

// In the real page: [$data, $errors] = validateFeedback($_POST);

 

Output

bool(true)
Asha rated 5
Array
(
    [name] => Name is required.
    [rating] => Choose a rating from 1 to 5.
    [comment] => Comment must be at least 10 characters.
)

 

  • The function returns both the cleaned data (trimmed strings, an integer rating) and the errors, keyed by field name.
  • Valid data comes back typed and normalized: ' Asha ' becomes 'Asha', and '5' becomes 5.
  • All errors are reported together, so the user can fix everything in one attempt.

Protecting Forms

Post/Redirect/Get (PRG)

After a successful POST, always redirect (with status 303) instead of rendering a page directly. Otherwise, refreshing the result page asks the browser to resubmit the form, which can create duplicate orders or messages. See \$_POST.

CSRF Tokens

A Cross-Site Request Forgery attack makes a logged-in user's browser submit a form to your site from a malicious page. A secret token stored in the session and included in every form prevents this:

<?php
session_start();

function csrfToken(): string
{
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['csrf_token'];
}

function isValidCsrfToken(mixed $token): bool
{
    return is_string($token)
        && isset($_SESSION['csrf_token'])
        && hash_equals($_SESSION['csrf_token'], $token);
}

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && !isValidCsrfToken($_POST['csrf_token'] ?? null)) {
    http_response_code(419);
    exit('Your session has expired. Please reload the page and try again.');
}
?>
<form method="post" action="">
    <input type="hidden" name="csrf_token" value="<?= htmlspecialchars(csrfToken()) ?>">
    <!-- other fields -->
</form>

 

  • The token is random and unique per session; a malicious site cannot read it from your page.
  • Every POST must include the token; requests without a matching token are rejected before any processing.
  • hash_equals() compares the tokens in constant time.
  • Status 419 is a convention used by some frameworks (Laravel) for expired tokens; 403 is also common.

Other Safeguards

  • Serve forms over HTTPS.
  • Limit the rate of submissions for login and contact forms (to slow down bots and password guessing).
  • Use a CAPTCHA or honeypot field for public forms that attract spam.
  • Never trust hidden fields or select values — validate them on the server.

Common Mistakes

Fields Without name

Effect: Values are not submitted.

Fix: Every input needs a name attribute.

Trusting Browser Validation

Effect: required, type="email", and maxlength are bypassed by direct requests.

Fix: Validate everything on the server; use HTML validation only for user convenience.

Printing Input Without Escaping

Effect: Cross-site scripting.

Fix: htmlspecialchars() on every value you output.

Showing a Result Page Directly After POST

Effect: Duplicate submissions on refresh.

Fix: Redirect after success (PRG).

Losing User Input on Errors

Effect: Frustrated users who must retype everything.

Fix: Refill the form with the submitted (escaped) values — see Sticky Forms.


Best Practices

  • Use GET for retrieving data and POST for changing data.
  • Process POST requests at the top of the script, before any output.
  • Validate in a reusable function that returns cleaned data and errors.
  • Protect every POST form with a CSRF token, and redirect after success.
  • Escape all output, and keep the user's input when showing errors.

Official reference: https\://www.php.net/manual/en/tutorial.forms.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PDO Error Handling PHP SimpleXML Parser
Ask about this post
AI Ask about this post

Ask questions about PHP Form Handling and get answers drawn from it.

Signed-in readers only.