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

symfony/html-sanitizer

Symfony HtmlSanitizer provides an OO API to clean untrusted HTML for safe DOM insertion. Configure allowed/blocked elements and attributes, drop or keep children, force attributes, enforce HTTPS, and restrict link schemes/hosts to prevent XSS and unsafe behavior.

View on GitHub
Deep Wiki
Context7
## Getting Started

### First Steps
1. **Installation**: Add the package via Composer:
   ```bash
   composer require symfony/html-sanitizer

For Laravel, ensure compatibility with your PHP version (PHP 8.1+ recommended).

  1. Basic Setup: Create a sanitizer instance with a minimal config:

    use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
    use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;
    
    $config = (new HtmlSanitizerConfig())
        ->allowSafeElements(); // Start with a safe baseline
    
    $sanitizer = new HtmlSanitizer($config);
    
  2. First Use Case: Sanitize user-generated HTML in a comment system:

    $userInput = '<p>Hello <b>World</b>! <script>alert("XSS")</script></p>';
    $cleanHtml = $sanitizer->sanitize($userInput);
    // Output: <p>Hello <b>World</b>!</p>
    

Key Entry Points

  • sanitize(): Core method for sanitizing HTML strings.
  • sanitizeFor(): Context-aware sanitization (e.g., head, textarea).
  • HtmlSanitizerConfig: Builder for rules (elements, attributes, URLs).

Implementation Patterns

Common Workflows

1. Dynamic Content Sanitization

  • Use Case: User-generated content (comments, rich-text editors).
  • Pattern:
    $config = (new HtmlSanitizerConfig())
        ->allowSafeElements()
        ->allowElement('a', ['href', 'title'])
        ->allowElement('img', ['src', 'alt'])
        ->allowAttribute('class', '*')
        ->forceHttpsUrls();
    
    $sanitizer = new HtmlSanitizer($config);
    
    // In a controller:
    $cleanHtml = $sanitizer->sanitize(request()->input('content'));
    return view('post.show', ['content' => $cleanHtml]);
    

2. Context-Specific Sanitization

  • Use Case: Sanitizing HTML for specific DOM contexts (e.g., <head> vs. <body>).
  • Pattern:
    // For meta tags in <head>
    $metaContent = $sanitizer->sanitizeFor('head', $userInput);
    
    // For textarea content (escape HTML)
    $textareaContent = $sanitizer->sanitizeFor('textarea', $userInput);
    

3. URL Sanitization

  • Use Case: Restricting links/media to trusted domains.
  • Pattern:
    $config = (new HtmlSanitizerConfig())
        ->allowSafeElements()
        ->allowLinkSchemes(['https', 'mailto'])
        ->allowLinkHosts(['trusted.com', '*.example.org'])
        ->allowRelativeLinks();
    
    $sanitizer = new HtmlSanitizer($config);
    

4. Attribute-Level Control

  • Use Case: Allowing specific attributes (e.g., data-*) while blocking others.
  • Pattern:
    $config = (new HtmlSanitizerConfig())
        ->allowSafeElements()
        ->allowAttribute('data-custom', '*') // Allow on all elements
        ->dropAttribute('onclick', '*')      // Block globally
        ->forceAttribute('a', 'rel', 'noopener noreferrer');
    

5. Reusable Configurations

  • Use Case: Sharing sanitizer rules across services.
  • Pattern:
    // config/sanitizer.php
    return [
        'default' => (new HtmlSanitizerConfig())
            ->allowSafeElements()
            ->allowElement('div', ['class'])
            ->forceHttpsUrls(),
    
        'rich_text' => (new HtmlSanitizerConfig())
            ->allowStaticElements()
            ->allowElement('a', ['href', 'title'])
            ->allowElement('img', ['src', 'alt']),
    ];
    
    // In a service:
    $sanitizer = new HtmlSanitizer(config('sanitizer.default'));
    

Integration Tips

Laravel-Specific Patterns

  1. Service Provider Binding:

    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->singleton(HtmlSanitizer::class, function ($app) {
            $config = (new HtmlSanitizerConfig())
                ->allowSafeElements()
                ->allowElement('a', ['href', 'title']);
            return new HtmlSanitizer($config);
        });
    }
    
  2. Form Request Validation + Sanitization:

    // app/Http/Requests/SanitizeContentRequest.php
    public function validated()
    {
        $data = parent::validated();
        $data['content'] = app(HtmlSanitizer::class)->sanitize($data['content']);
        return $data;
    }
    
  3. Blade Directives:

    // app/Providers/BladeServiceProvider.php
    Blade::directive('sanitize', function ($expression) {
        return "<?php echo app(\\Symfony\\Component\\HtmlSanitizer\\HtmlSanitizer::class)->sanitize({$expression}); ?>";
    });
    
    // In Blade:
    @sanitize($userInput)
    

Performance Considerations

  • Reuse Configurations: Instantiate HtmlSanitizer once per context (e.g., per HTTP request).
  • Cache Configurations: For static rules, pre-configure and reuse the HtmlSanitizerConfig.
  • Avoid Over-Sanitization: Only allow elements/attributes you explicitly need.

Gotchas and Tips

Pitfalls

  1. Attribute Sanitizer Caveats:

    • allowAttribute('*', '*') is not a wildcard for all attributes. Use allowSafeAttributes() or explicitly list attributes.
    • forceAttribute() replaces all values of the attribute, not just adds to them.
  2. URL Handling Quirks:

    • allowRelativeLinks() does not imply allowRelativeMedias(). Configure separately.
    • Hosts with wildcards (e.g., *.example.org) must be exact matches for subdomains.
  3. Context Misuse:

    • sanitizeFor('head', ...) drops <body>-only tags (e.g., <div>), but sanitizeFor('div', ...) treats it as body context.
    • sanitizeFor('textarea', ...) escapes HTML (not sanitizes). Use sanitize() for HTML content.
  4. Nested Elements:

    • Blocking a parent element (e.g., blockElement('section')) retains children. Use dropElement() to remove them entirely.
  5. PHP 8.4+ Native Parser:

    • On PHP 8.4+, the package uses the native HTML5 parser. Test edge cases (e.g., malformed HTML) if downgrading.

Debugging Tips

  1. Inspect Sanitized Output:

    $sanitizer->sanitize($input, true); // Returns array with warnings/errors
    
  2. Log Configuration:

    $config->debug(true); // Logs dropped elements/attributes
    
  3. Test Edge Cases:

    • Malformed HTML: Use <div><p>test</div> to test parser resilience.
    • Unicode/URLs: Test BiDi marks (e.g., &#x202E;) and percent-encoded spaces.

Extension Points

  1. Custom Attribute Sanitizers:

    use Symfony\Component\HtmlSanitizer\AttributeSanitizerInterface;
    
    class CustomAttributeSanitizer implements AttributeSanitizerInterface
    {
        public function sanitize(string $name, string $value, string $element): string
        {
            if ($name === 'data-custom') {
                return preg_replace('/[^a-z0-9_-]/i', '', $value);
            }
            return $value;
        }
    }
    
    $config->withAttributeSanitizer(new CustomAttributeSanitizer());
    
  2. Override Default Rules:

    • Extend HtmlSanitizerConfig for reusable rule sets:
      class AppHtmlSanitizerConfig extends HtmlSanitizerConfig
      {
          public function __construct()
          {
              parent::__construct();
              $this->allowSafeElements()
                   ->allowElement('a', ['href', 'title'])
                   ->forceHttpsUrls();
          }
      }
      
  3. Event Listeners:

    • Use Symfony’s event system to modify sanitization dynamically (e.g., per-user rules):
      $sanitizer->addListener('sanitize', function ($event) {
          if ($event->getContext() === 'body') {
              $event->getConfig()->allowElement('custom-tag');
          }
      });
      

Security Notes

  • Always Sanitize: Never trust user input, even if "pre-sanitized."
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
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata