Lesson 14 / 25
Forms, Validation, Sessions and Cookies
Handle form input, validate it, and manage sessions and cookies securely.
Working with user input and state
Never trust input. Read values from $_POST or $_GET, then validate them (required fields, types, lengths, formats, allowed values) before use, and return clear error messages. filter_var helps with common formats (FILTER_VALIDATE_EMAIL, FILTER_VALIDATE_INT with ranges), and frameworks provide validation rules. Because HTTP is stateless and PHP discards memory after each request, sessions store per-user state on the server: session_start() reads a session ID from a cookie and loads $_SESSION. Secure them: set cookies with HttpOnly (not readable by JavaScript), Secure (HTTPS only) and SameSite=Lax or Strict; call session_regenerate_id(true) after login to prevent session fixation; and store sessions in Redis or a database when running several servers. Set other cookies with setcookie() and the same options. Use the POST-redirect-GET pattern after successful form submissions so refreshing the page does not resubmit the form.
Validating a sign-up form and starting a secure session
Validation first, then a regenerated session ID and a redirect.
<?php
declare(strict_types=1);
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
$errors = [];
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
$name = trim((string) ($_POST['name'] ?? ''));
$password = (string) ($_POST['password'] ?? '');
if ($email === false) { $errors['email'] = 'Enter a valid email address.'; }
if ($name === '' || mb_strlen($name) > 100) { $errors['name'] = 'Name is required (max 100 characters).'; }
if (mb_strlen($password) < 12) { $errors['password'] = 'Use at least 12 characters.'; }
if ($errors !== []) {
http_response_code(422);
render('signup', ['errors' => $errors, 'old' => ['email' => $_POST['email'] ?? '', 'name' => $name]]);
exit;
}
$userId = $users->register($email, $name, password_hash($password, PASSWORD_DEFAULT));
session_regenerate_id(true); // new session id after authentication
$_SESSION['user_id'] = $userId;
header('Location: /welcome', true, 303); // POST-redirect-GET
exit;A cloakroom token
A session cookie is the cloakroom token: the token itself holds nothing valuable, but it lets the attendant find your coat (session data) behind the counter. Issuing a fresh token after you show ID (login) stops anyone using an old token they copied.
Quick check: Why call session_regenerate_id(true) after a successful login?
- To log the user out
- To clear the shopping cart
- To speed up the session
- To issue a new session ID and prevent session fixation attacks
Answer
To issue a new session ID and prevent session fixation attacks — A new ID ensures an attacker who planted or knew the old ID cannot hijack the authenticated session.