Forms, Validation, and Safe Input Handling

A reliable form workflow preserves user input, reports useful errors, prevents duplicate submissions, and treats every client-supplied value as untrusted.

The POST/Redirect/GET Pattern

  1. Display the form with GET.
  2. Validate and process the submission with POST.
  3. Store a flash message or errors.
  4. Redirect to a GET page after success.

This prevents a browser refresh from repeating the last state-changing POST.

A Complete Validation Example

<?php
declare(strict_types=1);

session_start();

$values = [
    'name' => trim($_POST['name'] ?? ''),
    'email' => trim($_POST['email'] ?? ''),
];
$errors = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if ($values['name'] === '' || mb_strlen($values['name']) > 100) {
        $errors['name'] = 'Enter a name between 1 and 100 characters.';
    }

    if (filter_var($values['email'], FILTER_VALIDATE_EMAIL) === false) {
        $errors['email'] = 'Enter a valid email address.';
    }

    if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
        $errors['form'] = 'The form expired. Reload the page and try again.';
    }

    if ($errors === []) {
        $_SESSION['flash'] = 'Contact saved successfully.';
        header('Location: /contacts');
        exit;
    }
}

$_SESSION['csrf_token'] ??= bin2hex(random_bytes(32));
?>

<form method="post" action="" novalidate>
    <input type="hidden" name="csrf_token"
           value="<?= htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES, 'UTF-8') ?>">

    <label for="name">Name</label>
    <input id="name" name="name" maxlength="100" required
           value="<?= htmlspecialchars($values['name'], ENT_QUOTES, 'UTF-8') ?>">
    <?php if (isset($errors['name'])): ?>
        <p role="alert"><?= htmlspecialchars($errors['name'], ENT_QUOTES, 'UTF-8') ?></p>
    <?php endif; ?>

    <label for="email">Email</label>
    <input id="email" name="email" type="email" required
           value="<?= htmlspecialchars($values['email'], ENT_QUOTES, 'UTF-8') ?>">
    <?php if (isset($errors['email'])): ?>
        <p role="alert"><?= htmlspecialchars($errors['email'], ENT_QUOTES, 'UTF-8') ?></p>
    <?php endif; ?>

    <button type="submit">Save contact</button>
</form>

Validation Versus Sanitization

ActionPurposeExample
NormalizeConvert equivalent inputs to a consistent formTrim whitespace or normalize a phone number
ValidateDecide whether input meets the rulesRequire a valid date and a positive seat count
EscapeSafely render data in a specific output contextUse htmlspecialchars() for HTML text

File Upload Rules

  • Check the upload error code.
  • Enforce a server-side size limit.
  • Inspect MIME type using finfo; do not trust the filename extension.
  • Generate a new storage filename.
  • Store uploads outside the public document root or serve through a controlled endpoint.
  • Never execute uploaded content.