# Forms, Validation, Sessions and Cookies — PHP

Source: https://www.skillbyai.com/en/php/w-forms

> 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
<?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.

**Quiz:** 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
- [x] 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.
