PHPackages                             yasser-elgammal/pure-text - 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. yasser-elgammal/pure-text

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

yasser-elgammal/pure-text
=========================

A Laravel package for filtering and replacing inappropriate or unwanted words with support for Arabic and Unicode, multiple replacement strategies, Blade directives, middleware, and more.

2.0.0(3w ago)1267MITPHPPHP ^8.1CI failing

Since Nov 8Pushed 3w ago1 watchersCompare

[ Source](https://github.com/YasserElgammal/pure-text)[ Packagist](https://packagist.org/packages/yasser-elgammal/pure-text)[ Docs](https://github.com/YasserElgammal/pure-text)[ RSS](/packages/yasser-elgammal-pure-text/feed)WikiDiscussions main Synced today

READMEChangelog (5)Dependencies (4)Versions (8)Used By (0)

PureText
========

[](#puretext)

[![Tests](https://github.com/YasserElgammal/pure-text/actions/workflows/tests.yml/badge.svg)](https://github.com/YasserElgammal/pure-text/actions/workflows/tests.yml)[![Latest Version](https://camo.githubusercontent.com/c5e9c6ae0d619361c795f355040bdf23a505e2f649c7f4ccbcf62e332ad26947/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7961737365722d656c67616d6d616c2f707572652d746578742e737667)](https://packagist.org/packages/yasser-elgammal/pure-text)[![License](https://camo.githubusercontent.com/2398da6e1d68268a9183eaa64d16f251330b74afdcceb5e9048194e53dd61e10/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7961737365722d656c67616d6d616c2f707572652d746578742e737667)](https://packagist.org/packages/yasser-elgammal/pure-text)[![PHP Version](https://camo.githubusercontent.com/8779955e09b5f30352b2287f494b82b08e9b004015f51e1969ba3bfce6eede72/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f7961737365722d656c67616d6d616c2f707572652d746578742e737667)](https://packagist.org/packages/yasser-elgammal/pure-text)

**PureText** is a Laravel package for filtering and replacing inappropriate or unwanted words within model attributes automatically. Designed to be customizable and efficient, PureText allows developers to specify filterable attributes for each model and handle multiple languages seamlessly — including **Arabic and other Unicode languages**.

---

✨ Features
----------

[](#-features)

- **Automatic Model Filtering** — Apply the `PureTextFilterable` trait and bad words are filtered on save.
- **Multiple Replacement Strategies** — Choose between `fixed`, `character`, or `length_match` replacements.
- **Unicode &amp; Arabic Support** — Proper Unicode-aware word boundaries for non-Latin languages.
- **Evasion Detection** — Catches common tricks like `b-a-d`, `b_a_d`, `b.a.d`.
- **Facade** — `PureText::filter()`, `PureText::containsBadWords()`, `PureText::getBadWords()`.
- **Blade Directive** — `@pureText($text)` for templates.
- **Middleware** — Filter request fields automatically via route middleware.
- **Validation Rule** — `pure_text` rule for Laravel Validator.
- **Helper Functions** — `pure_text()` and `has_bad_words()` global helpers.
- **Events** — `TextFiltered` event dispatched on model attribute filtering.
- **Customizable** — Bring your own implementation via `TextFilterInterface`.

---

📋 Requirements
--------------

[](#-requirements)

- PHP 8.1+
- Laravel 10, 11, or 12

---

📦 Installation
--------------

[](#-installation)

Install via Composer:

```
composer require yasser-elgammal/pure-text
```

Publish the configuration file:

```
php artisan vendor:publish --tag=pure-text-config
```

Configure your word list in `config/badwords.php`.

---

🚀 Usage
-------

[](#-usage)

### 1. Automatic Model Filtering (Trait)

[](#1-automatic-model-filtering-trait)

Add the `PureTextFilterable` trait to any model and define `$filterable` attributes:

```
use YasserElgammal\PureText\Traits\PureTextFilterable;

class Post extends Model
{
    use PureTextFilterable;

    protected $filterable = ['title', 'content'];
}
```

Now, bad words are automatically replaced when saving:

```
$post = new Post();
$post->title = "This is a badword example";
$post->save();

echo $post->title; // "This is a *** example"
```

### 2. Facade

[](#2-facade)

```
use YasserElgammal\PureText\Facades\PureText;

// Filter text
$clean = PureText::filter('Some bad text');

// Check if text contains bad words
if (PureText::containsBadWords($text)) {
    // handle it
}

// Get all bad words found
$words = PureText::getBadWords($text); // ['bad', 'ugly']
```

### 3. Blade Directive

[](#3-blade-directive)

```
@pureText($post->content)
```

### 4. Validation Rule

[](#4-validation-rule)

```
$request->validate([
    'title'   => 'required|pure_text',
    'content' => 'required|pure_text',
]);
```

### 5. Middleware

[](#5-middleware)

Register in your route:

```
// Filter all string fields
Route::post('/comment', [CommentController::class, 'store'])
    ->middleware('pure-text');

// Filter specific fields only
Route::post('/comment', [CommentController::class, 'store'])
    ->middleware('pure-text:title,content');
```

### 6. Helper Functions

[](#6-helper-functions)

```
// Filter text
$clean = pure_text('Some bad text');

// Check for bad words
if (has_bad_words($text)) {
    // handle it
}
```

---

⚙️ Configuration
----------------

[](#️-configuration)

After publishing, edit `config/badwords.php`:

```
return [
    // List of bad words to filter
    'words' => ['badword1', 'badword2'],

    // Replacement text (used with 'fixed' strategy)
    'replacement' => '***',

    // Strategy: 'fixed', 'character', or 'length_match'
    'strategy' => 'fixed',

    // Character used with 'character' strategy
    'character' => '*',
];
```

### Replacement Strategies

[](#replacement-strategies)

StrategyInputOutputDescription`fixed``badword``***`Replaces with the `replacement` value`character``badword``*******`Each character replaced with `character``length_match``badword``*******`First char of `replacement` repeated to match length---

🔌 Advanced: Custom Implementation
---------------------------------

[](#-advanced-custom-implementation)

You can swap the filter service with your own by binding `TextFilterInterface`:

```
use YasserElgammal\PureText\Contracts\TextFilterInterface;

$this->app->singleton(TextFilterInterface::class, function () {
    return new MyCustomFilterService();
});
```

---

📡 Events
--------

[](#-events)

When a model attribute is filtered via the `PureTextFilterable` trait, a `TextFiltered` event is dispatched:

```
use YasserElgammal\PureText\Events\TextFiltered;

class TextFilteredListener
{
    public function handle(TextFiltered $event): void
    {
        logger('Filtered text on model', [
            'original'  => $event->originalText,
            'filtered'  => $event->filteredText,
            'model'     => $event->model?->getTable(),
            'attribute' => $event->attribute,
        ]);
    }
}
```

---

🧪 Testing
---------

[](#-testing)

```
composer test
```

---

📄 Changelog
-----------

[](#-changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for recent changes.

🤝 Contributing
--------------

[](#-contributing)

Contributions are welcome! Please fork this repository and submit a pull request for any improvements.

📜 License
---------

[](#-license)

The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance77

Regular maintenance activity

Popularity17

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~116 days

Recently: every ~144 days

Total

6

Last Release

23d ago

Major Versions

1.x-dev → 2.0.02026-06-10

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/35766609?v=4)[Yasser Elgammal](/maintainers/YasserElgammal)[@YasserElgammal](https://github.com/YasserElgammal)

---

Top Contributors

[![YasserElgammal](https://avatars.githubusercontent.com/u/35766609?v=4)](https://github.com/YasserElgammal "YasserElgammal (16 commits)")

---

Tags

laravelunicodefilterprofanityarabiccontent moderationbad wordstext filter

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/yasser-elgammal-pure-text/health.svg)

```
[![Health](https://phpackages.com/badges/yasser-elgammal-pure-text/health.svg)](https://phpackages.com/packages/yasser-elgammal-pure-text)
```

###  Alternatives

[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77022.3M151](/packages/laravel-mcp)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8793.2M25](/packages/yajra-laravel-oci8)[propaganistas/laravel-disposable-email

Disposable email validator

6023.0M6](/packages/propaganistas-laravel-disposable-email)[axlon/laravel-postal-code-validation

Worldwide postal code validation for Laravel

3893.6M1](/packages/axlon-laravel-postal-code-validation)[wendelladriel/laravel-validated-dto

Data Transfer Objects with validation for Laravel applications

762649.9k18](/packages/wendelladriel-laravel-validated-dto)[sunspikes/clamav-validator

Custom Laravel anti-virus validator for file uploads using ClamAV.

3722.1M6](/packages/sunspikes-clamav-validator)

PHPackages © 2026

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