commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / IDS / vendors / htmlpurifier / HTMLPurifier / Filter / ExtractStyleBlocks.php
1 <?php
2
3 /**
4 * This filter extracts <style> blocks from input HTML, cleans them up
5 * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks')
6 * so they can be used elsewhere in the document.
7 *
8 * @note
9 * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for
10 * sample usage.
11 *
12 * @note
13 * This filter can also be used on stylesheets not included in the
14 * document--something purists would probably prefer. Just directly
15 * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS()
16 */
17 class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
18 {
19
20 public $name = 'ExtractStyleBlocks';
21 private $_styleMatches = array();
22 private $_tidy;
23
24 public function __construct() {
25 $this->_tidy = new csstidy();
26 }
27
28 /**
29 * Save the contents of CSS blocks to style matches
30 * @param $matches preg_replace style $matches array
31 */
32 protected function styleCallback($matches) {
33 $this->_styleMatches[] = $matches[1];
34 }
35
36 /**
37 * Removes inline <style> tags from HTML, saves them for later use
38 * @todo Extend to indicate non-text/css style blocks
39 */
40 public function preFilter($html, $config, $context) {
41 $tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl');
42 if ($tidy !== null) $this->_tidy = $tidy;
43 $html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html);
44 $style_blocks = $this->_styleMatches;
45 $this->_styleMatches = array(); // reset
46 $context->register('StyleBlocks', $style_blocks); // $context must not be reused
47 if ($this->_tidy) {
48 foreach ($style_blocks as &$style) {
49 $style = $this->cleanCSS($style, $config, $context);
50 }
51 }
52 return $html;
53 }
54
55 /**
56 * Takes CSS (the stuff found in <style>) and cleans it.
57 * @warning Requires CSSTidy <http://csstidy.sourceforge.net/>
58 * @param $css CSS styling to clean
59 * @param $config Instance of HTMLPurifier_Config
60 * @param $context Instance of HTMLPurifier_Context
61 * @return Cleaned CSS
62 */
63 public function cleanCSS($css, $config, $context) {
64 // prepare scope
65 $scope = $config->get('Filter.ExtractStyleBlocks.Scope');
66 if ($scope !== null) {
67 $scopes = array_map('trim', explode(',', $scope));
68 } else {
69 $scopes = array();
70 }
71 // remove comments from CSS
72 $css = trim($css);
73 if (strncmp('<!--', $css, 4) === 0) {
74 $css = substr($css, 4);
75 }
76 if (strlen($css) > 3 && substr($css, -3) == '-->') {
77 $css = substr($css, 0, -3);
78 }
79 $css = trim($css);
80 $this->_tidy->parse($css);
81 $css_definition = $config->getDefinition('CSS');
82 foreach ($this->_tidy->css as $k => $decls) {
83 // $decls are all CSS declarations inside an @ selector
84 $new_decls = array();
85 foreach ($decls as $selector => $style) {
86 $selector = trim($selector);
87 if ($selector === '') continue; // should not happen
88 if ($selector[0] === '+') {
89 if ($selector !== '' && $selector[0] === '+') continue;
90 }
91 if (!empty($scopes)) {
92 $new_selector = array(); // because multiple ones are possible
93 $selectors = array_map('trim', explode(',', $selector));
94 foreach ($scopes as $s1) {
95 foreach ($selectors as $s2) {
96 $new_selector[] = "$s1 $s2";
97 }
98 }
99 $selector = implode(', ', $new_selector); // now it's a string
100 }
101 foreach ($style as $name => $value) {
102 if (!isset($css_definition->info[$name])) {
103 unset($style[$name]);
104 continue;
105 }
106 $def = $css_definition->info[$name];
107 $ret = $def->validate($value, $config, $context);
108 if ($ret === false) unset($style[$name]);
109 else $style[$name] = $ret;
110 }
111 $new_decls[$selector] = $style;
112 }
113 $this->_tidy->css[$k] = $new_decls;
114 }
115 // remove stuff that shouldn't be used, could be reenabled
116 // after security risks are analyzed
117 $this->_tidy->import = array();
118 $this->_tidy->charset = null;
119 $this->_tidy->namespace = null;
120 $css = $this->_tidy->print->plain();
121 // we are going to escape any special characters <>& to ensure
122 // that no funny business occurs (i.e. </style> in a font-family prop).
123 if ($config->get('Filter.ExtractStyleBlocks.Escaping')) {
124 $css = str_replace(
125 array('<', '>', '&'),
126 array('\3C ', '\3E ', '\26 '),
127 $css
128 );
129 }
130 return $css;
131 }
132
133 }
134
135 // vim: et sw=4 sts=4