larahook/purifier
Laravel wrapper for HTMLPurifier that cleans and sanitizes untrusted HTML before it reaches your views. Filter user-generated content through a simple, configurable API to strip XSS and other malicious markup while preserving safe formatting.
Architecture fit
larahook/purifier is a thin Laravel service-provider wrapper around ezyang/htmlpurifier: a container binding, a facade, and a publishable config file. Architecturally it slots into a conventional Laravel monolith at the request boundary (sanitize on write) or the render boundary (sanitize on read). Two fit caveats matter for planning: (1) HTMLPurifier is an HTML4/XHTML-era sanitizer and does not natively understand HTML5 elements (<figure>, <video>, data-*), so any product surface relying on modern markup needs custom config or will silently lose content; (2) it is a poor fit for API-only/headless services where sanitization is better owned by the consuming client or by a modern allowlist sanitizer. This is an infrastructure utility, not a differentiating capability — the opportunity score (35.5) is consistent with that: useful, low strategic leverage.
Integration feasibility
Wiring is hours, not days: composer require, auto-discovery, php artisan vendor:publish, facade call. The real cost is policy, not plumbing — defining HTML.Allowed, attribute allowlists, and URI schemes is a security decision that needs review and a test corpus. Feasibility is high if the package installs cleanly on our Laravel/PHP matrix; that is unverified from the metadata.
Technical risk The dominant risk is supply chain, not code. Two stars and zero dependents means effectively no community scrutiny, no downstream issue triage, and no independent confirmation that the wrapper tracks Laravel's container/config changes across 9, 10, 11, and 12. Treat it as vendored code we own that happens to live on Packagist. Secondary risks: HTMLPurifier itself is mature but in low-maintenance mode (rare but real CVE cadence, with fixes landing upstream, not here); and performance is a known hazard — HTMLPurifier is DOM-based and can cost hundreds of milliseconds per large document if the definition cache is not configured correctly. The 2026-03-25 release date is encouraging for liveness but says nothing about breadth of testing.
Key questions
composer.json constraints for laravel/framework, php, and ezyang/htmlpurifier? Does it install on our current Laravel and PHP 8.3/8.4?mews/purifier? If so, what changed, and why would we take the fork over the ~2k-star original?clean()/purify() facade parity with upstream wrappers?Stack fit
Fits a standard Laravel application on PHP 8.x. Verify against our actual framework version first — a Laravel 5-era wrapper may declare illuminate/support constraints that block install on 10/11/12, in which case we fork and bump constraints rather than downgrade the app.
Migration path
If we are already on mews/purifier, the swap is a namespace change, facade alias update, and config diff — low mechanical cost, but re-run the sanitization contract tests because default configs differ. If we are greenfield, do not call the facade directly from controllers/models. Introduce an application-owned Sanitizer interface with a purify(string $html): string method and bind the package behind it. That single indirection lets us replace this package with Symfony's HtmlSanitizer (HTML5-aware, actively maintained) or a forked copy without touching call sites — the cheapest insurance available given the adoption profile.
Compatibility
Two environment traps to design around: config publishing versus config:cache (published config must be static and committed, not generated at boot), and the definition cache path — in immutable/containerized deploys the cache directory must be created at image build or mounted writable, or HTMLPurifier falls back to its slow reparse path. Pin the exact package version and the underlying ezyang/htmlpurifier version; mirror both to an internal Composer registry so a yanked upstream release cannot break a deploy.
Sequencing
Sanitizer interface; write contract tests that run against the wrapper so a future swap is a config change.Maintenance
Assume we own it. Budget a pinned version, an internal mirror, a subscription to upstream HTMLPurifier releases, and a light quarterly review of the wrapper's Laravel compatibility. Realistic ongoing cost is low single-digit engineer-hours per quarter — until an upstream CVE forces a patch, at which point the wrapper's thinness is a benefit: we can bump ezyang/htmlpurifier in our fork without waiting for a maintainer.
Support No community to lean on: no issue triage, no Stack Overflow corpus, no downstream bug reports. Mitigate by keeping the wrapper's own surface small (provider + config) and relying on upstream HTMLPurifier's genuinely good documentation for policy questions. Ensure at least two engineers can read the config vocabulary; a single-owner bus factor here is a content-security risk.
Scaling Sanitization is CPU-bound and synchronous per request. Three levers, in order of value: sanitize-on-write for immutable content (comments, imported articles) so the cost is paid once; enable the definition cache so HTMLPurifier's grammar isn't rebuilt per process; cache purified output keyed by content hash for hot read paths. For bulk imports (legacy content migration, CSV/HTML uploads), move sanitization to a queue worker so it doesn't inflate request latency or trip PHP time/memory limits. Cap input size before the sanitizer — a multi-megabyte document will hurt regardless of configuration.
Failure modes
libxml version differences between base images can change parsing behavior across instances; pin the runtime image.Ramp-up Integration learning curve is roughly an hour for any Laravel developer. Policy authoring is the expensive part: HTMLPurifier's configuration vocabulary is idiosyncratic and under-documented for HTML5, so plan on half a day of focused work plus a written runbook covering the allowlist rationale, the definition-cache path, and the escalation path for upstream security releases. Given the package's adoption profile, the runbook is not optional — it is the primary control that makes a 2-star dependency operationally acceptable.
How can I help you explore Laravel packages today?