Weave Code
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

Html Sanitizer Laravel Package

typo3/html-sanitizer

Standalone PHP HTML sanitizer from TYPO3. Define sanitization rules via Behavior, apply with Visitors, and get a ready-to-use Sanitizer via Builders/presets. Control allowed tags, attributes, and values; encode or remove invalid nodes and comments.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require typo3/html-sanitizer
    
  2. Basic Usage Import the CommonBuilder for predefined safe HTML rules:

    use TYPO3\HtmlSanitizer\Builder\CommonBuilder;
    use TYPO3\HtmlSanitizer\Sanitizer;
    
    $builder = new CommonBuilder();
    $sanitizer = $builder->build();
    $cleanHtml = $sanitizer->sanitize($unsafeHtml);
    
  3. First Use Case Sanitize user-generated content (e.g., comments, forum posts) to prevent XSS:

    $userInput = '<script>alert("XSS")</script><p>Safe content</p>';
    $safeOutput = $sanitizer->sanitize($userInput);
    // Output: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;<p>Safe content</p>
    

Where to Look First

  • CommonBuilder: Predefined safe HTML rules (e.g., <p>, <a>, <img>).
  • Behavior: Customize allowed tags, attributes, and values.
  • Sanitizer: Core class for sanitizing HTML.

Implementation Patterns

Core Workflow

  1. Define Rules Use CommonBuilder or create a custom Behavior:

    $behavior = (new Behavior())
        ->withTags(
            (new Behavior\Tag('div'))->addAttrs(new Behavior\Attr('class')),
            (new Behavior\Tag('a'))->addAttrs(
                (new Behavior\Attr('href'))
                    ->addValues(new Behavior\RegExpAttrValue('#^https?://#'))
            )
        );
    
  2. Build Sanitizer

    $sanitizer = new Sanitizer($behavior, new CommonVisitor($behavior));
    
  3. Sanitize Input

    $cleanHtml = $sanitizer->sanitize($userInput);
    

Integration Tips

  • Laravel Blade Directives Create a custom Blade directive for reusable sanitization:

    Blade::directive('sanitize', function ($expression) {
        $sanitizer = resolve(Sanitizer::class);
        return "<?php echo {$sanitizer}->sanitize({$expression}); ?>";
    });
    

    Usage:

    @sanitize($userComment)
    
  • Form Request Validation Sanitize input in FormRequest validation:

    public function rules()
    {
        return [
            'bio' => 'required|string',
        ];
    }
    
    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            $sanitizer = app(Sanitizer::class);
            $validator->request->merge([
                'bio' => $sanitizer->sanitize($validator->request->bio),
            ]);
        });
    }
    
  • Service Provider Binding Bind Sanitizer in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(Sanitizer::class, function ($app) {
            $builder = new CommonBuilder();
            return $builder->build();
        });
    }
    
  • Dynamic Rule Sets Use BuilderInterface to create multiple sanitizers for different contexts (e.g., admin vs. public content):

    $adminBuilder = new CommonBuilder();
    $adminBuilder->allowTags(['script']); // Only for trusted admins
    $adminSanitizer = $adminBuilder->build();
    

Gotchas and Tips

Pitfalls

  1. Immutable Behavior Methods like withTags() return a new instance. Always reassign:

    $behavior = $behavior->withTags(new Behavior\Tag('span'));
    
  2. Mandatory Attributes Forgetting to mark attributes as mandatory (e.g., href for <a>) will silently remove the tag:

    (new Behavior\Tag('a'))
        ->addAttrs(
            (new Behavior\Attr('href'))
                ->withFlags(Behavior\Attr::MANDATORY)
        );
    
  3. Custom Elements Avoid ALLOW_CUSTOM_ELEMENTS flag. Explicitly list allowed tags (e.g., <my-custom>) to prevent unexpected HTML.

  4. Encoding Flags ENCODE_INVALID_TAG keeps invalid tags but "disarms" them (e.g., <script> becomes &lt;script&gt;). Use REMOVE_UNEXPECTED_CHILDREN to strip children from disallowed tags.

  5. CDATA and Comments By default, comments and CDATA sections are allowed but encoded. Explicitly disable them:

    $behavior->withoutNodes(new Behavior\Comment());
    
  6. Raw Text Bypass Avoid ALLOW_INSECURE_RAW_TEXT unless absolutely necessary (security risk). Use custom handlers instead:

    $behavior->withNodes(
        new Behavior\NodeHandler(
            new Behavior\Tag('raw'),
            new Behavior\Handler\ClosureHandler(
                fn ($node) => $node->textContent // Custom logic
            )
        )
    );
    

Debugging

  • Log Sanitization Steps Enable debug logging in CommonVisitor:

    $visitor = new CommonVisitor($behavior, [
        'debug' => true,
        'logger' => \Psr\Log\LoggerInterface::class,
    ]);
    
  • Inspect DOM Nodes Use DOMDocument to debug parsed HTML:

    $dom = new DOMDocument();
    $dom->loadHTML($userInput, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXPath($dom);
    $nodes = $xpath->query('//script'); // Check for disallowed nodes
    

Extension Points

  1. Custom Visitors Extend VisitorInterface to add preprocessing/postprocessing:

    class MyVisitor implements VisitorInterface
    {
        public function visit(NodeInterface $node, DOMNode $domNode): void
        {
            if ($domNode->nodeName === 'a' && !$domNode->hasAttribute('href')) {
                $domNode->parentNode->removeChild($domNode);
            }
        }
    }
    
  2. Attribute Value Validation Use RegExpAttrValue or CallbackAttrValue for dynamic validation:

    $emailAttr = (new Behavior\Attr('data-email'))
        ->addValues(new Behavior\CallbackAttrValue(
            fn ($value) => filter_var($value, FILTER_VALIDATE_EMAIL) !== false
        ));
    
  3. Output Rules Override serialization rules (e.g., for custom tags):

    $sanitizer = new Sanitizer($behavior, new CommonVisitor($behavior));
    $sanitizer->setSerializer(new CustomSerializer($behavior));
    
  4. Performance Reuse Sanitizer instances (they are stateless). Cache builders for common use cases:

    $cache = new \Symfony\Component\Cache\Simple\FilesystemCache();
    $builder = $cache->get('html_sanitizer_builder', function () {
        return new CommonBuilder();
    });
    

Security Quirks

  • Always Sanitize Early Sanitize input before processing (e.g., in FormRequest or controller) to fail fast.

  • Test Edge Cases Test with payloads like:

    <svg onload=alert(1)>
    <script>/*<![CDATA[*/alert(1)//]]>*/
    

    Ensure they are encoded or removed.

  • Avoid Whitelisting javascript: Even if allowed, javascript: URIs can bypass sanitization. Use RegExpAttrValue to restrict to http:///https:// only.

Laravel-Specific Tips

  • Store Sanitizer in Cache Reduce overhead for repeated requests:

    $sanitizer = Cache::remember('html_sanitizer', now()->addHours(1), function () {
        return (new CommonBuilder())->build();
    });
    
  • Use in Form Requests Sanitize input during validation:

    public function passedValidation()
    {
        $this->merge([
            'content' => app(Sanitizer::class)->sanitize($this->content),
        ]);
    }
    
  • Middleware for Global Sanitization Sanitize all user input in middleware:

    public function handle($request, Closure $next)
    {
        $sanitizer = app(Sanitizer::class);
        $request->replace(array_map(
            fn ($value) => is_string($value) ? $sanitizer->sanitize($value) : $value,
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi