26 public $name =
'ExtractStyleBlocks';
35 $this->_tidy =
new csstidy();
38 $this->_enum_attrdef =
new HTMLPurifier_AttrDef_Enum(array(
'first-child',
'link',
'visited',
'active',
'hover',
'focus'));
46 $this->_styleMatches[] = $matches[1];
53 public function preFilter($html, $config, $context) {
54 $tidy = $config->get(
'Filter.ExtractStyleBlocks.TidyImpl');
55 if ($tidy !== null) $this->_tidy = $tidy;
56 $html = preg_replace_callback(
'#<style(?:\s.*)?>(.+)</style>#isU', array($this,
'styleCallback'), $html);
58 $this->_styleMatches = array();
59 $context->register(
'StyleBlocks', $style_blocks);
61 foreach ($style_blocks as &$style) {
62 $style = $this->
cleanCSS($style, $config, $context);
76 public function cleanCSS($css, $config, $context) {
78 $scope = $config->get(
'Filter.ExtractStyleBlocks.Scope');
79 if ($scope !== null) {
80 $scopes = array_map(
'trim', explode(
',', $scope));
86 if (strncmp(
'<!--', $css, 4) === 0) {
87 $css = substr($css, 4);
89 if (strlen($css) > 3 && substr($css, -3) ==
'-->') {
90 $css = substr($css, 0, -3);
93 set_error_handler(
'htmlpurifier_filter_extractstyleblocks_muteerrorhandler');
94 $this->_tidy->parse($css);
95 restore_error_handler();
96 $css_definition = $config->getDefinition(
'CSS');
97 $html_definition = $config->getDefinition(
'HTML');
99 foreach ($this->_tidy->css as $k => $decls) {
101 $new_decls = array();
102 foreach ($decls as $selector => $style) {
103 $selector = trim($selector);
104 if ($selector ===
'')
continue;
167 $selectors = array_map(
'trim', explode(
',', $selector));
168 $new_selectors = array();
169 foreach ($selectors as $sel) {
171 $basic_selectors = preg_split(
'/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
177 for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
178 $x = $basic_selectors[$i];
184 $delim =
' ' . $x .
' ';
188 $components = preg_split(
'/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
191 for ($j = 0, $cc = count($components); $j < $cc; $j ++) {
192 $y = $components[$j];
194 if ($y ===
'*' || isset($html_definition->info[$y = strtolower($y)])) {
208 if ($sdelim ===
'#') {
210 } elseif ($sdelim ===
'.') {
212 } elseif ($sdelim ===
':') {
217 $r = $attrdef->validate($y, $config, $context);
230 if ($nsel === null) {
233 $nsel .= $delim . $nx;
241 if ($nsel !== null) {
242 if (!empty($scopes)) {
243 foreach ($scopes as $s) {
244 $new_selectors[] =
"$s $nsel";
247 $new_selectors[] = $nsel;
251 if (empty($new_selectors))
continue;
252 $selector = implode(
', ', $new_selectors);
253 foreach ($style as
$name => $value) {
254 if (!isset($css_definition->info[
$name])) {
255 unset($style[
$name]);
258 $def = $css_definition->info[
$name];
259 $ret = $def->validate($value, $config, $context);
260 if (
$ret ===
false) unset($style[
$name]);
263 $new_decls[$selector] = $style;
265 $new_css[$k] = $new_decls;
269 $this->_tidy->css = $new_css;
270 $this->_tidy->import = array();
271 $this->_tidy->charset = null;
272 $this->_tidy->namespace = null;
273 $css = $this->_tidy->print->plain();
276 if ($config->get(
'Filter.ExtractStyleBlocks.Escaping')) {
278 array(
'<',
'>',
'&'),
279 array(
'\3C ',
'\3E ',
'\26 '),