Kodokon kodokon.com

Forms: receiving and validating data

Handle forms like a pro: the right HTTP method, strict input validation, and safe re-display.

9 min · 3 questions

Open this lesson in Kodokon

A form is the first point of contact between your users and your PHP code. The get method places data in the URL (?q=pizza): perfect for a search or a filter, because the page can be bookmarked and shared. The post method carries data in the request body: it's the mandatory method whenever the request changes something (account creation, order, deletion) or carries sensitive data. PHP stores the received values in the $_GET and $_POST superglobals.

HTML
<form action="search.php" method="get">
  <label for="q">Search</label>
  <input id="q" name="q" type="text">
  <button type="submit">Search</button>
</form>
<?php
$query = trim($_GET['q'] ?? '');

if ($query !== '') {
    echo "<p>You are searching for: " .
        htmlspecialchars($query, ENT_QUOTES) . "</p>";
}
?>
search.php: the form and its handling on the same page.

Professional rule number one: never trust incoming data. A user can send anything, including forged values crafted outside your form. The filter_input() function reads and validates a value in a single step: it returns the validated value, false if it's invalid, and null if the field is missing - three cases to distinguish in your error messages.

PHP
<?php

declare(strict_types=1);

$errors = [];

$email = filter_input(
    INPUT_POST,
    'email',
    FILTER_VALIDATE_EMAIL
);

$age = filter_input(
    INPUT_POST,
    'age',
    FILTER_VALIDATE_INT,
    ['options' => ['min_range' => 18, 'max_range' => 120]]
);

$name = trim((string) ($_POST['name'] ?? ''));

if ($name === '' || mb_strlen($name) > 50) {
    $errors[] = "Name required (50 characters max).";
}

if (!is_string($email)) {
    $errors[] = "Invalid email address.";
}

if (!is_int($age)) {
    $errors[] = "Invalid age (between 18 and 120).";
}

if ($errors === []) {
    echo "Registration valid.";
}
Validating a registration with filter_input().

When validation fails, don't send back an empty form: re-display the values the user typed (a "sticky" form) and the error messages next to the fields concerned. Any re-displayed value must go through htmlspecialchars(): it's what neutralizes tags and prevents script injection.

HTML
<?php
$name = trim($_POST['name'] ?? '');
$hasError = isset($_POST['name']) && $name === '';
$safeName = htmlspecialchars($name, ENT_QUOTES);
?>
<form method="post" action="">
  <label for="name">Your name</label>
  <input id="name" name="name"
    value="<?= $safeName ?>">
  <?php if ($hasError): ?>
    <p>Name is required.</p>
  <?php endif; ?>
  <button type="submit">Submit</button>
</form>
Sticky form: the input survives the error.

Knowledge check

Make sure you remember the key points of this lesson.

  1. Which HTTP method is appropriate for a form that creates a user account?
    • GET, so the data stays visible in the URL
    • POST, because the request changes the server state and the data must not appear in the URL
    • Either one works, it's a matter of style
  2. What does filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) return if the field was not sent at all?
    • false
    • An empty string
    • null
    • It throws an exception
  3. Why pass a value through htmlspecialchars() before re-displaying it in a page?
    • To neutralize HTML tags and prevent script injection (XSS vulnerability)
    • To automatically correct typos
    • To compress the value and speed up display