Forms, sessions and safety
Handling GET and POST, validating input, keeping sessions, and the defences against the classic web attacks.
Reading request data
$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL);
$page = filter_input(INPUT_GET, "page", FILTER_VALIDATE_INT, ["options" => ["min_range" => 1]]);
if ($email === null || $email === false) {
http_response_code(422);
exit("Invalid email");
}
// never: $email = $_POST["email"]; then use it directly in SQL or HTML| Superglobal | Carries |
|---|---|
$_GET | Query-string parameters |
$_POST | Submitted form body |
$_SESSION | Per-visitor server-side state |
$_COOKIE | Cookie values from the browser |
$_SERVER | Request and server metadata |
⚠️
Validate, do not sanitise blindly. Decide what a valid value looks like (an integer, an email, a value from an allow-list) and reject everything else.
Sessions and authentication
session_start();
// login
$user = findUserByEmail($email);
if ($user && password_verify($password, $user["password_hash"])) {
session_regenerate_id(true); // prevent session fixation
$_SESSION["uid"] = $user["id"];
}
// protection
if (empty($_SESSION["uid"])) {
header("Location: /login");
exit;
}
// hashing a new password
$hash = password_hash($password, PASSWORD_DEFAULT);password_hash/password_verifyhandle salting and cost factors for you.- Regenerate the session id on privilege change to defeat session fixation.
- Set cookie flags:
HttpOnly,Secure,SameSite=Lax.
The classic attacks and their fixes
| Attack | Defence |
|---|---|
| SQL injection | Prepared statements with bound parameters |
| XSS | htmlspecialchars() on every output |
| CSRF | Per-session token in forms, verified on POST |
| File upload abuse | Check MIME type and size, store outside the web root, rename |
| Path traversal | Never concatenate user input into a filesystem path |
// SQL injection, fixed
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
// CSRF token
$_SESSION["csrf"] = bin2hex(random_bytes(32));
// in the form: <input type="hidden" name="csrf" value="<?= $_SESSION['csrf'] ?>">
// on submit: hash_equals($_SESSION["csrf"], $_POST["csrf"] ?? "")⚠️
Compare CSRF tokens with
hash_equals(), not == — constant-time comparison avoids leaking information through timing.FAQ
Where should uploaded files go?
Outside the web root, with a generated name and a recorded whitelist of allowed types. Never trust the client-supplied filename or MIME type.
Why not use md5 or sha1 for passwords?
They are fast and unsalted, so a GPU can test billions of guesses per second. Use
password_hash() with bcrypt or Argon2.Related
PHP arrays Hash functions: MD5, SHA-1, SHA-256
Last refreshed 2026-09-17.