From 5070404376d3b4287ce5c6bfae13e888b464742d Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 28 Oct 2016 23:59:52 -0700 Subject: [PATCH] Handle semicolons in strings in CSS correctly. Fixes http://htmlpurifier.org/phorum/read.php?3,7522,8096 Signed-off-by: Edward Z. Yang --- NEWS | 1 + library/HTMLPurifier/AttrDef/CSS.php | 37 ++++++++++++++++++++++++++++------ tests/HTMLPurifier/AttrDef/CSSTest.php | 1 + 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 5e91c63f..39dd522e 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier - Close directory when done in Serializer DefinitionCache (#100) - Deleted some asserts to avoid linters from choking (#97) - Rework Serializer cache behavior to avoid chmod'ing if possible (#32) +- Embedded semicolons in strings in CSS are now handled correctly! 4.8.0, released 2016-07-16 # By default, when a link has a target attribute associated diff --git a/library/HTMLPurifier/AttrDef/CSS.php b/library/HTMLPurifier/AttrDef/CSS.php index 2b977ca3..ad2cb90a 100644 --- a/library/HTMLPurifier/AttrDef/CSS.php +++ b/library/HTMLPurifier/AttrDef/CSS.php @@ -27,13 +27,38 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef $definition = $config->getCSSDefinition(); $allow_duplicates = $config->get("CSS.AllowDuplicates"); - // we're going to break the spec and explode by semicolons. - // This is because semicolon rarely appears in escaped form - // Doing this is generally flaky but fast - // IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI - // for details - $declarations = explode(';', $css); + // According to the CSS2.1 spec, the places where a + // non-delimiting semicolon can appear are in strings + // escape sequences. So here is some dumb hack to + // handle quotes. + $len = strlen($css); + $accum = ""; + $declarations = array(); + $quoted = false; + for ($i = 0; $i < $len; $i++) { + $c = strcspn($css, ";'\"", $i); + $accum .= substr($css, $i, $c); + $i += $c; + if ($i == $len) break; + $d = $css[$i]; + if ($quoted) { + $accum .= $d; + if ($d == $quoted) { + $quoted = false; + } + } else { + if ($d == ";") { + $declarations[] = $accum; + $accum = ""; + } else { + $accum .= $d; + $quoted = $d; + } + } + } + if ($accum != "") $declarations[] = $accum; + $propvalues = array(); $new_declarations = ''; diff --git a/tests/HTMLPurifier/AttrDef/CSSTest.php b/tests/HTMLPurifier/AttrDef/CSSTest.php index 3ec19c76..718b5be6 100644 --- a/tests/HTMLPurifier/AttrDef/CSSTest.php +++ b/tests/HTMLPurifier/AttrDef/CSSTest.php @@ -27,6 +27,7 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness $this->assertDef('background-color:rgb(0,0,255);'); $this->assertDef('background-color:transparent;'); $this->assertDef('background:#333 url("chess.png") repeat fixed 50% top;'); + $this->assertDef('background:#333 url("che;ss.png") repeat fixed 50% top;'); $this->assertDef('color:#F00;'); $this->assertDef('border-top-color:#F00;'); $this->assertDef('border-color:#F00 #FF0;'); -- 2.11.4.GIT