HTML Forms

HTML Forms and the PHP Side of Them

A form submits each named control as name=value, but a checkbox only when checked, so test it with isset(). Names ending in [] arrive as a list. GET puts the pairs in the URL and logs, so keep it for bookmarkable searches; POST changes data, and files need multipart/form-data (Single File Uploads). This template re-fills every field and prints each error beside it, using lib.php (Structured Validation) and the controller's $errors and $thanks (Headers and Redirects):

The review form template with sticky values and inline errors (form.php)PHP
<?php
$old = fn(string $k): string => is_string($_POST[$k] ?? null) ? $_POST[$k] : '';
$err = fn(string $k): string => isset($errors[$k]) ? ' <b>' . e($errors[$k]) . '</b>' : '';
$on = fn(string $k, string $v, string $attr): string =>
    in_array($v, (array) ($_POST[$k] ?? []), true) ? " $attr" : '';
?>
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Add a review</title>
<style>body{font:15px sans-serif}label{display:block;margin:8px 0}b{color:#b00020}</style>
</head><body><h2>Add a review</h2>
<?php if ($thanks): ?><p>Thank you for reviewing book <?= $thanks ?>.</p><?php endif ?>
<form method="post" action="/review.php">
<label>Book <select name="book">
<?php foreach (BOOKS as $id => $title): ?>
<option value="<?= $id ?>"<?= $on('book', "$id", 'selected') ?>><?= e($title) ?></option>
<?php endforeach ?>
</select><?= $err('book') ?></label>
<?php foreach (['rating' => 'Rating (1-5)', 'email' => 'Email'] as $k => $label): ?>
<label><?= $label ?> <input name="<?= $k ?>" value="<?= e($old($k)) ?>"><?= $err($k) ?></label>
<?php endforeach ?>
<label>Tags <?php foreach (TAGS as $t): ?>
<input type="checkbox" name="tags[]" value="<?= $t ?>"<?= $on('tags', $t, 'checked') ?>>
<?= $t ?> <?php endforeach ?><?= $err('tags') ?></label>
<label>Review<?= $err('body') ?><br>
<textarea name="body" rows="3" cols="40"><?= e($old('body')) ?></textarea></label>
<button>Post review</button></form></body></html>

$old() returns only strings, so a forged email[]=x never reaches e(). $on() casts to an array, covering the <select> value and the tags[] list with one strict test. Everything printed is escaped, including what the reader typed (HTML-Safe Output and Escaping). HTML's required and type="email" help honest users, but curl 3,008 ignores them. A real form also carries a CSRF token (CSRF Tokens).