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

Purify Laravel Package

stevebauman/purify

Laravel wrapper for HTMLPurifier to sanitize user HTML safely. Clean strings or arrays via the Purify facade, with optional per-call configuration. Publish a config file, tune allowed tags/attributes, and leverage caching for performance.

View on GitHub
Deep Wiki
Context7

Getting Started

To begin using stevebauman/purify in a Laravel project, follow these minimal steps:

  1. Installation:

    composer require stevebauman/purify
    php artisan vendor:publish --provider="Stevebauman\Purify\PurifyServiceProvider"
    

    This installs the package and publishes the default configuration file (config/purify.php).

  2. First Use Case: Clean a user-submitted HTML string to remove malicious content:

    use Stevebauman\Purify\Facades\Purify;
    
    $dirtyHtml = '<script>alert("XSS");</script><p>Hello</p>';
    $cleanHtml = Purify::clean($dirtyHtml); // Returns: '<p>Hello</p>'
    
  3. Key Files to Review:

    • config/purify.php: Default configurations and custom rules.
    • app/Providers/AppServiceProvider.php: Register custom definitions if needed.
    • app/Models/Post.php: Example of using PurifyHtmlOnGet cast for Eloquent models.

Implementation Patterns

Core Workflows

  1. Basic Sanitization: Use Purify::clean($input) for one-off sanitization tasks (e.g., form submissions, API payloads). Example:

    $cleaned = Purify::clean(request('content'));
    
  2. Batch Processing: Sanitize arrays of HTML strings (e.g., bulk imports, comment sections):

    $cleanedComments = Purify::clean($commentsArray);
    
  3. Dynamic Configurations: Override default rules for specific use cases (e.g., admin vs. user-generated content):

    $cleaned = Purify::config(['HTML.Allowed' => 'div,p,a[href]'])->clean($input);
    
  4. Eloquent Integration: Use PurifyHtmlOnGet cast to sanitize HTML on retrieval (recommended for security):

    // Laravel 11+
    protected function casts(): array
    {
        return [
            'content' => PurifyHtmlOnGet::class,
        ];
    }
    
  5. API Responses: Sanitize HTML before returning it in API responses:

    return response()->json(['content' => Purify::clean($model->content)]);
    

Integration Tips

  1. Form Requests: Extend FormRequest to auto-sanitize inputs:

    public function rules()
    {
        return [
            'content' => 'required|string',
        ];
    }
    
    public function passedValidation()
    {
        $this->merge([
            'content' => Purify::clean($this->content),
        ]);
        return parent::passedValidation();
    }
    
  2. Middleware: Sanitize HTML in middleware for global protection:

    public function handle($request, Closure $next)
    {
        $request->merge([
            'content' => Purify::clean($request->content),
        ]);
        return $next($request);
    }
    
  3. Livewire/Alpine: Sanitize user-generated content in frontend interactions:

    // Alpine.js
    document.addEventListener('alpine:init', () => {
        Alpine.data('editor', () => ({
            content: '',
            sanitize() {
                this.content = await axios.post('/sanitize', { html: this.content });
            }
        }));
    });
    
  4. Queue Jobs: Defer sanitization to background jobs for performance:

    SanitizeJob::dispatch($userInput)->onQueue('purify');
    

Gotchas and Tips

Pitfalls

  1. Cache Invalidation: Forgetting to run php artisan purify:clear after updating definitions or configs causes stale rules to persist.

    • Fix: Clear cache manually or automate with purify:clear in a post-update hook.
  2. Overly Permissive Rules: Allowing unrestricted attributes (e.g., a[*]) can reintroduce XSS risks.

    • Fix: Explicitly whitelist attributes:
      'HTML.Allowed' => 'a[href|title|rel]',
      
  3. CSS Property Gaps: Default CSS definitions may lack modern values (e.g., text-align: start/end).

    • Fix: Extend with a custom CssDefinition:
      $definition->info['text-align'] = new \HTMLPurifier_AttrDef_Enum(
          ['start', 'end', 'left', 'right', 'center'],
          false
      );
      
  4. Nested Configurations: Dynamic configs override all settings, not merge them.

    • Fix: Prefer named configs in config/purify.php for reuse:
      'configs' => [
          'comments' => ['HTML.Allowed' => 'p,b,i,a[href]'],
      ],
      // Usage:
      Purify::config('comments')->clean($input);
      
  5. Performance Spikes: Disabling caching (serializer: null) causes slowdowns in production.

    • Fix: Use a dedicated cache driver/disk for Purify:
      'serializer' => storage_path('app/purify-cache'),
      

Debugging Tips

  1. Inspect Purified Output: Log the cleaned HTML to verify rules:

    \Log::debug('Cleaned HTML:', ['output' => Purify::clean($input)]);
    
  2. Validate Configs: Use HTMLPurifier’s live config doc to test rules: http://htmlpurifier.org/live/configdoc/plain.html

  3. Check Definitions: For custom elements/attributes, validate against the HTMLPurifier schema.

  4. Error Handling: Wrap Purify::clean() in a try-catch to handle malformed HTML:

    try {
        $cleaned = Purify::clean($input);
    } catch (\HTMLPurifier_Exception $e) {
        \Log::error('Purify error:', ['input' => $input, 'error' => $e->getMessage()]);
        $cleaned = ''; // Fallback
    }
    

Extension Points

  1. Custom Definitions: Extend Html5Definition for modern elements (e.g., <dialog>, <slot>):

    class ExtendedHtml5Definition implements Definition {
        public static function apply($definition) {
            Html5Definition::apply($definition);
            $definition->addElement('dialog', 'Block', 'Flow', 'Common');
        }
    }
    
  2. Attribute Whitelisting: Dynamically allow attributes based on context:

    $config = [
        'HTML.AllowedAttributes' => [
            'a' => ['href', 'title', 'rel', 'data-track' => true],
        ],
    ];
    Purify::config($config)->clean($input);
    
  3. URI Filtering: Restrict allowed URLs (e.g., block external links):

    'URI.AllowedSchemes' => ['http', 'https', 'mailto'],
    
  4. Image Sanitization: Validate image sources (e.g., allow only CDN-hosted images):

    'URI.Image' => [
        'schemes' => ['https'],
        'hosts' => ['cdn.example.com'],
    ],
    
  5. Event Hooks: Listen to purify.cleaning events to log or modify inputs:

    Purify::cleaning(function ($input, $config) {
        \Log::debug('Sanitizing input', ['input' => $input, 'config' => $config]);
    });
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport