Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

🀬 🚫 Blasp is a profanity filter package for Laravel that helps detect and mask profane words in a given sentence. It offers a robust set of features for handling variations of offensive language, including substitutions, obscured characters, and doubled letters.

License

Notifications You must be signed in to change notification settings

Blaspsoft/blasp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

123 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Blasp Icon

Official API Available! This package powers blasp.app - a universal profanity filtering REST API that works with any language. Free tier with 1,000 requests/month, multi-language support, and custom word lists.

GitHub Workflow Status (main) Total Downloads Latest Version License

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

  • 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

  • PHP 8.2+
  • Laravel 8.0+

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

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

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

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

Method Returns Description
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

The regex driver detects obfuscated profanity:

Type Example Detected As
Straight 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:

Type Example Detected As
Phonetic 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

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

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

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

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

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

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

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);
Action Behaviour
reject (default) Returns 422 JSON with field errors
sanitize Replaces profane fields in the request and continues

Configure which fields to check in config/blasp.php:

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

Validation Rules

String Rule

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

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

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

<p>@clean($comment->body)</p>

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

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

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

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

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

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

# 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

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

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

Events

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

Event Fired When Properties
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

Namespace Changes

v3 v4
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

v3 Key v4 Key Notes
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

v3 Method v4 Method
hasProfanity() isOffensive()
getCleanString() clean()
getSourceString() original()
getProfanitiesCount() count()
getUniqueProfanitiesFound() uniqueWords()

All v3 methods still work as deprecated aliases.

Builder API Changes

v3 Method v4 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

  • 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

We welcome contributions! Please see our Contributing Guide for details.

Changelog

See CHANGELOG.md for detailed version history.

License

Blasp is open-sourced software licensed under the MIT license.

About

🀬 🚫 Blasp is a profanity filter package for Laravel that helps detect and mask profane words in a given sentence. It offers a robust set of features for handling variations of offensive language, including substitutions, obscured characters, and doubled letters.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 6

Languages