to drop into any POST
* - csrf_verify(): abort with HTTP 403 if the POSTed token is missing/invalid */ // Defensive: callers normally start the session themselves, but make sure we // have one to store the token in. if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } // Generate the token once per session. if (empty($_SESSION['_csrf_token'])) { $_SESSION['_csrf_token'] = bin2hex(random_bytes(32)); } if (!function_exists('csrf_token')) { /** * Return the current CSRF token as a hex string. */ function csrf_token(): string { return $_SESSION['_csrf_token'] ?? ''; } /** * Emit a ready-to-use hidden for any POST in a template. * Usage in a .tpl: */ function csrf_field(): string { return ''; } /** * Verify the CSRF token of a POST request. * Stops execution with HTTP 403 if the token is missing or does not match. * Uses hash_equals() instead of === to prevent timing attacks. */ function csrf_verify(): void { $submitted = isset($_POST['_csrf_token']) ? (string)$_POST['_csrf_token'] : ''; $stored = csrf_token(); if ($stored === '' || !hash_equals($stored, $submitted)) { http_response_code(403); // Generic message — does not reveal details about the mechanism. die('

403 Forbidden

Invalid or missing security token. Please go back and try again.

'); } } }