aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas@loeuillet.org>2014-02-21 15:57:10 +0100
committerNicolas Lœuillet <nicolas@loeuillet.org>2014-02-21 15:57:10 +0100
commit99679d06884120c57f43b44e55e03595f1f87bed (patch)
treea3f2a1aa1afdaeca1386d0c6e8a75344fd2241fb /inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS
parent655214ab30ee84884dc408488b85586f36263fcb (diff)
parentd3b47e94705e17b3ba3529cbb1dc6efe69c5d2b7 (diff)
downloadwallabag-99679d06884120c57f43b44e55e03595f1f87bed.tar.gz
wallabag-99679d06884120c57f43b44e55e03595f1f87bed.tar.zst
wallabag-99679d06884120c57f43b44e55e03595f1f87bed.zip
Merge pull request #481 from wallabag/dev1.5.2
1.5.2
Diffstat (limited to 'inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS')
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php34
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php111
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php157
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php56
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php105
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php48
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php44
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php77
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php176
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php219
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php32
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php56
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php77
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php112
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php71
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php84
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php54
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php46
-rw-r--r--inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php74
19 files changed, 1633 insertions, 0 deletions
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php
new file mode 100644
index 00000000..1a30e8fe
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php
@@ -0,0 +1,34 @@
1<?php
2
3class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
4{
5
6 public function __construct()
7 {
8 parent::__construct(false); // opacity is non-negative, but we will clamp it
9 }
10
11 /**
12 * @param string $number
13 * @param HTMLPurifier_Config $config
14 * @param HTMLPurifier_Context $context
15 * @return string
16 */
17 public function validate($number, $config, $context)
18 {
19 $result = parent::validate($number, $config, $context);
20 if ($result === false) {
21 return $result;
22 }
23 $float = (float)$result;
24 if ($float < 0.0) {
25 $result = '0';
26 }
27 if ($float > 1.0) {
28 $result = '1';
29 }
30 return $result;
31 }
32}
33
34// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php
new file mode 100644
index 00000000..ecd6e276
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php
@@ -0,0 +1,111 @@
1<?php
2
3/**
4 * Validates shorthand CSS property background.
5 * @warning Does not support url tokens that have internal spaces.
6 */
7class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
8{
9
10 /**
11 * Local copy of component validators.
12 * @type HTMLPurifier_AttrDef[]
13 * @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
14 */
15 protected $info;
16
17 /**
18 * @param HTMLPurifier_Config $config
19 */
20 public function __construct($config)
21 {
22 $def = $config->getCSSDefinition();
23 $this->info['background-color'] = $def->info['background-color'];
24 $this->info['background-image'] = $def->info['background-image'];
25 $this->info['background-repeat'] = $def->info['background-repeat'];
26 $this->info['background-attachment'] = $def->info['background-attachment'];
27 $this->info['background-position'] = $def->info['background-position'];
28 }
29
30 /**
31 * @param string $string
32 * @param HTMLPurifier_Config $config
33 * @param HTMLPurifier_Context $context
34 * @return bool|string
35 */
36 public function validate($string, $config, $context)
37 {
38 // regular pre-processing
39 $string = $this->parseCDATA($string);
40 if ($string === '') {
41 return false;
42 }
43
44 // munge rgb() decl if necessary
45 $string = $this->mungeRgb($string);
46
47 // assumes URI doesn't have spaces in it
48 $bits = explode(' ', $string); // bits to process
49
50 $caught = array();
51 $caught['color'] = false;
52 $caught['image'] = false;
53 $caught['repeat'] = false;
54 $caught['attachment'] = false;
55 $caught['position'] = false;
56
57 $i = 0; // number of catches
58
59 foreach ($bits as $bit) {
60 if ($bit === '') {
61 continue;
62 }
63 foreach ($caught as $key => $status) {
64 if ($key != 'position') {
65 if ($status !== false) {
66 continue;
67 }
68 $r = $this->info['background-' . $key]->validate($bit, $config, $context);
69 } else {
70 $r = $bit;
71 }
72 if ($r === false) {
73 continue;
74 }
75 if ($key == 'position') {
76 if ($caught[$key] === false) {
77 $caught[$key] = '';
78 }
79 $caught[$key] .= $r . ' ';
80 } else {
81 $caught[$key] = $r;
82 }
83 $i++;
84 break;
85 }
86 }
87
88 if (!$i) {
89 return false;
90 }
91 if ($caught['position'] !== false) {
92 $caught['position'] = $this->info['background-position']->
93 validate($caught['position'], $config, $context);
94 }
95
96 $ret = array();
97 foreach ($caught as $value) {
98 if ($value === false) {
99 continue;
100 }
101 $ret[] = $value;
102 }
103
104 if (empty($ret)) {
105 return false;
106 }
107 return implode(' ', $ret);
108 }
109}
110
111// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
new file mode 100644
index 00000000..f95de5bb
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
@@ -0,0 +1,157 @@
1<?php
2
3/* W3C says:
4 [ // adjective and number must be in correct order, even if
5 // you could switch them without introducing ambiguity.
6 // some browsers support that syntax
7 [
8 <percentage> | <length> | left | center | right
9 ]
10 [
11 <percentage> | <length> | top | center | bottom
12 ]?
13 ] |
14 [ // this signifies that the vertical and horizontal adjectives
15 // can be arbitrarily ordered, however, there can only be two,
16 // one of each, or none at all
17 [
18 left | center | right
19 ] ||
20 [
21 top | center | bottom
22 ]
23 ]
24 top, left = 0%
25 center, (none) = 50%
26 bottom, right = 100%
27*/
28
29/* QuirksMode says:
30 keyword + length/percentage must be ordered correctly, as per W3C
31
32 Internet Explorer and Opera, however, support arbitrary ordering. We
33 should fix it up.
34
35 Minor issue though, not strictly necessary.
36*/
37
38// control freaks may appreciate the ability to convert these to
39// percentages or something, but it's not necessary
40
41/**
42 * Validates the value of background-position.
43 */
44class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
45{
46
47 /**
48 * @type HTMLPurifier_AttrDef_CSS_Length
49 */
50 protected $length;
51
52 /**
53 * @type HTMLPurifier_AttrDef_CSS_Percentage
54 */
55 protected $percentage;
56
57 public function __construct()
58 {
59 $this->length = new HTMLPurifier_AttrDef_CSS_Length();
60 $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
61 }
62
63 /**
64 * @param string $string
65 * @param HTMLPurifier_Config $config
66 * @param HTMLPurifier_Context $context
67 * @return bool|string
68 */
69 public function validate($string, $config, $context)
70 {
71 $string = $this->parseCDATA($string);
72 $bits = explode(' ', $string);
73
74 $keywords = array();
75 $keywords['h'] = false; // left, right
76 $keywords['v'] = false; // top, bottom
77 $keywords['ch'] = false; // center (first word)
78 $keywords['cv'] = false; // center (second word)
79 $measures = array();
80
81 $i = 0;
82
83 $lookup = array(
84 'top' => 'v',
85 'bottom' => 'v',
86 'left' => 'h',
87 'right' => 'h',
88 'center' => 'c'
89 );
90
91 foreach ($bits as $bit) {
92 if ($bit === '') {
93 continue;
94 }
95
96 // test for keyword
97 $lbit = ctype_lower($bit) ? $bit : strtolower($bit);
98 if (isset($lookup[$lbit])) {
99 $status = $lookup[$lbit];
100 if ($status == 'c') {
101 if ($i == 0) {
102 $status = 'ch';
103 } else {
104 $status = 'cv';
105 }
106 }
107 $keywords[$status] = $lbit;
108 $i++;
109 }
110
111 // test for length
112 $r = $this->length->validate($bit, $config, $context);
113 if ($r !== false) {
114 $measures[] = $r;
115 $i++;
116 }
117
118 // test for percentage
119 $r = $this->percentage->validate($bit, $config, $context);
120 if ($r !== false) {
121 $measures[] = $r;
122 $i++;
123 }
124 }
125
126 if (!$i) {
127 return false;
128 } // no valid values were caught
129
130 $ret = array();
131
132 // first keyword
133 if ($keywords['h']) {
134 $ret[] = $keywords['h'];
135 } elseif ($keywords['ch']) {
136 $ret[] = $keywords['ch'];
137 $keywords['cv'] = false; // prevent re-use: center = center center
138 } elseif (count($measures)) {
139 $ret[] = array_shift($measures);
140 }
141
142 if ($keywords['v']) {
143 $ret[] = $keywords['v'];
144 } elseif ($keywords['cv']) {
145 $ret[] = $keywords['cv'];
146 } elseif (count($measures)) {
147 $ret[] = array_shift($measures);
148 }
149
150 if (empty($ret)) {
151 return false;
152 }
153 return implode(' ', $ret);
154 }
155}
156
157// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php
new file mode 100644
index 00000000..bd310ff2
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php
@@ -0,0 +1,56 @@
1<?php
2
3/**
4 * Validates the border property as defined by CSS.
5 */
6class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * Local copy of properties this property is shorthand for.
11 * @type HTMLPurifier_AttrDef[]
12 */
13 protected $info = array();
14
15 /**
16 * @param HTMLPurifier_Config $config
17 */
18 public function __construct($config)
19 {
20 $def = $config->getCSSDefinition();
21 $this->info['border-width'] = $def->info['border-width'];
22 $this->info['border-style'] = $def->info['border-style'];
23 $this->info['border-top-color'] = $def->info['border-top-color'];
24 }
25
26 /**
27 * @param string $string
28 * @param HTMLPurifier_Config $config
29 * @param HTMLPurifier_Context $context
30 * @return bool|string
31 */
32 public function validate($string, $config, $context)
33 {
34 $string = $this->parseCDATA($string);
35 $string = $this->mungeRgb($string);
36 $bits = explode(' ', $string);
37 $done = array(); // segments we've finished
38 $ret = ''; // return value
39 foreach ($bits as $bit) {
40 foreach ($this->info as $propname => $validator) {
41 if (isset($done[$propname])) {
42 continue;
43 }
44 $r = $validator->validate($bit, $config, $context);
45 if ($r !== false) {
46 $ret .= $r . ' ';
47 $done[$propname] = true;
48 break;
49 }
50 }
51 }
52 return rtrim($ret);
53 }
54}
55
56// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php
new file mode 100644
index 00000000..e553c65e
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php
@@ -0,0 +1,105 @@
1<?php
2
3/**
4 * Validates Color as defined by CSS.
5 */
6class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * @param string $color
11 * @param HTMLPurifier_Config $config
12 * @param HTMLPurifier_Context $context
13 * @return bool|string
14 */
15 public function validate($color, $config, $context)
16 {
17 static $colors = null;
18 if ($colors === null) {
19 $colors = $config->get('Core.ColorKeywords');
20 }
21
22 $color = trim($color);
23 if ($color === '') {
24 return false;
25 }
26
27 $lower = strtolower($color);
28 if (isset($colors[$lower])) {
29 return $colors[$lower];
30 }
31
32 if (strpos($color, 'rgb(') !== false) {
33 // rgb literal handling
34 $length = strlen($color);
35 if (strpos($color, ')') !== $length - 1) {
36 return false;
37 }
38 $triad = substr($color, 4, $length - 4 - 1);
39 $parts = explode(',', $triad);
40 if (count($parts) !== 3) {
41 return false;
42 }
43 $type = false; // to ensure that they're all the same type
44 $new_parts = array();
45 foreach ($parts as $part) {
46 $part = trim($part);
47 if ($part === '') {
48 return false;
49 }
50 $length = strlen($part);
51 if ($part[$length - 1] === '%') {
52 // handle percents
53 if (!$type) {
54 $type = 'percentage';
55 } elseif ($type !== 'percentage') {
56 return false;
57 }
58 $num = (float)substr($part, 0, $length - 1);
59 if ($num < 0) {
60 $num = 0;
61 }
62 if ($num > 100) {
63 $num = 100;
64 }
65 $new_parts[] = "$num%";
66 } else {
67 // handle integers
68 if (!$type) {
69 $type = 'integer';
70 } elseif ($type !== 'integer') {
71 return false;
72 }
73 $num = (int)$part;
74 if ($num < 0) {
75 $num = 0;
76 }
77 if ($num > 255) {
78 $num = 255;
79 }
80 $new_parts[] = (string)$num;
81 }
82 }
83 $new_triad = implode(',', $new_parts);
84 $color = "rgb($new_triad)";
85 } else {
86 // hexadecimal handling
87 if ($color[0] === '#') {
88 $hex = substr($color, 1);
89 } else {
90 $hex = $color;
91 $color = '#' . $color;
92 }
93 $length = strlen($hex);
94 if ($length !== 3 && $length !== 6) {
95 return false;
96 }
97 if (!ctype_xdigit($hex)) {
98 return false;
99 }
100 }
101 return $color;
102 }
103}
104
105// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php
new file mode 100644
index 00000000..38900232
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php
@@ -0,0 +1,48 @@
1<?php
2
3/**
4 * Allows multiple validators to attempt to validate attribute.
5 *
6 * Composite is just what it sounds like: a composite of many validators.
7 * This means that multiple HTMLPurifier_AttrDef objects will have a whack
8 * at the string. If one of them passes, that's what is returned. This is
9 * especially useful for CSS values, which often are a choice between
10 * an enumerated set of predefined values or a flexible data type.
11 */
12class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
13{
14
15 /**
16 * List of objects that may process strings.
17 * @type HTMLPurifier_AttrDef[]
18 * @todo Make protected
19 */
20 public $defs;
21
22 /**
23 * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects
24 */
25 public function __construct($defs)
26 {
27 $this->defs = $defs;
28 }
29
30 /**
31 * @param string $string
32 * @param HTMLPurifier_Config $config
33 * @param HTMLPurifier_Context $context
34 * @return bool|string
35 */
36 public function validate($string, $config, $context)
37 {
38 foreach ($this->defs as $i => $def) {
39 $result = $this->defs[$i]->validate($string, $config, $context);
40 if ($result !== false) {
41 return $result;
42 }
43 }
44 return false;
45 }
46}
47
48// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
new file mode 100644
index 00000000..ff0d897e
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
@@ -0,0 +1,44 @@
1<?php
2
3/**
4 * Decorator which enables CSS properties to be disabled for specific elements.
5 */
6class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
7{
8 /**
9 * @type HTMLPurifier_AttrDef
10 */
11 public $def;
12 /**
13 * @type string
14 */
15 public $element;
16
17 /**
18 * @param HTMLPurifier_AttrDef $def Definition to wrap
19 * @param string $element Element to deny
20 */
21 public function __construct($def, $element)
22 {
23 $this->def = $def;
24 $this->element = $element;
25 }
26
27 /**
28 * Checks if CurrentToken is set and equal to $this->element
29 * @param string $string
30 * @param HTMLPurifier_Config $config
31 * @param HTMLPurifier_Context $context
32 * @return bool|string
33 */
34 public function validate($string, $config, $context)
35 {
36 $token = $context->get('CurrentToken', true);
37 if ($token && $token->name == $this->element) {
38 return false;
39 }
40 return $this->def->validate($string, $config, $context);
41 }
42}
43
44// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php
new file mode 100644
index 00000000..019722a4
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php
@@ -0,0 +1,77 @@
1<?php
2
3/**
4 * Microsoft's proprietary filter: CSS property
5 * @note Currently supports the alpha filter. In the future, this will
6 * probably need an extensible framework
7 */
8class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
9{
10 /**
11 * @type HTMLPurifier_AttrDef_Integer
12 */
13 protected $intValidator;
14
15 public function __construct()
16 {
17 $this->intValidator = new HTMLPurifier_AttrDef_Integer();
18 }
19
20 /**
21 * @param string $value
22 * @param HTMLPurifier_Config $config
23 * @param HTMLPurifier_Context $context
24 * @return bool|string
25 */
26 public function validate($value, $config, $context)
27 {
28 $value = $this->parseCDATA($value);
29 if ($value === 'none') {
30 return $value;
31 }
32 // if we looped this we could support multiple filters
33 $function_length = strcspn($value, '(');
34 $function = trim(substr($value, 0, $function_length));
35 if ($function !== 'alpha' &&
36 $function !== 'Alpha' &&
37 $function !== 'progid:DXImageTransform.Microsoft.Alpha'
38 ) {
39 return false;
40 }
41 $cursor = $function_length + 1;
42 $parameters_length = strcspn($value, ')', $cursor);
43 $parameters = substr($value, $cursor, $parameters_length);
44 $params = explode(',', $parameters);
45 $ret_params = array();
46 $lookup = array();
47 foreach ($params as $param) {
48 list($key, $value) = explode('=', $param);
49 $key = trim($key);
50 $value = trim($value);
51 if (isset($lookup[$key])) {
52 continue;
53 }
54 if ($key !== 'opacity') {
55 continue;
56 }
57 $value = $this->intValidator->validate($value, $config, $context);
58 if ($value === false) {
59 continue;
60 }
61 $int = (int)$value;
62 if ($int > 100) {
63 $value = '100';
64 }
65 if ($int < 0) {
66 $value = '0';
67 }
68 $ret_params[] = "$key=$value";
69 $lookup[$key] = true;
70 }
71 $ret_parameters = implode(',', $ret_params);
72 $ret_function = "$function($ret_parameters)";
73 return $ret_function;
74 }
75}
76
77// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php
new file mode 100644
index 00000000..b9b63f8e
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php
@@ -0,0 +1,176 @@
1<?php
2
3/**
4 * Validates shorthand CSS property font.
5 */
6class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * Local copy of validators
11 * @type HTMLPurifier_AttrDef[]
12 * @note If we moved specific CSS property definitions to their own
13 * classes instead of having them be assembled at run time by
14 * CSSDefinition, this wouldn't be necessary. We'd instantiate
15 * our own copies.
16 */
17 protected $info = array();
18
19 /**
20 * @param HTMLPurifier_Config $config
21 */
22 public function __construct($config)
23 {
24 $def = $config->getCSSDefinition();
25 $this->info['font-style'] = $def->info['font-style'];
26 $this->info['font-variant'] = $def->info['font-variant'];
27 $this->info['font-weight'] = $def->info['font-weight'];
28 $this->info['font-size'] = $def->info['font-size'];
29 $this->info['line-height'] = $def->info['line-height'];
30 $this->info['font-family'] = $def->info['font-family'];
31 }
32
33 /**
34 * @param string $string
35 * @param HTMLPurifier_Config $config
36 * @param HTMLPurifier_Context $context
37 * @return bool|string
38 */
39 public function validate($string, $config, $context)
40 {
41 static $system_fonts = array(
42 'caption' => true,
43 'icon' => true,
44 'menu' => true,
45 'message-box' => true,
46 'small-caption' => true,
47 'status-bar' => true
48 );
49
50 // regular pre-processing
51 $string = $this->parseCDATA($string);
52 if ($string === '') {
53 return false;
54 }
55
56 // check if it's one of the keywords
57 $lowercase_string = strtolower($string);
58 if (isset($system_fonts[$lowercase_string])) {
59 return $lowercase_string;
60 }
61
62 $bits = explode(' ', $string); // bits to process
63 $stage = 0; // this indicates what we're looking for
64 $caught = array(); // which stage 0 properties have we caught?
65 $stage_1 = array('font-style', 'font-variant', 'font-weight');
66 $final = ''; // output
67
68 for ($i = 0, $size = count($bits); $i < $size; $i++) {
69 if ($bits[$i] === '') {
70 continue;
71 }
72 switch ($stage) {
73 case 0: // attempting to catch font-style, font-variant or font-weight
74 foreach ($stage_1 as $validator_name) {
75 if (isset($caught[$validator_name])) {
76 continue;
77 }
78 $r = $this->info[$validator_name]->validate(
79 $bits[$i],
80 $config,
81 $context
82 );
83 if ($r !== false) {
84 $final .= $r . ' ';
85 $caught[$validator_name] = true;
86 break;
87 }
88 }
89 // all three caught, continue on
90 if (count($caught) >= 3) {
91 $stage = 1;
92 }
93 if ($r !== false) {
94 break;
95 }
96 case 1: // attempting to catch font-size and perhaps line-height
97 $found_slash = false;
98 if (strpos($bits[$i], '/') !== false) {
99 list($font_size, $line_height) =
100 explode('/', $bits[$i]);
101 if ($line_height === '') {
102 // ooh, there's a space after the slash!
103 $line_height = false;
104 $found_slash = true;
105 }
106 } else {
107 $font_size = $bits[$i];
108 $line_height = false;
109 }
110 $r = $this->info['font-size']->validate(
111 $font_size,
112 $config,
113 $context
114 );
115 if ($r !== false) {
116 $final .= $r;
117 // attempt to catch line-height
118 if ($line_height === false) {
119 // we need to scroll forward
120 for ($j = $i + 1; $j < $size; $j++) {
121 if ($bits[$j] === '') {
122 continue;
123 }
124 if ($bits[$j] === '/') {
125 if ($found_slash) {
126 return false;
127 } else {
128 $found_slash = true;
129 continue;
130 }
131 }
132 $line_height = $bits[$j];
133 break;
134 }
135 } else {
136 // slash already found
137 $found_slash = true;
138 $j = $i;
139 }
140 if ($found_slash) {
141 $i = $j;
142 $r = $this->info['line-height']->validate(
143 $line_height,
144 $config,
145 $context
146 );
147 if ($r !== false) {
148 $final .= '/' . $r;
149 }
150 }
151 $final .= ' ';
152 $stage = 2;
153 break;
154 }
155 return false;
156 case 2: // attempting to catch font-family
157 $font_family =
158 implode(' ', array_slice($bits, $i, $size - $i));
159 $r = $this->info['font-family']->validate(
160 $font_family,
161 $config,
162 $context
163 );
164 if ($r !== false) {
165 $final .= $r . ' ';
166 // processing completed successfully
167 return rtrim($final);
168 }
169 return false;
170 }
171 }
172 return false;
173 }
174}
175
176// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php
new file mode 100644
index 00000000..f9af36d7
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php
@@ -0,0 +1,219 @@
1<?php
2
3/**
4 * Validates a font family list according to CSS spec
5 */
6class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
7{
8
9 protected $mask = null;
10
11 public function __construct()
12 {
13 $this->mask = '_- ';
14 for ($c = 'a'; $c <= 'z'; $c++) {
15 $this->mask .= $c;
16 }
17 for ($c = 'A'; $c <= 'Z'; $c++) {
18 $this->mask .= $c;
19 }
20 for ($c = '0'; $c <= '9'; $c++) {
21 $this->mask .= $c;
22 } // cast-y, but should be fine
23 // special bytes used by UTF-8
24 for ($i = 0x80; $i <= 0xFF; $i++) {
25 // We don't bother excluding invalid bytes in this range,
26 // because the our restriction of well-formed UTF-8 will
27 // prevent these from ever occurring.
28 $this->mask .= chr($i);
29 }
30
31 /*
32 PHP's internal strcspn implementation is
33 O(length of string * length of mask), making it inefficient
34 for large masks. However, it's still faster than
35 preg_match 8)
36 for (p = s1;;) {
37 spanp = s2;
38 do {
39 if (*spanp == c || p == s1_end) {
40 return p - s1;
41 }
42 } while (spanp++ < (s2_end - 1));
43 c = *++p;
44 }
45 */
46 // possible optimization: invert the mask.
47 }
48
49 /**
50 * @param string $string
51 * @param HTMLPurifier_Config $config
52 * @param HTMLPurifier_Context $context
53 * @return bool|string
54 */
55 public function validate($string, $config, $context)
56 {
57 static $generic_names = array(
58 'serif' => true,
59 'sans-serif' => true,
60 'monospace' => true,
61 'fantasy' => true,
62 'cursive' => true
63 );
64 $allowed_fonts = $config->get('CSS.AllowedFonts');
65
66 // assume that no font names contain commas in them
67 $fonts = explode(',', $string);
68 $final = '';
69 foreach ($fonts as $font) {
70 $font = trim($font);
71 if ($font === '') {
72 continue;
73 }
74 // match a generic name
75 if (isset($generic_names[$font])) {
76 if ($allowed_fonts === null || isset($allowed_fonts[$font])) {
77 $final .= $font . ', ';
78 }
79 continue;
80 }
81 // match a quoted name
82 if ($font[0] === '"' || $font[0] === "'") {
83 $length = strlen($font);
84 if ($length <= 2) {
85 continue;
86 }
87 $quote = $font[0];
88 if ($font[$length - 1] !== $quote) {
89 continue;
90 }
91 $font = substr($font, 1, $length - 2);
92 }
93
94 $font = $this->expandCSSEscape($font);
95
96 // $font is a pure representation of the font name
97
98 if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) {
99 continue;
100 }
101
102 if (ctype_alnum($font) && $font !== '') {
103 // very simple font, allow it in unharmed
104 $final .= $font . ', ';
105 continue;
106 }
107
108 // bugger out on whitespace. form feed (0C) really
109 // shouldn't show up regardless
110 $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font);
111
112 // Here, there are various classes of characters which need
113 // to be treated differently:
114 // - Alphanumeric characters are essentially safe. We
115 // handled these above.
116 // - Spaces require quoting, though most parsers will do
117 // the right thing if there aren't any characters that
118 // can be misinterpreted
119 // - Dashes rarely occur, but they fairly unproblematic
120 // for parsing/rendering purposes.
121 // The above characters cover the majority of Western font
122 // names.
123 // - Arbitrary Unicode characters not in ASCII. Because
124 // most parsers give little thought to Unicode, treatment
125 // of these codepoints is basically uniform, even for
126 // punctuation-like codepoints. These characters can
127 // show up in non-Western pages and are supported by most
128 // major browsers, for example: "MS 明朝" is a
129 // legitimate font-name
130 // <http://ja.wikipedia.org/wiki/MS_明朝>. See
131 // the CSS3 spec for more examples:
132 // <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png>
133 // You can see live samples of these on the Internet:
134 // <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック>
135 // However, most of these fonts have ASCII equivalents:
136 // for example, 'MS Mincho', and it's considered
137 // professional to use ASCII font names instead of
138 // Unicode font names. Thanks Takeshi Terada for
139 // providing this information.
140 // The following characters, to my knowledge, have not been
141 // used to name font names.
142 // - Single quote. While theoretically you might find a
143 // font name that has a single quote in its name (serving
144 // as an apostrophe, e.g. Dave's Scribble), I haven't
145 // been able to find any actual examples of this.
146 // Internet Explorer's cssText translation (which I
147 // believe is invoked by innerHTML) normalizes any
148 // quoting to single quotes, and fails to escape single
149 // quotes. (Note that this is not IE's behavior for all
150 // CSS properties, just some sort of special casing for
151 // font-family). So a single quote *cannot* be used
152 // safely in the font-family context if there will be an
153 // innerHTML/cssText translation. Note that Firefox 3.x
154 // does this too.
155 // - Double quote. In IE, these get normalized to
156 // single-quotes, no matter what the encoding. (Fun
157 // fact, in IE8, the 'content' CSS property gained
158 // support, where they special cased to preserve encoded
159 // double quotes, but still translate unadorned double
160 // quotes into single quotes.) So, because their
161 // fixpoint behavior is identical to single quotes, they
162 // cannot be allowed either. Firefox 3.x displays
163 // single-quote style behavior.
164 // - Backslashes are reduced by one (so \\ -> \) every
165 // iteration, so they cannot be used safely. This shows
166 // up in IE7, IE8 and FF3
167 // - Semicolons, commas and backticks are handled properly.
168 // - The rest of the ASCII punctuation is handled properly.
169 // We haven't checked what browsers do to unadorned
170 // versions, but this is not important as long as the
171 // browser doesn't /remove/ surrounding quotes (as IE does
172 // for HTML).
173 //
174 // With these results in hand, we conclude that there are
175 // various levels of safety:
176 // - Paranoid: alphanumeric, spaces and dashes(?)
177 // - International: Paranoid + non-ASCII Unicode
178 // - Edgy: Everything except quotes, backslashes
179 // - NoJS: Standards compliance, e.g. sod IE. Note that
180 // with some judicious character escaping (since certain
181 // types of escaping doesn't work) this is theoretically
182 // OK as long as innerHTML/cssText is not called.
183 // We believe that international is a reasonable default
184 // (that we will implement now), and once we do more
185 // extensive research, we may feel comfortable with dropping
186 // it down to edgy.
187
188 // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of
189 // str(c)spn assumes that the string was already well formed
190 // Unicode (which of course it is).
191 if (strspn($font, $this->mask) !== strlen($font)) {
192 continue;
193 }
194
195 // Historical:
196 // In the absence of innerHTML/cssText, these ugly
197 // transforms don't pose a security risk (as \\ and \"
198 // might--these escapes are not supported by most browsers).
199 // We could try to be clever and use single-quote wrapping
200 // when there is a double quote present, but I have choosen
201 // not to implement that. (NOTE: you can reduce the amount
202 // of escapes by one depending on what quoting style you use)
203 // $font = str_replace('\\', '\\5C ', $font);
204 // $font = str_replace('"', '\\22 ', $font);
205 // $font = str_replace("'", '\\27 ', $font);
206
207 // font possibly with spaces, requires quoting
208 $final .= "'$font', ";
209 }
210 $final = rtrim($final, ', ');
211 if ($final === '') {
212 return false;
213 }
214 return $final;
215 }
216
217}
218
219// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php
new file mode 100644
index 00000000..5f13edfd
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php
@@ -0,0 +1,32 @@
1<?php
2
3/**
4 * Validates based on {ident} CSS grammar production
5 */
6class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * @param string $string
11 * @param HTMLPurifier_Config $config
12 * @param HTMLPurifier_Context $context
13 * @return bool|string
14 */
15 public function validate($string, $config, $context)
16 {
17 $string = trim($string);
18
19 // early abort: '' and '0' (strings that convert to false) are invalid
20 if (!$string) {
21 return false;
22 }
23
24 $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/';
25 if (!preg_match($pattern, $string)) {
26 return false;
27 }
28 return $string;
29 }
30}
31
32// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
new file mode 100644
index 00000000..f4848494
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
@@ -0,0 +1,56 @@
1<?php
2
3/**
4 * Decorator which enables !important to be used in CSS values.
5 */
6class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
7{
8 /**
9 * @type HTMLPurifier_AttrDef
10 */
11 public $def;
12 /**
13 * @type bool
14 */
15 public $allow;
16
17 /**
18 * @param HTMLPurifier_AttrDef $def Definition to wrap
19 * @param bool $allow Whether or not to allow !important
20 */
21 public function __construct($def, $allow = false)
22 {
23 $this->def = $def;
24 $this->allow = $allow;
25 }
26
27 /**
28 * Intercepts and removes !important if necessary
29 * @param string $string
30 * @param HTMLPurifier_Config $config
31 * @param HTMLPurifier_Context $context
32 * @return bool|string
33 */
34 public function validate($string, $config, $context)
35 {
36 // test for ! and important tokens
37 $string = trim($string);
38 $is_important = false;
39 // :TODO: optimization: test directly for !important and ! important
40 if (strlen($string) >= 9 && substr($string, -9) === 'important') {
41 $temp = rtrim(substr($string, 0, -9));
42 // use a temp, because we might want to restore important
43 if (strlen($temp) >= 1 && substr($temp, -1) === '!') {
44 $string = rtrim(substr($temp, 0, -1));
45 $is_important = true;
46 }
47 }
48 $string = $this->def->validate($string, $config, $context);
49 if ($this->allow && $is_important) {
50 $string .= ' !important';
51 }
52 return $string;
53 }
54}
55
56// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php
new file mode 100644
index 00000000..88da41d9
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php
@@ -0,0 +1,77 @@
1<?php
2
3/**
4 * Represents a Length as defined by CSS.
5 */
6class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * @type HTMLPurifier_Length|string
11 */
12 protected $min;
13
14 /**
15 * @type HTMLPurifier_Length|string
16 */
17 protected $max;
18
19 /**
20 * @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable.
21 * @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable.
22 */
23 public function __construct($min = null, $max = null)
24 {
25 $this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
26 $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
27 }
28
29 /**
30 * @param string $string
31 * @param HTMLPurifier_Config $config
32 * @param HTMLPurifier_Context $context
33 * @return bool|string
34 */
35 public function validate($string, $config, $context)
36 {
37 $string = $this->parseCDATA($string);
38
39 // Optimizations
40 if ($string === '') {
41 return false;
42 }
43 if ($string === '0') {
44 return '0';
45 }
46 if (strlen($string) === 1) {
47 return false;
48 }
49
50 $length = HTMLPurifier_Length::make($string);
51 if (!$length->isValid()) {
52 return false;
53 }
54
55 if ($this->min) {
56 $c = $length->compareTo($this->min);
57 if ($c === false) {
58 return false;
59 }
60 if ($c < 0) {
61 return false;
62 }
63 }
64 if ($this->max) {
65 $c = $length->compareTo($this->max);
66 if ($c === false) {
67 return false;
68 }
69 if ($c > 0) {
70 return false;
71 }
72 }
73 return $length->toString();
74 }
75}
76
77// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php
new file mode 100644
index 00000000..b4cce9a9
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php
@@ -0,0 +1,112 @@
1<?php
2
3/**
4 * Validates shorthand CSS property list-style.
5 * @warning Does not support url tokens that have internal spaces.
6 */
7class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
8{
9
10 /**
11 * Local copy of validators.
12 * @type HTMLPurifier_AttrDef[]
13 * @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
14 */
15 protected $info;
16
17 /**
18 * @param HTMLPurifier_Config $config
19 */
20 public function __construct($config)
21 {
22 $def = $config->getCSSDefinition();
23 $this->info['list-style-type'] = $def->info['list-style-type'];
24 $this->info['list-style-position'] = $def->info['list-style-position'];
25 $this->info['list-style-image'] = $def->info['list-style-image'];
26 }
27
28 /**
29 * @param string $string
30 * @param HTMLPurifier_Config $config
31 * @param HTMLPurifier_Context $context
32 * @return bool|string
33 */
34 public function validate($string, $config, $context)
35 {
36 // regular pre-processing
37 $string = $this->parseCDATA($string);
38 if ($string === '') {
39 return false;
40 }
41
42 // assumes URI doesn't have spaces in it
43 $bits = explode(' ', strtolower($string)); // bits to process
44
45 $caught = array();
46 $caught['type'] = false;
47 $caught['position'] = false;
48 $caught['image'] = false;
49
50 $i = 0; // number of catches
51 $none = false;
52
53 foreach ($bits as $bit) {
54 if ($i >= 3) {
55 return;
56 } // optimization bit
57 if ($bit === '') {
58 continue;
59 }
60 foreach ($caught as $key => $status) {
61 if ($status !== false) {
62 continue;
63 }
64 $r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
65 if ($r === false) {
66 continue;
67 }
68 if ($r === 'none') {
69 if ($none) {
70 continue;
71 } else {
72 $none = true;
73 }
74 if ($key == 'image') {
75 continue;
76 }
77 }
78 $caught[$key] = $r;
79 $i++;
80 break;
81 }
82 }
83
84 if (!$i) {
85 return false;
86 }
87
88 $ret = array();
89
90 // construct type
91 if ($caught['type']) {
92 $ret[] = $caught['type'];
93 }
94
95 // construct image
96 if ($caught['image']) {
97 $ret[] = $caught['image'];
98 }
99
100 // construct position
101 if ($caught['position']) {
102 $ret[] = $caught['position'];
103 }
104
105 if (empty($ret)) {
106 return false;
107 }
108 return implode(' ', $ret);
109 }
110}
111
112// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php
new file mode 100644
index 00000000..73d586f2
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php
@@ -0,0 +1,71 @@
1<?php
2
3/**
4 * Framework class for strings that involve multiple values.
5 *
6 * Certain CSS properties such as border-width and margin allow multiple
7 * lengths to be specified. This class can take a vanilla border-width
8 * definition and multiply it, usually into a max of four.
9 *
10 * @note Even though the CSS specification isn't clear about it, inherit
11 * can only be used alone: it will never manifest as part of a multi
12 * shorthand declaration. Thus, this class does not allow inherit.
13 */
14class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
15{
16 /**
17 * Instance of component definition to defer validation to.
18 * @type HTMLPurifier_AttrDef
19 * @todo Make protected
20 */
21 public $single;
22
23 /**
24 * Max number of values allowed.
25 * @todo Make protected
26 */
27 public $max;
28
29 /**
30 * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply
31 * @param int $max Max number of values allowed (usually four)
32 */
33 public function __construct($single, $max = 4)
34 {
35 $this->single = $single;
36 $this->max = $max;
37 }
38
39 /**
40 * @param string $string
41 * @param HTMLPurifier_Config $config
42 * @param HTMLPurifier_Context $context
43 * @return bool|string
44 */
45 public function validate($string, $config, $context)
46 {
47 $string = $this->parseCDATA($string);
48 if ($string === '') {
49 return false;
50 }
51 $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
52 $length = count($parts);
53 $final = '';
54 for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
55 if (ctype_space($parts[$i])) {
56 continue;
57 }
58 $result = $this->single->validate($parts[$i], $config, $context);
59 if ($result !== false) {
60 $final .= $result . ' ';
61 $num++;
62 }
63 }
64 if ($final === '') {
65 return false;
66 }
67 return rtrim($final);
68 }
69}
70
71// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php
new file mode 100644
index 00000000..c78f6c9d
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php
@@ -0,0 +1,84 @@
1<?php
2
3/**
4 * Validates a number as defined by the CSS spec.
5 */
6class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * Indicates whether or not only positive values are allowed.
11 * @type bool
12 */
13 protected $non_negative = false;
14
15 /**
16 * @param bool $non_negative indicates whether negatives are forbidden
17 */
18 public function __construct($non_negative = false)
19 {
20 $this->non_negative = $non_negative;
21 }
22
23 /**
24 * @param string $number
25 * @param HTMLPurifier_Config $config
26 * @param HTMLPurifier_Context $context
27 * @return string|bool
28 * @warning Some contexts do not pass $config, $context. These
29 * variables should not be used without checking HTMLPurifier_Length
30 */
31 public function validate($number, $config, $context)
32 {
33 $number = $this->parseCDATA($number);
34
35 if ($number === '') {
36 return false;
37 }
38 if ($number === '0') {
39 return '0';
40 }
41
42 $sign = '';
43 switch ($number[0]) {
44 case '-':
45 if ($this->non_negative) {
46 return false;
47 }
48 $sign = '-';
49 case '+':
50 $number = substr($number, 1);
51 }
52
53 if (ctype_digit($number)) {
54 $number = ltrim($number, '0');
55 return $number ? $sign . $number : '0';
56 }
57
58 // Period is the only non-numeric character allowed
59 if (strpos($number, '.') === false) {
60 return false;
61 }
62
63 list($left, $right) = explode('.', $number, 2);
64
65 if ($left === '' && $right === '') {
66 return false;
67 }
68 if ($left !== '' && !ctype_digit($left)) {
69 return false;
70 }
71
72 $left = ltrim($left, '0');
73 $right = rtrim($right, '0');
74
75 if ($right === '') {
76 return $left ? $sign . $left : '0';
77 } elseif (!ctype_digit($right)) {
78 return false;
79 }
80 return $sign . $left . '.' . $right;
81 }
82}
83
84// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php
new file mode 100644
index 00000000..aac1a6f5
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php
@@ -0,0 +1,54 @@
1<?php
2
3/**
4 * Validates a Percentage as defined by the CSS spec.
5 */
6class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
7{
8
9 /**
10 * Instance to defer number validation to.
11 * @type HTMLPurifier_AttrDef_CSS_Number
12 */
13 protected $number_def;
14
15 /**
16 * @param bool $non_negative Whether to forbid negative values
17 */
18 public function __construct($non_negative = false)
19 {
20 $this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
21 }
22
23 /**
24 * @param string $string
25 * @param HTMLPurifier_Config $config
26 * @param HTMLPurifier_Context $context
27 * @return bool|string
28 */
29 public function validate($string, $config, $context)
30 {
31 $string = $this->parseCDATA($string);
32
33 if ($string === '') {
34 return false;
35 }
36 $length = strlen($string);
37 if ($length === 1) {
38 return false;
39 }
40 if ($string[$length - 1] !== '%') {
41 return false;
42 }
43
44 $number = substr($string, 0, $length - 1);
45 $number = $this->number_def->validate($number, $config, $context);
46
47 if ($number === false) {
48 return false;
49 }
50 return "$number%";
51 }
52}
53
54// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php
new file mode 100644
index 00000000..3992de0e
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php
@@ -0,0 +1,46 @@
1<?php
2
3/**
4 * Validates the value for the CSS property text-decoration
5 * @note This class could be generalized into a version that acts sort of
6 * like Enum except you can compound the allowed values.
7 */
8class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
9{
10
11 /**
12 * @param string $string
13 * @param HTMLPurifier_Config $config
14 * @param HTMLPurifier_Context $context
15 * @return bool|string
16 */
17 public function validate($string, $config, $context)
18 {
19 static $allowed_values = array(
20 'line-through' => true,
21 'overline' => true,
22 'underline' => true,
23 );
24
25 $string = strtolower($this->parseCDATA($string));
26
27 if ($string === 'none') {
28 return $string;
29 }
30
31 $parts = explode(' ', $string);
32 $final = '';
33 foreach ($parts as $part) {
34 if (isset($allowed_values[$part])) {
35 $final .= $part . ' ';
36 }
37 }
38 $final = rtrim($final);
39 if ($final === '') {
40 return false;
41 }
42 return $final;
43 }
44}
45
46// vim: et sw=4 sts=4
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php
new file mode 100644
index 00000000..482b0997
--- /dev/null
+++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php
@@ -0,0 +1,74 @@
1<?php
2
3/**
4 * Validates a URI in CSS syntax, which uses url('http://example.com')
5 * @note While theoretically speaking a URI in a CSS document could
6 * be non-embedded, as of CSS2 there is no such usage so we're
7 * generalizing it. This may need to be changed in the future.
8 * @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as
9 * the separator, you cannot put a literal semicolon in
10 * in the URI. Try percent encoding it, in that case.
11 */
12class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
13{
14
15 public function __construct()
16 {
17 parent::__construct(true); // always embedded
18 }
19
20 /**
21 * @param string $uri_string
22 * @param HTMLPurifier_Config $config
23 * @param HTMLPurifier_Context $context
24 * @return bool|string
25 */
26 public function validate($uri_string, $config, $context)
27 {
28 // parse the URI out of the string and then pass it onto
29 // the parent object
30
31 $uri_string = $this->parseCDATA($uri_string);
32 if (strpos($uri_string, 'url(') !== 0) {
33 return false;
34 }
35 $uri_string = substr($uri_string, 4);
36 $new_length = strlen($uri_string) - 1;
37 if ($uri_string[$new_length] != ')') {
38 return false;
39 }
40 $uri = trim(substr($uri_string, 0, $new_length));
41
42 if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) {
43 $quote = $uri[0];
44 $new_length = strlen($uri) - 1;
45 if ($uri[$new_length] !== $quote) {
46 return false;
47 }
48 $uri = substr($uri, 1, $new_length - 1);
49 }
50
51 $uri = $this->expandCSSEscape($uri);
52
53 $result = parent::validate($uri, $config, $context);
54
55 if ($result === false) {
56 return false;
57 }
58
59 // extra sanity check; should have been done by URI
60 $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
61
62 // suspicious characters are ()'; we're going to percent encode
63 // them for safety.
64 $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result);
65
66 // there's an extra bug where ampersands lose their escaping on
67 // an innerHTML cycle, so a very unlucky query parameter could
68 // then change the meaning of the URL. Unfortunately, there's
69 // not much we can do about that...
70 return "url(\"$result\")";
71 }
72}
73
74// vim: et sw=4 sts=4