s9e / TextFormatter

Text formatting library that supports BBCode, HTML and other markup via plugins. Handles emoticons, censors words, automatically embeds media and more.
MIT License
233 stars 36 forks source link

BBCode regexp stopped working (phpBB) #222

Closed rxu closed 1 year ago

rxu commented 1 year ago

Is there probably some known library change that would make this construction to stop working (phpBB 3.3.2 & Textformatter 2.7.5 vs phpBB 3.3.10 & Textformatter 2.11.5):

BBCode: [css]{REGEXP=/^[\-\.,;:' #\{\}0-9a-zA-Z]+$/}[/css] HTML replacement: <style type="text/css">{REGEXP}</style>

I'd think it's phpBB issue but couldn't find any related changes in the core so far. Thanks.

JoshyPHP commented 1 year ago

This one is not immediately obvious so it took me a hot minute to figure out. By default, rules are automatically generated to enforce the HTML content model so nesting BBCodes in a certain way would not break the layout. At the root of a document, the library enforces the div element's content model (it allows pretty much anything but meta elements) and since style isn't allowed in div, it is ignored. The library actually goes one step further by figuring out that this BBCode cannot be used anywhere in a text and removes it altogether, but that doesn't matter here.

What you need to do is specifically allow this BBCode at the root of the text, or allow it on a per-BBCode basis.

The specs flip-flopped on where to allow style elements, that's why different versions of the library may generate different results.

$configurator = new s9e\TextFormatter\Configurator;
$configurator->BBCodes->addCustom(
    "[css]{REGEXP=/^[\-\.,;:' #\{\}0-9a-zA-Z]+$/}[/css]",
    new s9e\TextFormatter\Configurator\Items\UnsafeTemplate('<style type="text/css">{REGEXP}</style>')
);

$configurator->rootRules->allowChild('CSS');

extract($configurator->finalize());

$text = '[css]font-size: 3px;[/css]';
$xml  = $parser->parse($text);
$html = $renderer->render($xml);

die("$html\n");
<style type="text/css">font-size: 3px;</style>
rxu commented 1 year ago

Ah, so in phpBB context that requires an extension. Thanks for the explanation.

JoshyPHP commented 1 year ago

Yeah, you can only set the root context in PHP. In theory, you could create a BBCode that creates a new context and manually allow another BBCode that's used to create the style element even if HTML forbids it. The parent BBCode can automatically create the child tag and perform validation, the child tag would not be able to perform validation and should only be used inside of the parent. That's a big hack IMO, and I don't recommend using that kind of constructs.

$configurator = new s9e\TextFormatter\Configurator;

$configurator->BBCodes->addCustom(
    "[css #allowChild=STYLE #createChild=STYLE #isTransparent=false]{REGEXP=/^[\-\.,;:' #\{\}0-9a-zA-Z]+$/}[/css]",
    '<xsl:apply-templates/>'
);
$configurator->BBCodes->addCustom(
    "[style #requireParent=CSS]{TEXT}[/style]",
    new s9e\TextFormatter\Configurator\Items\UnsafeTemplate('<style type="text/css"><xsl:apply-templates/></style>')
);

extract($configurator->finalize());

$text = '[css]display:none[/css]';
$xml  = $parser->parse($text);
$html = $renderer->render($xml);

die("$html\n");
<style type="text/css">display:none</style>