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 sanitizing rules via Behavior, apply multiple Visitors, and run through a Sanitizer built from reusable presets. Supports safe tag/attribute allowlists, value validation (e.g., regex), and encoding or removing invalid nodes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require typo3/html-sanitizer
    
  2. Basic Usage:
    use TYPO3\HtmlSanitizer\Sanitizer;
    use TYPO3\HtmlSanitizer\Builder\CommonBuilder;
    
    $sanitizer = (new CommonBuilder())->build();
    $cleanHtml = $sanitizer->sanitize('<div>Unsafe <script>alert("XSS")</script> content</div>');
    

First Use Case: User-Generated Content

Sanitize HTML from user inputs (comments, posts, etc.) to prevent XSS:

$sanitizer = (new CommonBuilder())
    ->allowTags('p', 'b', 'i', 'a')
    ->allowAttributes('a')->addValues('href')->withRegex('#^https?://#')
    ->build();

$userInput = '<p>Hello <b>World</b>! <a href="javascript:alert(1)">Click</a></p>';
echo $sanitizer->sanitize($userInput);
// Output: <p>Hello <b>World</b>! <a>Click</a></p>

Key Starting Points

  • CommonBuilder: Predefined safe HTML rules (good for quick starts).
  • Sanitizer: Core class for sanitizing HTML.
  • Behavior: Define custom rules for tags, attributes, and values.

Implementation Patterns

Common Workflows

1. Custom Sanitizer Configuration

Define a sanitizer for a blog platform allowing only specific tags/attributes:

use TYPO3\HtmlSanitizer\Behavior;
use TYPO3\HtmlSanitizer\Visitor\CommonVisitor;

$behavior = (new Behavior())
    ->withTags(
        (new Behavior\Tag('h1'))->allowChildren(),
        (new Behavior\Tag('p'))->allowChildren(),
        (new Behavior\Tag('a', Behavior\Tag::ALLOW_CHILDREN))
            ->addAttrs(
                (new Behavior\Attr('href'))
                    ->addValues(new Behavior\RegExpAttrValue('#^https?://#'))
            )
    );

$sanitizer = new Sanitizer($behavior, new CommonVisitor($behavior));

2. Dynamic Rule Adjustments

Extend rules based on user roles (e.g., admins get more tags):

$adminBehavior = $baseBehavior->withTags(
    (new Behavior\Tag('img'))
        ->addAttrs(
            (new Behavior\Attr('src'))->addValues(new Behavior\RegExpAttrValue('#^https?://#')),
            (new Behavior\Attr('alt'))
        )
);

3. Custom Node Handlers

Transform or replace specific nodes (e.g., convert <typo3> tags to text):

$behavior->withNodes(
    new Behavior\NodeHandler(
        new Behavior\Tag('typo3'),
        new Behavior\Handler\ClosureHandler(
            fn($node, $domNode) => new DOMText('[' . $domNode->textContent . ']')
        )
    )
);

4. Reusing Builders

Create reusable builders for different contexts (e.g., CommentBuilder, RichTextBuilder):

class CommentBuilder implements BuilderInterface {
    public function build(): Sanitizer {
        $behavior = (new Behavior())
            ->withTags(
                (new Behavior\Tag('p'))->allowChildren(),
                (new Behavior\Tag('b'))->allowChildren(),
                (new Behavior\Tag('i'))->allowChildren()
            );
        return new Sanitizer($behavior, new CommonVisitor($behavior));
    }
}

5. Integration with Laravel

Store sanitized HTML in the database or cache:

// In a Laravel controller
public function store(Request $request) {
    $sanitizer = app()->make(Sanitizer::class);
    $cleanHtml = $sanitizer->sanitize($request->input('content'));
    // Save $cleanHtml to DB
}

Integration Tips

Laravel Service Provider

Register the sanitizer as a singleton:

// app/Providers/AppServiceProvider.php
public function register() {
    $this->app->singleton(Sanitizer::class, function() {
        return (new CommonBuilder())->build();
    });
}

Form Request Validation

Extend Laravel validation to sanitize inputs:

// app/Http/Requests/SanitizeRequest.php
public function passedValidation() {
    $sanitizer = app(Sanitizer::class);
    $this->merge([
        'content' => $sanitizer->sanitize($this->content),
    ]);
}

Blade Directives

Create a Blade directive for sanitized output:

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

Usage:

{{-- In a Blade template --}}
<div>@sanitize($userInput)</div>

Gotchas and Tips

Pitfalls

1. Immutable Behavior

  • Behavior objects are immutable. Always chain methods (e.g., withTags()) to create new instances:
    // Wrong: Modifies nothing
    $behavior->withTags(new Behavior\Tag('div'));
    
    // Correct: Creates a new instance
    $behavior = $behavior->withTags(new Behavior\Tag('div'));
    

2. Attribute Value Validation

  • Regex validation can be strict. Ensure patterns match expected values:
    // Allows only HTTP/HTTPS URLs
    $hrefAttr = (new Behavior\Attr('href'))
        ->addValues(new Behavior\RegExpAttrValue('#^https?://#'));
    

3. Custom Elements

  • Disabling ALLOW_CUSTOM_ELEMENTS (default: false) blocks tags like <my-custom>:
    $behavior->withFlags(Behavior::ALLOW_CUSTOM_ELEMENTS);
    

4. Encoding Invalid Nodes

  • Flags like ENCODE_INVALID_TAG convert unsafe tags to HTML entities (e.g., <script>&lt;script&gt;). Test this behavior with your use case.

5. DOM Node Ownership

  • When using custom handlers, ensure DOMNode objects are from the same document to avoid errors:
    $newNode = new DOMText($domNode->textContent);
    $domNode->parentNode->replaceChild($newNode, $domNode);
    

Debugging Tips

1. Log Sanitized Output

  • Compare input vs. output to identify unexpected removals:
    $dirtyHtml = '<div>Test <script>alert(1)</script></div>';
    $cleanHtml = $sanitizer->sanitize($dirtyHtml);
    \Log::debug("Input: $dirtyHtml");
    \Log::debug("Output: $cleanHtml");
    

2. Test Edge Cases

  • Test with:
    • Empty tags: <div></div>
    • Self-closing tags: <img src="x">
    • Nested invalid tags: <div><script><p>Test</p></script></div>
    • Unicode characters: <div>Café</div>

3. Validate Against XSS Payloads

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->setAttribute('rel', 'nofollow');
            }
        }
    }
    

2. Dynamic Behavior

  • Load behaviors from config (e.g., JSON/YAML):
    $config = json_decode(file_get_contents('config/sanitizer.json'), true);
    $behavior = (new Behavior())
        ->withTags(...array_map(fn($tag) => new Behavior\Tag($tag), $config['tags']));
    

3. Performance Optimization

  • Reuse Sanitizer instances (they are stateless):
    $sanitizer = (new CommonBuilder())->build();
    foreach ($userInputs as $input) {
        $clean = $sanitizer->sanitize($input); // Reuse instance
    }
    

4. Custom Serialization

  • Override default HTML serialization (e.g., for XML output):
    $serializer = new \TYPO3\HtmlSanitizer\Serializer\XmlSerializer();
    $sanitizer = new Sanitizer($behavior, new CommonVisitor($behavior), $serializer
    
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai