php
45 lines · 6 steps
Building a profanity filter in PHP
A class compiles a blocklist into one regex, then uses it to detect and mask offensive words.
Explained by
highlit
1<?php
2
3namespace App\Services;
4
5final class ProfanityFilter
6{
7 private const REPLACEMENT = '****';
8
9 private array $blocklist = [
10 'damn', 'hell', 'crap', 'jerk', 'idiot', 'moron', 'bastard',
11 ];
12
13 private string $pattern;
14
15 public function __construct(array $extraWords = [])
16 {
17 $words = array_merge($this->blocklist, $extraWords);
18 $escaped = array_map(static fn (string $word): string => preg_quote($word, '/'), $words);
19
20 $this->pattern = '/\b(?:' . implode('|', $escaped) . ')\b/iu';
21 }
22
23 public function clean(string $comment): string
24 {
25 return preg_replace_callback(
26 $this->pattern,
27 static fn (array $match): string => self::mask($match[0]),
28 $comment,
29 ) ?? $comment;
30 }
31
32 public function contains(string $comment): bool
33 {
34 return (bool) preg_match($this->pattern, $comment);
35 }
36
37 private static function mask(string $word): string
38 {
39 $length = mb_strlen($word);
40
41 return $length <= 2
42 ? str_repeat('*', $length)
43 : mb_substr($word, 0, 1) . str_repeat('*', $length - 1);
44 }
45}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Compiling a word list into a single regex once in the constructor keeps every later match fast and consistent.
- 2Escaping user-supplied words with preg_quote prevents them from being interpreted as regex metacharacters.
- 3Multibyte-aware string functions like mb_strlen and mb_substr keep masking correct for non-ASCII text.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
go
package logging import ( "context"
Deduplicating log attributes in Go's slog
decorator-pattern
structured-logging
immutability
Intermediate
8 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-profanity-filter-in-php-explained-php-71da/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.