PHPackages                             blaspsoft/blasp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. blaspsoft/blasp

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

blaspsoft/blasp
===============

Blasp is a powerful and customisable profanity filter package for Laravel applications

v4.0.1(4mo ago)351272.1k—4.2%27[3 issues](https://github.com/Blaspsoft/blasp/issues)[1 PRs](https://github.com/Blaspsoft/blasp/pulls)1MITPHPPHP ^8.2CI passing

Since Oct 19Pushed 3mo ago3 watchersCompare

[ Source](https://github.com/Blaspsoft/blasp)[ Packagist](https://packagist.org/packages/blaspsoft/blasp)[ Docs](https://github.com/blaspsoft/blasp)[ RSS](/packages/blaspsoft-blasp/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (10)Dependencies (6)Versions (24)Used By (1)

 [![Blasp Icon](./assets/icon.png)](./assets/icon.png)

 [![GitHub Workflow Status (main)](https://github.com/Blaspsoft/blasp/actions/workflows/main.yml/badge.svg)](https://github.com/Blaspsoft/blasp/actions/workflows/main.yml) [![Total Downloads](https://camo.githubusercontent.com/cd724b55b48ab27c6fbc76878571c49c5c80fbe2d71f90c491ca1389bdb318b0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f626c617370736f66742f626c617370)](https://packagist.org/packages/blaspsoft/blasp) [![Latest Version](https://camo.githubusercontent.com/2a018b6c5356d2f5300776b6fe9e468b918f0d7da5aa5471d3264c3b7549a0d1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626c617370736f66742f626c617370)](https://packagist.org/packages/blaspsoft/blasp) [![License](https://camo.githubusercontent.com/39aa3e9b48f79fac8e3be7f28e05aeb374e2fc0b56ef3c269c9486c138447320/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f626c617370736f66742f626c617370)](https://packagist.org/packages/blaspsoft/blasp)

Blasp - Advanced Profanity Filter for Laravel
=============================================

[](#blasp---advanced-profanity-filter-for-laravel)

Blasp is a powerful, extensible profanity filter for Laravel. Version 4 is a ground-up rewrite with a driver-based architecture, severity scoring, masking strategies, Eloquent model integration, and a clean fluent API.

Features
--------

[](#features)

- **Driver Architecture** — `regex` (detects obfuscation, substitutions, separators), `pattern` (fast exact matching), `phonetic` (catches sound-alike evasions), or `pipeline` (chains multiple drivers together). Extend with custom drivers.
- **Multi-Language** — English, Spanish, German, French with language-specific normalizers. Check one, many, or all at once.
- **Severity Scoring** — Words categorised as mild/moderate/high/extreme. Filter by minimum severity and get a 0-100 score.
- **Masking Strategies** — Character mask (`*`, `#`), grawlix (`!@#$%`), or a custom callback.
- **Eloquent Integration** — `Blaspable` trait auto-sanitizes or rejects profanity on model save.
- **Middleware** — Reject or sanitize profane request fields with configurable severity.
- **Validation Rules** — Fluent validation rule with language, severity, and score threshold support.
- **Testing Utilities** — `Blasp::fake()` for test doubles with assertions.
- **Events** — `ProfanityDetected`, `ContentBlocked`, and `ModelProfanityDetected`.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 8.0+

Installation
------------

[](#installation)

```
composer require blaspsoft/blasp
```

Publish configuration:

```
# Everything (config + language files)
php artisan vendor:publish --tag="blasp"

# Config only
php artisan vendor:publish --tag="blasp-config"

# Language files only
php artisan vendor:publish --tag="blasp-languages"
```

Quick Start
-----------

[](#quick-start)

```
use Blaspsoft\Blasp\Facades\Blasp;

$result = Blasp::check('This is a fucking sentence');

$result->isOffensive();  // true
$result->clean();         // "This is a ******* sentence"
$result->original();      // "This is a fucking sentence"
$result->score();         // 30
$result->count();         // 1
$result->uniqueWords();   // ['fucking']
$result->severity();      // Severity::High
```

Fluent API
----------

[](#fluent-api)

All builder methods return a `PendingCheck` and can be chained:

```
// Language selection
Blasp::in('spanish')->check($text);
Blasp::in('english', 'french')->check($text);
Blasp::inAllLanguages()->check($text);

// Language shortcuts
Blasp::english()->check($text);
Blasp::spanish()->check($text);
Blasp::german()->check($text);
Blasp::french()->check($text);

// Driver selection
Blasp::driver('regex')->check($text);     // Full obfuscation detection (default)
Blasp::driver('pattern')->check($text);   // Fast exact matching
Blasp::driver('phonetic')->check($text);  // Sound-alike detection (e.g. "phuck", "sheit")
Blasp::driver('pipeline')->check($text);  // Chain multiple drivers (config-based)

// Ad-hoc pipeline — chain any drivers without config
Blasp::pipeline('regex', 'phonetic')->check($text);
Blasp::pipeline('pattern', 'phonetic')->in('english')->mask('#')->check($text);

// Shorthand modes
Blasp::strict()->check($text);   // Forces regex driver
Blasp::lenient()->check($text);  // Forces pattern driver

// Masking
Blasp::mask('*')->check($text);        // Character mask (default)
Blasp::mask('#')->check($text);        // Custom character
Blasp::mask('grawlix')->check($text);  // !@#$% cycling
Blasp::mask(fn($word, $len) => '[CENSORED]')->check($text);  // Callback

// Severity filtering
use Blaspsoft\Blasp\Enums\Severity;
Blasp::withSeverity(Severity::High)->check($text);  // Ignores mild/moderate

// Allow/block lists (merged with config)
Blasp::allow('damn', 'hell')->check($text);
Blasp::block('customword')->check($text);

// Chain everything
Blasp::spanish()
    ->mask('#')
    ->withSeverity(Severity::Moderate)
    ->check($text);

// Batch checking
$results = Blasp::checkMany(['text one', 'text two']);
```

Result Object
-------------

[](#result-object)

The `Result` object is returned by every `check()` call:

MethodReturnsDescription`isOffensive()``bool`Text contains profanity`isClean()``bool`Text is clean`clean()``string`Text with profanities masked`original()``string`Original unmodified text`score()``int`Severity score (0-100)`count()``int`Total profanity matches`uniqueWords()``array`Unique base words detected`severity()``?Severity`Highest severity in matches`words()``Collection``MatchedWord` objects with position, length, severity`toArray()``array`Full result as array`toJson()``string`Full result as JSON`Result` implements `JsonSerializable`, `Stringable` (returns clean text), and `Countable`.

Detection Types
---------------

[](#detection-types)

The regex driver detects obfuscated profanity:

TypeExampleDetected AsStraight match`fucking``fucking`Substitution`fÛck!ng`, `f4ck``fucking`, `fuck`Separators`f-u-c-k-i-n-g`, `f@ck``fucking`, `fuck`Doubled`ffuucckkiinngg``fucking`Combination`f-uuck!ng``fucking`> **Separator limit:** The regex driver allows up to 3 separator characters between each letter (e.g., `f--u--c--k`). This covers all realistic obfuscation patterns while keeping regex complexity low enough for PHP-FPM environments.

The pattern driver only detects straight word-boundary matches.

The phonetic driver uses `metaphone()` + Levenshtein distance to catch words that *sound like* profanity but are spelled differently:

TypeExampleDetected AsPhonetic spelling`phuck``fuck`Shortened form`fuk``fuck`Sound-alike`sheit``shit`Configure sensitivity in `config/blasp.php` under `drivers.phonetic`. A curated false-positive list prevents common words like "fork", "duck", and "beach" from being flagged.

### Pipeline Driver

[](#pipeline-driver)

The pipeline driver chains multiple drivers together so a single `check()` call runs all of them. It uses **union merge** semantics — text is flagged if **any** driver finds a match.

```
// Config-based: set 'default' => 'pipeline' or use driver('pipeline')
Blasp::driver('pipeline')->check('phuck this sh1t');

// Ad-hoc: pick drivers on the fly (no config needed)
Blasp::pipeline('regex', 'phonetic')->check('phuck this sh1t');
Blasp::pipeline('regex', 'pattern', 'phonetic')->check($text);
```

When multiple drivers detect the same word at the same position, duplicates are removed — only the longest match is kept. Masks are applied from the merged result, and the score is recalculated across all matches.

Configure the default sub-drivers in `config/blasp.php`:

```
'drivers' => [
    'pipeline' => [
        'drivers' => ['regex', 'phonetic'],  // Drivers to chain
    ],
],
```

Eloquent Integration
--------------------

[](#eloquent-integration)

The `Blaspable` trait automatically checks model attributes during save:

```
use Blaspsoft\Blasp\Blaspable;

class Comment extends Model
{
    use Blaspable;

    protected array $blaspable = ['body', 'title'];
}
```

```
// Sanitize mode (default) — profanity is masked, model saves
$comment = Comment::create(['body' => 'This is fucking great']);
$comment->body; // "This is ******* great"

// Check what happened
$comment->hadProfanity();            // true
$comment->blaspResults();            // ['body' => Result, 'title' => Result]
$comment->blaspResult('body');       // Result instance
```

### Per-Model Overrides

[](#per-model-overrides)

```
class Comment extends Model
{
    use Blaspable;

    protected array $blaspable = ['body', 'title'];
    protected string $blaspMode = 'reject';     // 'sanitize' (default) | 'reject'
    protected string $blaspLanguage = 'spanish'; // null = config default
    protected string $blaspMask = '#';           // null = config default
}
```

### Reject Mode

[](#reject-mode)

In reject mode, saving a model with profanity throws `ProfanityRejectedException` and the model is not persisted:

```
use Blaspsoft\Blasp\Exceptions\ProfanityRejectedException;

try {
    $comment = Comment::create(['body' => 'profane text']);
} catch (ProfanityRejectedException $e) {
    $e->attribute; // 'body'
    $e->result;    // Result instance
    $e->model;     // The unsaved model
}
```

### Disabling Checking

[](#disabling-checking)

```
Comment::withoutBlaspChecking(function () {
    Comment::create(['body' => 'unchecked content']);
});
```

### Events

[](#events)

A `ModelProfanityDetected` event fires whenever profanity is detected on a model attribute (both sanitize and reject modes):

```
use Blaspsoft\Blasp\Events\ModelProfanityDetected;

Event::listen(ModelProfanityDetected::class, function ($event) {
    $event->model;     // The model instance
    $event->attribute; // Which attribute had profanity
    $event->result;    // Result instance
});
```

Middleware
----------

[](#middleware)

Use `CheckProfanity` to filter incoming request fields. A `blasp` middleware alias is registered automatically:

```
// Using the short alias (recommended)
Route::post('/comment', CommentController::class)
    ->middleware('blasp');

// With parameters: action, severity
Route::post('/comment', CommentController::class)
    ->middleware('blasp:sanitize,mild');

// Or using the class directly
use Blaspsoft\Blasp\Middleware\CheckProfanity;

Route::post('/comment', CommentController::class)
    ->middleware(CheckProfanity::class);
```

ActionBehaviour`reject` (default)Returns 422 JSON with field errors`sanitize`Replaces profane fields in the request and continuesConfigure which fields to check in `config/blasp.php`:

```
'middleware' => [
    'action' => 'reject',
    'fields' => ['*'],                            // '*' = all fields
    'except' => ['password', 'email', '_token'],  // Always skipped
    'severity' => 'mild',
],
```

Validation Rules
----------------

[](#validation-rules)

### String Rule

[](#string-rule)

```
$request->validate([
    'comment' => ['required', 'blasp_check'],
    'bio'     => ['required', 'blasp_check:spanish'],
]);
```

### Fluent Rule Object

[](#fluent-rule-object)

```
use Blaspsoft\Blasp\Rules\Profanity;
use Blaspsoft\Blasp\Enums\Severity;

$request->validate([
    'comment' => ['required', Profanity::in('english')],
    'bio'     => ['required', Profanity::severity(Severity::High)],
    'tagline' => ['required', Profanity::maxScore(50)],
]);
```

Blade Directive
---------------

[](#blade-directive)

The `@clean` directive sanitizes and escapes text for safe display in views:

```
@clean($comment->body)

{{-- Equivalent to: {{ app('blasp')->check($comment->body)->clean() }} --}}
```

Output is HTML-escaped via `e()` for XSS safety.

Str / Stringable Macros
-----------------------

[](#str--stringable-macros)

Blasp registers macros on Laravel's `Str` and `Stringable` classes:

```
use Illuminate\Support\Str;

// Static methods
Str::isProfane('fuck this');        // true
Str::isProfane('hello');            // false
Str::cleanProfanity('fuck this');   // '**** this'
Str::cleanProfanity('hello');       // 'hello'

// Fluent Stringable methods
Str::of('fuck this')->isProfane();          // true
Str::of('fuck this')->cleanProfanity();     // Stringable('**** this')
Str::of('hello')->cleanProfanity()->upper(); // 'HELLO' (chaining works)
```

Configuration
-------------

[](#configuration)

Full `config/blasp.php` reference:

```
return [
    'default'   => env('BLASP_DRIVER', 'regex'),       // 'regex' | 'pattern' | 'phonetic' | 'pipeline'
    'language'  => env('BLASP_LANGUAGE', 'english'),    // Default language
    'mask'      => '*',                                 // Default mask character
    'severity'  => 'mild',                              // Minimum severity
    'events'    => false,                               // Fire ProfanityDetected events

    'cache' => [
        'enabled' => true,
        'driver'  => env('BLASP_CACHE_DRIVER'),
        'ttl'     => 86400,
        'results' => true,          // Cache check() results by content hash
    ],

    'middleware' => [
        'action'   => 'reject',
        'fields'   => ['*'],
        'except'   => ['password', 'email', '_token'],
        'severity' => 'mild',
    ],

    'model' => [
        'mode' => env('BLASP_MODEL_MODE', 'sanitize'),  // 'sanitize' | 'reject'
    ],

    'drivers' => [
        'pipeline' => [
            'drivers' => ['regex', 'phonetic'],    // Sub-drivers to chain
        ],
        'phonetic' => [
            'phonemes' => 4,                       // metaphone code length (2-8)
            'min_word_length' => 3,                // skip short words
            'max_distance_ratio' => 0.6,           // levenshtein threshold (0.3-0.8)
            'supported_languages' => ['english'],  // metaphone is English-oriented
            'false_positives' => ['fork', '...'],  // never flag these words
        ],
    ],

    'allow'  => [],    // Global allow-list
    'block'  => [],    // Global block-list

    'separators'      => [...],  // Characters treated as separators
    'substitutions'   => [...],  // Character leet-speak mappings
    'false_positives' => [...],  // Words that should never be flagged
];
```

Custom Drivers
--------------

[](#custom-drivers)

Implement `DriverInterface` and register with the manager:

```
use Blaspsoft\Blasp\Core\Contracts\DriverInterface;
use Blaspsoft\Blasp\Core\Result;
use Blaspsoft\Blasp\Core\Dictionary;
use Blaspsoft\Blasp\Core\Contracts\MaskStrategyInterface;

class MyDriver implements DriverInterface
{
    public function detect(string $text, Dictionary $dictionary, MaskStrategyInterface $mask, array $options = []): Result
    {
        // Your detection logic
    }
}

// Register in a service provider
Blasp::extend('my-driver', fn($app) => new MyDriver());

// Use it
Blasp::driver('my-driver')->check($text);
```

Caching
-------

[](#caching)

Blasp caches `check()` results by default. When the same text is checked with the same configuration (language, driver, severity, allow/block lists), the cached result is returned instantly.

```
// First call — runs full analysis, caches result
$result = Blasp::check('some text');

// Second call — returns cached result
$result = Blasp::check('some text');
```

Configure caching in `config/blasp.php`:

```
'cache' => [
    'enabled' => true,                      // Master switch for all caching
    'driver'  => env('BLASP_CACHE_DRIVER'), // null = default cache driver
    'ttl'     => 86400,                     // Cache lifetime in seconds
    'results' => true,                      // Cache check() results (disable independently)
],
```

Result caching is automatically bypassed when using a `CallbackMask` (closures can't be serialized). Clear both dictionary and result caches with:

```
php artisan blasp:clear
```

Or programmatically:

```
Dictionary::clearCache();
```

Artisan Commands
----------------

[](#artisan-commands)

```
# Clear the profanity cache
php artisan blasp:clear

# Test text from the command line
php artisan blasp:test "some text to check" --lang=english --detail

# List available languages with word counts
php artisan blasp:languages
```

Testing
-------

[](#testing)

### Faking

[](#faking)

```
use Blaspsoft\Blasp\Facades\Blasp;
use Blaspsoft\Blasp\Core\Result;

// Replace with a fake — all checks return clean by default
Blasp::fake();

// Pre-configure specific responses
Blasp::fake([
    'bad text'   => Result::withMatches(['fuck']),
    'clean text' => Result::none('clean text'),
]);

$result = Blasp::check('bad text');
$result->isOffensive(); // true

// Assertions
Blasp::assertChecked();
Blasp::assertCheckedTimes(1);
Blasp::assertCheckedWith('bad text');
```

### Disabling Filtering

[](#disabling-filtering)

```
Blasp::withoutFiltering(function () {
    // All checks return clean results
});
```

Events
------

[](#events-1)

Enable global events with `'events' => true` in config:

EventFired WhenProperties`ProfanityDetected``check()` finds profanity`result`, `originalText``ContentBlocked`Middleware detects profanity`result`, `request`, `field`, `action``ModelProfanityDetected`Blaspable trait detects profanity`model`, `attribute`, `result``ModelProfanityDetected` always fires (not gated by the `events` config).

Migrating from v3
-----------------

[](#migrating-from-v3)

### Namespace Changes

[](#namespace-changes)

v3v4`Blaspsoft\Blasp\Facades\Blasp``Blaspsoft\Blasp\Facades\Blasp` (unchanged)`Blaspsoft\Blasp\ServiceProvider``Blaspsoft\Blasp\BlaspServiceProvider`The Laravel auto-discovery handles provider/alias registration automatically. The facade namespace is the same as v3, so no import changes are needed for the facade.

### Config Changes

[](#config-changes)

v3 Keyv4 KeyNotes`default_language``language``default_language` still works as alias`mask_character``mask``mask_character` still works as alias`cache_driver``cache.driver``cache_driver` still works as alias—`default`New: driver selection (`regex`/`pattern`)—`severity`New: minimum severity level—`events`New: enable global events—`allow` / `block`New: global allow/block lists—`middleware`New: middleware configuration section—`model`New: Blaspable trait configuration### Result API Changes

[](#result-api-changes)

v3 Methodv4 Method`hasProfanity()``isOffensive()``getCleanString()``clean()``getSourceString()``original()``getProfanitiesCount()``count()``getUniqueProfanitiesFound()``uniqueWords()`All v3 methods still work as deprecated aliases.

### Builder API Changes

[](#builder-api-changes)

v3 Methodv4 Method`maskWith($char)``mask($char)``allLanguages()``inAllLanguages()``language($lang)``in($lang)``configure($profanities, $falsePositives)``block(...$words)` / `allow(...$words)`All v3 methods still work as deprecated aliases.

### New in v4

[](#new-in-v4)

- **Driver architecture** — `regex` and `pattern` drivers, custom driver support
- **Severity system** — Mild/Moderate/High/Extreme levels with scoring
- **Masking strategies** — Grawlix and callback masking
- **Blaspable trait** — Automatic Eloquent model profanity checking
- **Middleware** — Request-level profanity filtering
- **Fluent validation rule** — `Profanity::in('spanish')->severity(Severity::High)`
- **Testing utilities** — `Blasp::fake()`, assertions, `withoutFiltering()`
- **Events** — `ProfanityDetected`, `ContentBlocked`, `ModelProfanityDetected`
- **Artisan commands** — `blasp:clear`, `blasp:test`, `blasp:languages`
- **Batch checking** — `Blasp::checkMany([...])`
- **Multi-language in one call** — `Blasp::in('english', 'spanish')->check($text)`

Contributing
------------

[](#contributing)

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for detailed version history.

License
-------

[](#license)

Blasp is open-sourced software licensed under the [MIT license](LICENSE).

###  Health Score

58

—

FairBetter than 98% of packages

Maintenance77

Regular maintenance activity

Popularity55

Moderate usage in the ecosystem

Community23

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 83.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~27 days

Recently: every ~14 days

Total

20

Last Release

144d ago

Major Versions

v1.2.2 → v2.0.02025-02-27

v2.1.0 → v3.0.02025-09-05

v3.1.9 → v4.0.02026-03-26

PHP version history (2 changes)v1.0.0PHP ^7.4|^8.0

v2.0.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/25927364?v=4)[Michael Deeming](/maintainers/Deemonic)[@deemonic](https://github.com/deemonic)

---

Top Contributors

[![deemonic](https://avatars.githubusercontent.com/u/25927364?v=4)](https://github.com/deemonic "deemonic (131 commits)")[![charleskoko](https://avatars.githubusercontent.com/u/55494612?v=4)](https://github.com/charleskoko "charleskoko (22 commits)")[![damiantw](https://avatars.githubusercontent.com/u/19997758?v=4)](https://github.com/damiantw "damiantw (1 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (1 commits)")[![lucasltavares](https://avatars.githubusercontent.com/u/22200813?v=4)](https://github.com/lucasltavares "lucasltavares (1 commits)")[![moe-mizrak](https://avatars.githubusercontent.com/u/12977885?v=4)](https://github.com/moe-mizrak "moe-mizrak (1 commits)")

---

Tags

content-moderationlaravelphpprofanity-checkprofanity-detectionprofanity-filterprofanity-libraryprofanity-validatorprofanityfilterblaspsoftblasp

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/blaspsoft-blasp/health.svg)

```
[![Health](https://phpackages.com/badges/blaspsoft-blasp/health.svg)](https://phpackages.com/packages/blaspsoft-blasp)
```

###  Alternatives

[illuminate/validation

The Illuminate Validation package.

18838.8M2.0k](/packages/illuminate-validation)[sandermuller/laravel-fluent-validation

Fluent validation rule builders for Laravel

21428.9k6](/packages/sandermuller-laravel-fluent-validation)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
