php
51 lines · 8 steps
Building a per-form CSRF guard in PHP
A small class that mints, embeds, and verifies one-time CSRF tokens scoped to individual forms.
Explained by
highlit
1<?php
2
3final class CsrfGuard
4{
5 private const SESSION_KEY = '_csrf_tokens';
6 private const MAX_TOKENS = 10;
7
8 public function token(string $form = 'default'): string
9 {
10 if (session_status() !== PHP_SESSION_ACTIVE) {
11 session_start();
12 }
13
14 $token = bin2hex(random_bytes(32));
15 $tokens = $_SESSION[self::SESSION_KEY] ?? [];
16 $tokens[$form] = $token;
17
18 if (count($tokens) > self::MAX_TOKENS) {
19 $tokens = array_slice($tokens, -self::MAX_TOKENS, null, true);
20 }
21
22 $_SESSION[self::SESSION_KEY] = $tokens;
23
24 return $token;
25 }
26
27 public function field(string $form = 'default'): string
28 {
29 $value = htmlspecialchars($this->token($form), ENT_QUOTES, 'UTF-8');
30 $name = htmlspecialchars($form, ENT_QUOTES, 'UTF-8');
31
32 return sprintf(
33 '<input type="hidden" name="_csrf" value="%s"><input type="hidden" name="_csrf_form" value="%s">',
34 $value,
35 $name
36 );
37 }
38
39 public function validate(string $submitted, string $form = 'default'): bool
40 {
41 $expected = $_SESSION[self::SESSION_KEY][$form] ?? null;
42
43 if ($expected === null || $submitted === '') {
44 return false;
45 }
46
47 unset($_SESSION[self::SESSION_KEY][$form]);
48
49 return hash_equals($expected, $submitted);
50 }
51}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1CSRF tokens should be unpredictable, stored server-side, and bound to the specific form they protect.
- 2Comparing secrets with hash_equals avoids timing leaks that a plain equality check would expose.
- 3Consuming a token on validation makes it single-use, blocking replay of a stolen form submission.
Related explainers
php
<?php namespace App\Support;
Locale-aware formatting with PHP's intl extension
internationalization
encapsulation
constructor-injection
Intermediate
7 steps
php
<?php namespace App\Support;
Merging query params onto a URL in PHP
url-parsing
query-strings
immutability
Intermediate
8 steps
php
<?php class ImageUploadService {
Validating file uploads safely in PHP
file-upload
input-validation
security
Intermediate
8 steps
php
<?php namespace App\View;
Building a safe HTML escaper in PHP
security
xss
escaping
Intermediate
6 steps
ruby
require 'json' require 'set' class SensitiveScrubber
Recursively scrubbing secrets from JSON
recursion
data-masking
pattern-matching
Intermediate
7 steps
php
<?php namespace App\Observers;
How Eloquent observers hook lifecycle events in Laravel
observers
lifecycle-hooks
queues
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-per-form-csrf-guard-in-php-explained-php-aa9b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.