Skip to content

Commit

Permalink
Filters: escapeHtmlTag & escapeXmlTag escapes spaces using entities i…
Browse files Browse the repository at this point in the history
…nstead of adding quotes (BC break)
  • Loading branch information
dg committed Aug 8, 2023
1 parent e8a2d00 commit 7fe1ad4
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 34 deletions.
19 changes: 12 additions & 7 deletions src/Latte/Runtime/Filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ public static function escapeHtmlAttr($s, bool $double = true): string
public static function escapeHtmlTag($s): string
{
$s = (string) $s;
return preg_match('#^[a-z0-9:-]+$#i', $s)
? $s
: '"' . self::escapeHtmlAttr($s) . '"';
$s = htmlspecialchars($s, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8');
return preg_replace_callback(
'#[=/\s]#',
fn($m) => '&#' . ord($m[0]) . ';',
$s,
);
}


Expand Down Expand Up @@ -122,10 +125,12 @@ public static function escapeXml($s): string
*/
public static function escapeXmlTag($s): string
{
$s = (string) $s;
return preg_match('#^[a-z0-9:-]+$#i', $s)
? $s
: '"' . self::escapeXml($s) . '"';
$s = self::escapeXml((string) $s);
return preg_replace_callback(
'#[=/\s]#',
fn($m) => '&#' . ord($m[0]) . ';',
$s,
);
}


Expand Down
2 changes: 1 addition & 1 deletion tests/common/Compiler.unquoted.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ $template = <<<'EOD'
<span onclick=c{$x}d></span>
<span attr{$x}b=c{$x}d></span> {* not supported *}
<span attr{$x}b=c{$x}d></span>

EOD;

Expand Down
6 changes: 3 additions & 3 deletions tests/common/expected/Compiler.unquoted.attrs.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<span title="&apos; &amp; &quot;" class="&apos; &amp; &quot;"></span>

<span title="&apos; &amp; &quot;" "&apos; &amp; &quot;"></span>
<span title="&apos; &amp; &quot;" &apos;&#32;&amp;&#32;&quot;></span>

<span title="&apos; &amp; &quot;"></span>

<span title="&apos; &amp; &quot;"></span>

<span attr="c&apos; &amp; &quot;d"></span>

<span onclick="&quot;&apos; &amp; \&quot;&quot;" "&apos; &amp; &quot;"></span>
<span onclick="&quot;&apos; &amp; \&quot;&quot;" &apos;&#32;&amp;&#32;&quot;></span>

<span onclick="c&quot;&apos; &amp; \&quot;&quot;d"></span>

<span attr"&apos; &amp; &quot;"b="c&apos; &amp; &quot;d"></span>
<span attr&apos;&#32;&amp;&#32;&quot;b="c&apos; &amp; &quot;d"></span>
20 changes: 8 additions & 12 deletions tests/filters/escapeHtmlTag.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,15 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';


Assert::same('""', Filters::escapeHtmlTag(null));
Assert::same('""', Filters::escapeHtmlTag(''));
Assert::same('', Filters::escapeHtmlTag(null));
Assert::same('', Filters::escapeHtmlTag(''));
Assert::same('1', Filters::escapeHtmlTag(1));
Assert::same('string', Filters::escapeHtmlTag('string'));
Assert::same('N:string-string', Filters::escapeHtmlTag('N:string-string'));
Assert::same('"&lt; &amp; &apos; &quot; &gt;"', Filters::escapeHtmlTag('< & \' " >'));
Assert::same('"&amp;quot;"', Filters::escapeHtmlTag('&quot;'));
Assert::same('"&lt;br&gt;"', Filters::escapeHtmlTag(new Latte\Runtime\Html('<br>')));
Assert::same('"`hello "', Filters::escapeHtmlTag('`hello'));
Assert::same('žluťoučký', Filters::escapeHtmlTag('žluťoučký'));
Assert::same('&lt;&#32;&amp;&#32;&apos;&#32;&quot;&#32;&#61;&#32;&#47;&#32;&gt;', Filters::escapeHtmlTag('< & \' " = / >'));
Assert::same('&amp;quot;', Filters::escapeHtmlTag('&quot;'));
Assert::same('&lt;br&gt;', Filters::escapeHtmlTag(new Latte\Runtime\Html('<br>')));

// invalid UTF-8
Assert::same("\"foo \u{FFFD} bar\"", Filters::escapeHtmlTag("foo \u{D800} bar")); // invalid codepoint high surrogates
Assert::same("\"foo \u{FFFD}&quot; bar\"", Filters::escapeHtmlTag("foo \xE3\x80\x22 bar")); // stripped UTF

// JS
Assert::same('"hello &#123; worlds }"', Filters::escapeHtmlTag('hello { worlds }'));
Assert::same("foo&#32;\u{FFFD}&#32;bar", Filters::escapeHtmlTag("foo \u{D800} bar")); // invalid codepoint high surrogates
Assert::same("foo&#32;\u{FFFD}&quot;&#32;bar", Filters::escapeHtmlTag("foo \xE3\x80\x22 bar")); // stripped UTF
22 changes: 12 additions & 10 deletions tests/filters/escapeXmlTag.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';


Assert::same('""', Filters::escapeXmlTag(null));
Assert::same('""', Filters::escapeXmlTag(''));
Assert::same('', Filters::escapeXmlTag(null));
Assert::same('', Filters::escapeXmlTag(''));
Assert::same('1', Filters::escapeXmlTag(1));
Assert::same('string', Filters::escapeXmlTag('string'));
Assert::same('N:string-string', Filters::escapeXmlTag('N:string-string'));
Assert::same('"&lt; &amp; &apos; &quot; &gt;"', Filters::escapeXmlTag('< & \' " >'));
Assert::same('"&lt;br&gt;"', Filters::escapeXmlTag(new Latte\Runtime\Html('<br>')));
Assert::same('"`hello"', Filters::escapeXmlTag('`hello'));
Assert::same('žluťoučký', Filters::escapeXmlTag('žluťoučký'));
Assert::same('&lt;&#32;&amp;&#32;&apos;&#32;&quot;&#32;&#61;&#32;&#47;&#32;&gt;', Filters::escapeXmlTag('< & \' " = / >'));
Assert::same('&amp;quot;', Filters::escapeXmlTag('&quot;'));
Assert::same('&lt;br&gt;', Filters::escapeXmlTag(new Latte\Runtime\Html('<br>')));

// control characters
Assert::same(
"\"\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\x09\x0a\u{FFFD}\u{FFFD}\x0d\u{FFFD}\u{FFFD}\"",
"\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}&#9;&#10;\u{FFFD}\u{FFFD}&#13;\u{FFFD}\u{FFFD}",
Filters::escapeXmlTag("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
);
Assert::same(
"\"\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\"",
"\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}",
Filters::escapeXmlTag("\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"),
);

// invalid UTF-8
Assert::same("\"foo \u{FFFD} bar\"", Filters::escapeXmlTag("foo \u{D800} bar")); // invalid codepoint high surrogates
Assert::same("\"foo \u{FFFD}&quot; bar\"", Filters::escapeXmlTag("foo \xE3\x80\x22 bar")); // stripped UTF
Assert::same("foo&#32;\u{FFFD}&#32;bar", Filters::escapeXmlTag("foo \u{D800} bar")); // invalid codepoint high surrogates
Assert::same("foo&#32;\u{FFFD}&quot;&#32;bar", Filters::escapeXmlTag("foo \xE3\x80\x22 bar")); // stripped UTF
2 changes: 1 addition & 1 deletion tests/tags/expected/print.xss.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<p val="some&amp;&lt;&gt;&quot;&apos;/chars" val2="`mxss "> </p>
<p onclick="&quot;some&amp;&lt;&gt;\&quot;&apos;/chars&quot;"> </p>
<p ONCLICK="&quot;some&amp;&lt;&gt;\&quot;&apos;/chars&quot;" "some&amp;&lt;&gt;&quot;&apos;/chars"> </p>
<p ONCLICK="&quot;some&amp;&lt;&gt;\&quot;&apos;/chars&quot;" some&amp;&lt;&gt;&quot;&apos;&#47;chars> </p>

<STYLE type="text/css">
<!--
Expand Down

0 comments on commit 7fe1ad4

Please sign in to comment.