PHPackages                             hadikhanzadeh/laravel-sanitizer - 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. hadikhanzadeh/laravel-sanitizer

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

hadikhanzadeh/laravel-sanitizer
===============================

Recursive, filter-based input sanitization for Laravel applications, with per-field rules and dot-notation support.

v1.0.4(today)09↑2566.7%MITPHPPHP ^8.4CI passing

Since Aug 28Pushed todayCompare

[ Source](https://github.com/hadikhanzadeh/laravel-sanitizer)[ Packagist](https://packagist.org/packages/hadikhanzadeh/laravel-sanitizer)[ RSS](/packages/hadikhanzadeh-laravel-sanitizer/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (4)Versions (6)Used By (0)

Laravel Sanitizer
=================

[](#laravel-sanitizer)

[![Latest Version on Packagist](https://camo.githubusercontent.com/682bf86323b59064da8e48b2b6db82395317f0ac4edcc2e4372b9434232ebb4a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f686164696b68616e7a616465682f6c61726176656c2d73616e6974697a65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hadikhanzadeh/laravel-sanitizer)[![Tests](https://camo.githubusercontent.com/f6dff84e18c770c48e36d2d4253acdfca5c44ef44a25a4a59e79c663f4adc5ad/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f686164696b68616e7a616465682f6c61726176656c2d73616e6974697a65722f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/hadikhanzadeh/laravel-sanitizer/actions)[![Total Downloads](https://camo.githubusercontent.com/4043276f0003ed01d7addc17b3418528822ac4ab9932ab7555b9dd6a0d7105e2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f686164696b68616e7a616465682f6c61726176656c2d73616e6974697a65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hadikhanzadeh/laravel-sanitizer)[![License](https://camo.githubusercontent.com/6a255f4539b735b61ecb8b02794b1bb4d0f3e5ad1331a62d23d00cada5f4f424/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f686164696b68616e7a616465682f6c61726176656c2d73616e6974697a65722e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)

Recursive, filter-based input sanitization for Laravel applications — with per-field rules, dot-notation support for nested data, a `FormRequest` trait for zero-boilerplate integration, and a `sanitize` middleware for route-level or global coverage.

Why this package
----------------

[](#why-this-package)

Cleaning request input in Laravel usually ends up as ad-hoc calls to `trim()` and `strip_tags()` scattered across controllers, or a single monolithic sanitizer class that's hard to extend. This package instead treats each sanitization step as a small, testable, swappable class — registered through config, resolved through the container, and safe for `config:cache`.

It's a spiritual successor to the now-unmaintained `waavi/sanitizer`, rebuilt for PHP 8.4 and Laravel 12/13 with an interface-based filter architecture.

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

[](#requirements)

- PHP 8.4+
- Laravel 12.x or 13.x

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

[](#installation)

```
composer require hadikhanzadeh/laravel-sanitizer
```

The service provider is auto-discovered — no manual registration needed.

Optionally publish the config file to customize registered filters or defaults:

```
php artisan vendor:publish --tag=sanitizer-config
```

Basic usage
-----------

[](#basic-usage)

Resolve the `Sanitizer` service directly:

```
use HadiKhanzadeh\LaravelSanitizer\Sanitizer;

$sanitizer = app(Sanitizer::class);

$clean = $sanitizer->clean([
    'name' => '  Hadi  ',
    'bio'  => 'alert(1)Hello',
]);

// ['name' => 'Hadi', 'bio' => 'Hello']
```

Or use the facade:

```
use HadiKhanzadeh\LaravelSanitizer\Facades\Sanitizer;

$clean = Sanitizer::clean($request->all());
```

Automatic sanitization in FormRequests
--------------------------------------

[](#automatic-sanitization-in-formrequests)

Add the `SanitizesInput` trait to any `FormRequest` to sanitize its payload automatically before validation runs:

```
use HadiKhanzadeh\LaravelSanitizer\Concerns\SanitizesInput;
use Illuminate\Foundation\Http\FormRequest;

final class StoreProductRequest extends FormRequest
{
    use SanitizesInput;

    public function rules(): array
    {
        return [
            'name' => ['required', 'string'],
        ];
    }
}
```

### Per-field rules

[](#per-field-rules)

Override `sanitizationRules()` to control which filters run on specific fields:

```
protected function sanitizationRules(): array
{
    return [
        'description' => ['editor'],
        'title' => ['trim', 'strip_tags'],
    ];
}
```

### Nested fields (dot notation)

[](#nested-fields-dot-notation)

```
protected function sanitizationRules(): array
{
    return [
        'address.postal_code' => ['trim'],
    ];
}
```

### Changing the default pipeline

[](#changing-the-default-pipeline)

Fields without an explicit rule fall back to `config('sanitizer.default_filters')` (`trim`, `strip_tags` by default). Override per request:

```
protected function defaultSanitizationFilters(): ?array
{
    return ['trim'];
}
```

### Opting out

[](#opting-out)

```
protected bool $sanitizeInput = false;
```

### Before/after hooks

[](#beforeafter-hooks)

```
protected function beforeSanitization(): void
{
    // runs before the Sanitizer touches the payload
}

protected function afterSanitization(): void
{
    // runs after sanitization, before validation
}
```

Global or per-route sanitization via middleware
-----------------------------------------------

[](#global-or-per-route-sanitization-via-middleware)

If you'd rather sanitize input at the HTTP layer instead of (or in addition to) individual `FormRequest`s, the package ships a `sanitize` middleware alias. Unlike the `SanitizesInput` trait, the middleware always applies the configured default filter pipeline (`config('sanitizer.default_filters')`) uniformly to every field — it has no concept of per-field rules, since a route (not a single request class) is where it's applied.

### Apply to specific routes or groups

[](#apply-to-specific-routes-or-groups)

```
use Illuminate\Support\Facades\Route;

Route::middleware('sanitize')->group(function () {
    Route::post('/products', [ProductController::class, 'store']);
    Route::put('/products/{product}', [ProductController::class, 'update']);
});
```

Or on a single route:

```
Route::post('/comments', [CommentController::class, 'store'])->middleware('sanitize');
```

### Apply globally to every request

[](#apply-globally-to-every-request)

To sanitize all incoming input application-wide, register the alias as a global middleware. In Laravel 11+ (`bootstrap/app.php`):

```
use HadiKhanzadeh\LaravelSanitizer\Http\Middleware\SanitizeInput;

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(SanitizeInput::class);
})
```

> **Note:** The package intentionally does **not** register this middleware globally by itself — only the `sanitize` alias is registered. Applying sanitization to every request in every application by default would be a surprising, hard-to-override side effect of merely installing the package. Opt in explicitly at the route, group, or global level as shown above.

### Middleware vs. the `SanitizesInput` trait

[](#middleware-vs-the-sanitizesinput-trait)

Middleware (`sanitize`)`SanitizesInput` traitScopeRoute / route group / globalPer `FormRequest` classPer-field rulesNot supported — default pipeline onlyFull support via `sanitizationRules()`Dot-notation nested rulesNot supportedSupportedOpt-outSimply don't apply the middleware`protected bool $sanitizeInput = false;`Use the middleware for blanket, low-effort coverage across many simple routes; use the trait when a specific request needs per-field control (e.g. an `editor` field that must allow limited HTML).

Built-in filters
----------------

[](#built-in-filters)

NameClassDescription`trim``TrimFilter`Trims leading/trailing whitespace.`strip_tags``StripTagsFilter`Removes all HTML/PHP tags.`stripslashes``StripSlashesFilter`Removes backslashes. Registered but **not** in the default pipeline — a legacy filter, opt in per-field only if needed.`editor``EditorFilter`Sanitizes rich-text HTML via [`mews/purifier`](https://github.com/mewebstudio/Purifier), stripping dangerous attributes (`onclick`, `javascript:` URLs) that a plain tag allow-list would miss. Requires `composer require mews/purifier` and a `purifier.editor` config preset.> **Note:** `htmlspecialchars` is intentionally **not** included. Escaping is an output-layer concern (Blade, API resources) — encoding on input causes double-encoding when the value is escaped again later.

Adding a custom filter
----------------------

[](#adding-a-custom-filter)

Implement `SanitizationFilter`:

```
namespace App\Sanitization\Filters;

use HadiKhanzadeh\LaravelSanitizer\Contracts\SanitizationFilter;

final readonly class LowercaseFilter implements SanitizationFilter
{
    public function apply(mixed $value): mixed
    {
        return is_string($value) ? mb_strtolower($value) : $value;
    }
}
```

Register it in `config/sanitizer.php`:

```
'filters' => [
    // ...
    'lowercase' => \App\Sanitization\Filters\LowercaseFilter::class,
],
```

Use it like any other filter name in your rules.

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT. See [LICENSE.md](LICENSE.md).

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance100

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity54

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 ~0 days

Total

5

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/68141819?v=4)[Hadi Khanzadeh](/maintainers/hadikhanzadeh)[@hadikhanzadeh](https://github.com/hadikhanzadeh)

---

Top Contributors

[![hadikhanzadeh](https://avatars.githubusercontent.com/u/68141819?v=4)](https://github.com/hadikhanzadeh "hadikhanzadeh (10 commits)")

---

Tags

laravelsecuritysanitizerxsssanitizationform-requestclean-input

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/hadikhanzadeh-laravel-sanitizer/health.svg)

```
[![Health](https://phpackages.com/badges/hadikhanzadeh-laravel-sanitizer/health.svg)](https://phpackages.com/packages/hadikhanzadeh-laravel-sanitizer)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.2k99.8M363](/packages/laravel-horizon)[laravel/sail

Docker files for running a basic Laravel application.

1.9k212.4M1.5k](/packages/laravel-sail)[illuminate/database

The Illuminate Database package.

2.8k55.8M13.4k](/packages/illuminate-database)[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M343](/packages/laravel-ai)[moonshine/moonshine

Laravel administration panel

1.3k268.2k90](/packages/moonshine-moonshine)

PHPackages © 2026

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