|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00017 class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter 00018 { 00019 00020 public $name = 'ExtractStyleBlocks'; 00021 private $_styleMatches = array(); 00022 private $_tidy; 00023 00024 public function __construct() { 00025 $this->_tidy = new csstidy(); 00026 } 00027 00032 protected function styleCallback($matches) { 00033 $this->_styleMatches[] = $matches[1]; 00034 } 00035 00040 public function preFilter($html, $config, $context) { 00041 $tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl'); 00042 if ($tidy !== null) $this->_tidy = $tidy; 00043 $html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html); 00044 $style_blocks = $this->_styleMatches; 00045 $this->_styleMatches = array(); // reset 00046 $context->register('StyleBlocks', $style_blocks); // $context must not be reused 00047 if ($this->_tidy) { 00048 foreach ($style_blocks as &$style) { 00049 $style = $this->cleanCSS($style, $config, $context); 00050 } 00051 } 00052 return $html; 00053 } 00054 00063 public function cleanCSS($css, $config, $context) { 00064 // prepare scope 00065 $scope = $config->get('Filter.ExtractStyleBlocks.Scope'); 00066 if ($scope !== null) { 00067 $scopes = array_map('trim', explode(',', $scope)); 00068 } else { 00069 $scopes = array(); 00070 } 00071 // remove comments from CSS 00072 $css = trim($css); 00073 if (strncmp('<!--', $css, 4) === 0) { 00074 $css = substr($css, 4); 00075 } 00076 if (strlen($css) > 3 && substr($css, -3) == '-->') { 00077 $css = substr($css, 0, -3); 00078 } 00079 $css = trim($css); 00080 $this->_tidy->parse($css); 00081 $css_definition = $config->getDefinition('CSS'); 00082 foreach ($this->_tidy->css as $k => $decls) { 00083 // $decls are all CSS declarations inside an @ selector 00084 $new_decls = array(); 00085 foreach ($decls as $selector => $style) { 00086 $selector = trim($selector); 00087 if ($selector === '') continue; // should not happen 00088 if ($selector[0] === '+') { 00089 if ($selector !== '' && $selector[0] === '+') continue; 00090 } 00091 if (!empty($scopes)) { 00092 $new_selector = array(); // because multiple ones are possible 00093 $selectors = array_map('trim', explode(',', $selector)); 00094 foreach ($scopes as $s1) { 00095 foreach ($selectors as $s2) { 00096 $new_selector[] = "$s1 $s2"; 00097 } 00098 } 00099 $selector = implode(', ', $new_selector); // now it's a string 00100 } 00101 foreach ($style as $name => $value) { 00102 if (!isset($css_definition->info[$name])) { 00103 unset($style[$name]); 00104 continue; 00105 } 00106 $def = $css_definition->info[$name]; 00107 $ret = $def->validate($value, $config, $context); 00108 if ($ret === false) unset($style[$name]); 00109 else $style[$name] = $ret; 00110 } 00111 $new_decls[$selector] = $style; 00112 } 00113 $this->_tidy->css[$k] = $new_decls; 00114 } 00115 // remove stuff that shouldn't be used, could be reenabled 00116 // after security risks are analyzed 00117 $this->_tidy->import = array(); 00118 $this->_tidy->charset = null; 00119 $this->_tidy->namespace = null; 00120 $css = $this->_tidy->print->plain(); 00121 // we are going to escape any special characters <>& to ensure 00122 // that no funny business occurs (i.e. </style> in a font-family prop). 00123 if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { 00124 $css = str_replace( 00125 array('<', '>', '&'), 00126 array('\3C ', '\3E ', '\26 '), 00127 $css 00128 ); 00129 } 00130 return $css; 00131 } 00132 00133 } 00134 00135 // vim: et sw=4 sts=4