stevebauman/purify

Registered elements / transforms do not work on first invocation

Closed this issue · 2 comments

A difficult one to explain, but I'm trying to set up Purify to "allow" <u> tags, and transform them into <span style="text-decoration: underline">.

After I've done what I think is required, it works, but not on the first call to Purify::clean() in a given PHP request cycle, e.g.

$ tinker
Psy Shell v0.9.3 (PHP 7.1.16 — cli) by Justin Hileman
>>> Purify::clean('<u>Foo</u>');
PHP Warning:  Element 'u' is not supported (for information on implementing this, see the support forums)  in /private/tmp/purify-test/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php on line 311
>>> Purify::clean('<u>Foo</u>');
=> "<span style="text-decoration:underline;">Foo</span>"

Whereas I'd expect:

$ tinker
Psy Shell v0.9.3 (PHP 7.1.16 — cli) by Justin Hileman
>>> Purify::clean('<u>Foo</u>');
=> "<span style="text-decoration:underline;">Foo</span>"
>>> Purify::clean('<u>Foo</u>');
=> "<span style="text-decoration:underline;">Foo</span>"

Steps to reproduce:

  • laravel new test-project
  • cd test-project
  • composer require stevebauman/purify
  • php artisan vendor:publish --provider="Stevebauman\Purify\PurifyServiceProvider"
  • Edit config/purify.php and add "u" to HTML.Allowed
  • Create app/Providers/PurifyServiceProvider.php as per https://gist.github.com/leewillis77/6c1fe0ad5448b1fae6b5412a2ee02502
  • Edit config/app.php and add App\Providers\PurifyServiceProvider::class to the list of providers
  • Clear the purify cache (rm -fr storage/purify/)
  • Try Purify::clean('<u>Foo</u>'); in a tinker session

[Sidenote, I'd be happy if I could get it just to allow as an alternative, but the same issue happens with that]

A bit late but I thought I'd add my solution.

Add the element to the definition

if ($def = $config->maybeGetRawHTMLDefinition()) {
    $def->addElement('u', 'Inline', 'Inline', 'Common');
    $def->info_tag_transform['u'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration: underline;');
}

I really had a hard time getting this to work, but I finally tracked it down. The issue is the "tidy" functionality. <u> (and in my case, <s>) is being "fixed" into a styled span, even if you're trying to manually allow the tag (link to source).

Using the example service provider, this is what's in my setupDefinitions:

$underline = $def->addElement('u', 'Inline', 'Inline', 'Common');
$underline->formatting = true;

$strike = $def->addElement('s', 'Inline', 'Inline', 'Common');
$strike->formatting = true;

And this is the key step:

config/purify.php


<?php

return [
    ...

    'HTML.TidyLevel' => 'none',

    ...
];

If you don't disable Tidy, those tags will never work, since they're getting cleaned regardless of what your definition is.