Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Binput Laravel Package

graham-campbell/binput

Binput is a Laravel input cleaner that sanitises user input via HTMLPurifier, stripping dangerous markup while keeping safe content. It handles strings and arrays, supports cleaning types such as default, html, url and query, and integrates through a simple facade for safer request data.

View on GitHub
Deep Wiki
Context7

Getting Started

Check constraints before you install. The current line is v11.1.0, which explicitly adds Laravel 11 support. Read composer.json for the php and illuminate/* constraints and match them against your app. Laravel 12 is not claimed — treat L12 as unverified until you have run your own suite against it.

composer require graham-campbell/binput

The service provider and the Binput facade alias are registered by package auto-discovery, so no config/app.php edit is normally required. Confirm with php artisan about (or php artisan package:discover) that the provider is in the discovered list and the alias resolves.

Read src/ before you use it — it is small. This is a thin wrapper around the request layer exposed behind one facade. An hour in the source answers the questions that matter more reliably than any README: the exact method set (typically get, all, only, except), the default value each returns for a missing key, and — critically — whether values come back raw or processed. The package name and description ("Input Protector", "sanitizing and filtering support") suggest transformation; the method surface suggests a reader. Determine which one you actually have before you design around it.

First use case: collapse inconsistent input reads in one controller. Pick an endpoint where you currently mix request()->input(), request()->query(), and json_decode($request->getContent(), true):

use GrahamCampbell\Binput\Facades\Binput;

public function store()
{
    $name = Binput::get('name');
    $page = Binput::get('page', 1);
    $tags = Binput::get('tags', []);
    // ...
}

Then write a characterization test for that endpoint against application/x-www-form-urlencoded, application/json, and a query string, and diff the responses against the pre-change behaviour. That diff is your real acceptance criterion.

Implementation Patterns

Use the facade in controllers and prepareForValidation(). The natural home for it is request-shaping code: controllers, Form Requests that need to normalize a value before rules run, and API resources mapping input onto a DTO.

protected function prepareForValidation(): void
{
    $this->merge([
        'body' => trim((string) Binput::get('body', '')),
    ]);
}

Make defaults explicit at the call site. Binput::get('key', $default) replaces chains of ?? null guards. If your team standardizes on it, the "missing key" contract becomes visible in the call rather than buried in a conditional three lines later.

Use only() / except() to shape payload arrays, not as a substitute for $fillable/$guarded. Building a DTO input array with Binput::only([...]) is tidy; passing it straight into Model::create() still needs mass-assignment protection. Keep those two concerns separate.

Convert one vertical slice per PR. Don't rewrite every request()->input() in a single change. Convert one endpoint, add the content-type tests, review the diff, then expand. Type coercion, empty-string-vs-null, and nested-array handling are exactly the differences you want to surface while the diff is still auditable.

Keep validation as the gate. Whatever Binput does or doesn't do to the value, Form Requests and validation rules remain the actual contract. The pipeline to document in your team README is: read via Binput → validate via Form Request → map to DTO/Model → escape on output. That sentence is what stops the next developer treating the facade as a sanitizer.

Pass arrays explicitly in jobs and commands. A facade has no HTTP-boundary limitation, so a queued job that receives a payload can normalize through the same accessor — but only if the payload is handed to it deliberately. Be explicit at the call site about which values are trusted (from your own code) and which are untrusted (client-supplied), because inside a job there is no request to fall back on.

Test the contract, not the internals. Assert response shape:

it('reads and returns the submitted name', function () {
    $this->postJson('/profile', ['name' => 'Ada Lovelace'])
         ->assertOk()
         ->assertJsonPath('name', 'Ada Lovelace');
});

Add one case each for form-encoded, JSON, and query-string access on any endpoint you convert — that is precisely the surface where you are relying on the package to normalize behaviour.

Gotchas and Tips

"Input Protector" is a marketing name, not a security guarantee. Nothing here should replace validation, output escaping, parameterized queries, $fillable/$guarded, or policies. And if the package does transform values, layering it under Blade's auto-escaping is a direct route to double-encoded output (<) that corrupts legitimate content like names and apostrophes.

Verify the transformation behaviour empirically, first. Send <script>alert(1)</script>, " padded ", and ["a" => "<b>"] through it and log what comes back. This one five-minute test settles whether you have a pure reader or a sanitizer, and determines whether you must choose a single input policy (escape on output or sanitize on input) before rollout. Do this in staging, on your pinned version.

Missing key vs. empty string vs. null. Confirm what Binput::get('k') returns for an absent key and how that interacts with ConvertEmptyStringsToNull, required, and nullable. Write a test that hits both a missing key and a present-but-empty value — that is where the subtle bugs live.

JSON, nested bodies, and dot notation. The pitch is one accessor across content types, so test all three, and specifically test nested payloads ({"user":{"name":"x"}}) and dot access (Binput::get('user.name')). Verify rather than assume; behaviour may differ from $request->input().

File uploads are not input. Keep using $request->file('avatar') and $request->hasFile(). The facade reads scalar and array values, not UploadedFile instances.

Alias collisions. Binput is a global class alias. If you have a model, DTO, or service of the same name, resolution will conflict — rename yours or the alias config.

Low adoption means you own this source. A single maintainer and effectively zero dependents means limited public scrutiny and no guaranteed L12/L13 support. Pin the version, vendor or fork it into your repo if it becomes load-bearing, and add your own tests around the retrieval behaviour you depend on. That turns a future silent boot failure into a routine maintenance chore.

Debugging a surprise value. Hit a local instance with curl using the exact content type, and log Binput::get('key') next to $request->input('key') for the same request. The side-by-side comparison immediately narrows the cause to content type, dot notation, default handling, or transformation — far faster than reading the source cold.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings