rhukster/dom-sanitizer
MIT-licensed PHP 7.3+ DOM/SVG/MathML sanitizer using DOMDocument and DOMPurify-based allowlists. Remove dangerous tags/attributes, strip namespaces and PHP/HTML/XML tags, and optionally compress output. Supports HTML, SVG, and MathML modes.
Installation:
composer require rhukster/dom-sanitizer
Add to composer.json under require:
"rhukster/dom-sanitizer": "^1.0.11"
Basic Usage (HTML):
use Rhukster\DomSanitizer\DOMSanitizer;
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$cleanHtml = $sanitizer->sanitize($untrustedHtml);
Basic Usage (SVG):
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$cleanSvg = $sanitizer->sanitize($untrustedSvg);
Sanitize user-uploaded SVG files in a Laravel app (e.g., profile avatars or diagrams):
use Rhukster\DomSanitizer\DOMSanitizer;
public function storeAvatar(Request $request)
{
$request->validate(['avatar' => 'required|file|mimes:svg']);
$svgContent = file_get_contents($request->file('avatar')->getRealPath());
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$cleanSvg = $sanitizer->sanitize($svgContent);
// Save $cleanSvg to storage...
}
DOMSanitizer Class: Methods like addAllowedTags() for customization.Sanitizing Dynamic Content:
// Laravel Blade example: Sanitize user comments
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$safeComment = $sanitizer->sanitize($userInput, [
'remove-php-tags' => true,
'compress-output' => false,
]);
SVG-Specific Processing:
// Whitelist custom SVG attributes (e.g., for a diagram tool)
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$sanitizer->addAllowedAttributes(['data-custom-id', 'data-layer']);
$cleanSvg = $sanitizer->sanitize($svgInput);
MathML Integration:
// Sanitize MathML for a LaTeX-to-MathML converter
$sanitizer = new DOMSanitizer(DOMSanitizer::MATHML);
$safeMathml = $sanitizer->sanitize($mathmlInput, [
'remove-namespaces' => true,
]);
Service Provider Binding:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(DOMSanitizer::class, function ($app) {
return new DOMSanitizer(DOMSanitizer::HTML);
});
}
Request Filter Middleware:
// app/Http/Middleware/SanitizeInput.php
public function handle($request, Closure $next)
{
$sanitizer = app(DOMSanitizer::class);
$request->merge([
'clean_content' => $sanitizer->sanitize($request->input('content')),
]);
return $next($request);
}
Form Request Validation:
// app/Http/Requests/SanitizeSvgRequest.php
public function sanitizeSvg($svg)
{
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
return $sanitizer->sanitize($svg);
}
Event Listeners:
// Sanitize model attributes before saving
public function saving($model)
{
if ($model->isDirty('svg_content')) {
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$model->svg_content = $sanitizer->sanitize($model->svg_content);
}
}
DOMSanitizer instance for repeated use (e.g., in a service container).'compress-output' => false if you need to inspect the sanitized output for debugging.XXE Risks in Legacy Code:
loadXML() or simplexml_load_string() elsewhere, ensure they also use LIBXML_NONET and disable entity loading:
libxml_disable_entity_loader(true);
$dom = new DOMDocument();
$dom->loadXML($input, LIBXML_NONET);
DOMSanitizer::sanitize().False Positives in SVG:
feGaussianBlur) were incorrectly removed in v1.0.9. Ensure you’re on ^1.0.10 or later.getAllowedTags() to verify filters are included.CSS Injection in <style>:
DOMSanitizer::SVG, <style> tags are stripped by default. If you need styles, whitelist them carefully:
$sanitizer->addAllowedTags(['style']);
$sanitizer->addAllowedAttributes(['style' => ['type']]);
addDisallowedAttributes(['style' => ['url']]) to block external CSS URLs.Entity Encoding Bypasses:
	) to smuggle javascript: URIs. The package fixes this in ^1.0.10, but test edge cases:
// Test case: Ensure this fails
$malicious = '<a href="javascript:alert(x)">Click</a>';
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$result = $sanitizer->sanitize($malicious); // Should strip the href
Namespace Handling:
xmlns="http://www.w3.org/2000/svg") are preserved by default. To remove them:
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG, [
'remove-namespaces' => true,
]);
Inspect Allowed/Disallowed Lists:
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
dump($sanitizer->getAllowedTags()); // View whitelisted tags
dump($sanitizer->getDisallowedAttributes()); // View blocked attributes
Log Sanitization Steps:
$sanitizer = new DOMSanitizer(DOMSanitizer::HTML);
$sanitizer->setLogger(function ($message) {
\Log::debug('DOMSanitizer', ['message' => $message]);
});
Test Edge Cases:
$input = <<<'XML'
<!DOCTYPE foo [
<!ENTITY a "aaaa">
<!ENTITY b "&a;&a;&a;&a;">
]>
<svg>&b;</svg>
XML;
$sanitizer = new DOMSanitizer(DOMSanitizer::SVG);
$result = $sanitizer->sanitize($input); // Should return empty or safe SVG
file:// and http:// references.
$input = '<svg><script xlink:href="file:///etc/passwd"/></svg>';
$result = $sanitizer->sanitize($input); // Should strip the script
How can I help you explore Laravel packages today?