rhukster/dom-sanitizer
PHP 7.3+ DOM/SVG/MathML sanitizer using DOMDocument and DOMPurify-based allowlists. Removes dangerous tags/attributes, with options for namespace/PHP/HTML/XML stripping and output compression. Customize allowed/disallowed tags and attributes.
composer require rhukster/dom-sanitizer
use Rhukster\DomSanitizer\DOMSanitizer;
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$cleanHtml = $sanitizer->sanitize($userInput);
// For SVG
$svgSanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$cleanSvg = $svgSanitizer->sanitize($svgString);
// For MathML
$mathSanitizer = new DOMSanitizer(DOMSanitizer::MATHML);
$cleanMath = $mathSanitizer->sanitize($mathmlString);
Sanitizing User-Generated Content in a Laravel Form
// In a Controller
public function store(Request $request)
{
$sanitizer = app(DOMSanitizer::class); // Resolve from container
$cleanContent = $sanitizer->sanitize($request->input('description'));
// Store sanitized content
Post::create([
'title' => $request->title,
'content' => $cleanContent,
]);
return redirect()->route('posts.index');
}
DOMSanitizer Class: Methods like addAllowedTags() for customization.// Laravel Middleware
public function handle($request, Closure $next)
{
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$request->merge([
'sanitized_content' => $sanitizer->sanitize($request->content),
]);
return $next($request);
}
// AppServiceProvider
public function boot()
{
Post::observe(PostObserver::class);
}
// PostObserver
public function saving(Post $post)
{
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$post->content = $sanitizer->sanitize($post->content);
}
// Blade template
{!! $sanitizer->sanitize($userComment) !!}
Laravel Service Container:
Bind the sanitizer in AppServiceProvider for dependency injection:
$this->app->singleton(DOMSanitizer::class, function () {
return new DOMSanitizer(DOMSanitizer::HTML);
});
Custom Config:
Store allowed tags in config/sanitizer.php:
return [
'allowed_tags' => ['p', 'b', 'i', 'a[href]'],
'disallowed_attributes' => ['style', 'onclick'],
];
Then apply in a service:
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$sanitizer->setAllowedTags(config('sanitizer.allowed_tags'));
SVG-Specific Features: Whitelist SVG filters for design tools:
$svgSanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$svgSanitizer->addAllowedTags(['feGaussianBlur', 'feColorMatrix']);
MathML for Equations: Disable compression for readability:
$mathSanitizer = new DOMSanitizer(DOMSanitizer::MATHML, [
'compress-output' => false,
]);
DOMSanitizer once (e.g., as a singleton) and reuse across requests.False Positives with Custom Rules:
disallowed_tags may strip valid content (e.g., <script> in MathML contexts).getAllowedTags()/getDisallowedTags() methods.SVG Filter Case Sensitivity:
<feGaussianBlur> must match the allowlist exactly (camelCase vs. lowercase).addAllowedTags() with correct casing or normalize tags.Entity Encoding Bypasses:
javascript:	alert(1) may bypass regex checks.Compression Artifacts:
compress-output: true may break SVG/MathML structure.$sanitizer->sanitize($svg, ['compress-output' => false]);
PHP Extensions:
dom and libxml extensions (enabled by default in Laravel).Inspect Sanitized Output:
$sanitizer->sanitize($input, ['debug' => true]); // Hypothetical; use DOM methods if needed.
$dom = new DOMDocument();
$dom->loadHTML($input);
$xpath = new DOMXPath($dom);
// Inspect nodes with $xpath->query('//*');
Validate Allowlists: Compare your custom rules against DOMPurify’s defaults:
$sanitizer->getAllowedTags(); // Check against https://github.com/cure53/DOMPurify
Event Handler Leaks:
If onclick attributes persist, ensure:
DOMSanitizer instance is fresh (reused instances may cache rules).addAllowedAttributes() overrides default behavior.Dynamic Allowlists: Load tags from a database or config:
$allowedTags = config('sanitizer.tags.forum');
$sanitizer->setAllowedTags($allowedTags);
Pre/Post-Processing:
Chain with Laravel’s Str::of() or HtmlString:
use Illuminate\Support\HtmlString;
$clean = new HtmlString($sanitizer->sanitize($input));
Custom Sanitizer Class:
Extend DOMSanitizer for project-specific logic:
class AppSanitizer extends DOMSanitizer {
public function __construct() {
parent::__construct(DOMSanitizer::HTML);
$this->addAllowedTags(['custom-tag']);
}
}
Testing: Use PHPUnit to verify sanitization:
public function testSanitizesScriptTags()
{
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$this->assertStringNotContainsString('<script>', $sanitizer->sanitize('<script>alert(1)</script>'));
}
Default Behavior:
remove-html-tags: true strips all HTML tags unless overridden.remove-php-tags: true removes <?php ?> blocks (useful for security).Namespace Handling:
remove-namespaces: false by default; set to true to strip XML namespaces (e.g., <svg xmlns="...">).Output Formatting:
compress-output: true minifies whitespace but may break SVG/MathML. Disable for structured content.Block JavaScript URIs:
Explicitly disallow javascript: in attributes:
$sanitizer->addDisallowedAttributes(['href[javascript:]']);
SVG-Specific Protections: Restrict SVG to a sandboxed subset:
$svgSanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$svgSanitizer->addDisallowedTags(['script', 'animate']);
MathML Safety: Whitelist only essential MathML tags:
$mathSanitizer = new DOMSanitizer(DOMSanitizer::MATHML);
$mathSanitizer
How can I help you explore Laravel packages today?