30 public $name =
'ExtractStyleBlocks';
35 private $_styleMatches = array();
50 private $_class_attrdef;
55 private $_enum_attrdef;
59 $this->_tidy =
new csstidy();
60 $this->_tidy->set_cfg(
'lowercase_s',
false);
81 $this->_styleMatches[] = $matches[1];
94 $tidy =
$config->get(
'Filter.ExtractStyleBlocks.TidyImpl');
101 $html = preg_replace_callback(
'#<style(?:\s.*)?>(.*)<\/style>#isU', array($this,
'styleCallback'),
$html);
102 $style_blocks = $this->_styleMatches;
103 $this->_styleMatches = array();
104 $context->register(
'StyleBlocks', $style_blocks);
106 foreach ($style_blocks
as &$style) {
125 $scope =
$config->get(
'Filter.ExtractStyleBlocks.Scope');
126 if ($scope !==
null) {
127 $scopes = array_map(
'trim', explode(
',', $scope));
133 if (strncmp(
'<!--', $css, 4) === 0) {
134 $css = substr($css, 4);
136 if (strlen($css) > 3 && substr($css, -3) ==
'-->') {
137 $css = substr($css, 0, -3);
140 set_error_handler(
'htmlpurifier_filter_extractstyleblocks_muteerrorhandler');
141 $this->_tidy->parse($css);
142 restore_error_handler();
143 $css_definition =
$config->getDefinition(
'CSS');
144 $html_definition =
$config->getDefinition(
'HTML');
146 foreach ($this->_tidy->css
as $k => $decls) {
148 $new_decls = array();
149 foreach ($decls
as $selector => $style) {
150 $selector = trim($selector);
151 if ($selector ===
'') {
216 $selectors = array_map(
'trim', explode(
',', $selector));
217 $new_selectors = array();
218 foreach ($selectors
as $sel) {
220 $basic_selectors = preg_split(
'/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
226 for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
227 $x = $basic_selectors[$i];
233 $delim =
' ' . $x .
' ';
237 $components = preg_split(
'/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
240 for ($j = 0, $cc = count($components); $j < $cc; $j++) {
241 $y = $components[$j];
243 if ($y ===
'*' || isset($html_definition->info[$y = strtolower($y)])) {
257 if ($sdelim ===
'#') {
258 $attrdef = $this->_id_attrdef;
259 } elseif ($sdelim ===
'.') {
260 $attrdef = $this->_class_attrdef;
261 } elseif ($sdelim ===
':') {
262 $attrdef = $this->_enum_attrdef;
266 $r = $attrdef->validate($y,
$config, $context);
279 if ($nsel ===
null) {
282 $nsel .= $delim . $nx;
290 if ($nsel !==
null) {
291 if (!
empty($scopes)) {
292 foreach ($scopes
as $s) {
293 $new_selectors[] =
"$s $nsel";
296 $new_selectors[] = $nsel;
300 if (
empty($new_selectors)) {
303 $selector = implode(
', ', $new_selectors);
304 foreach ($style
as $name => $value) {
305 if (!isset($css_definition->info[
$name])) {
306 unset($style[
$name]);
311 if (
$ret ===
false) {
312 unset($style[
$name]);
317 $new_decls[$selector] = $style;
319 $new_css[$k] = $new_decls;
323 $this->_tidy->css = $new_css;
324 $this->_tidy->import = array();
325 $this->_tidy->charset =
null;
326 $this->_tidy->namespace =
null;
327 $css = $this->_tidy->print->plain();
330 if (
$config->get(
'Filter.ExtractStyleBlocks.Escaping')) {
332 array(
'<',
'>',
'&'),
333 array(
'\3C ',
'\3E ',
'\26 '),