diff options
Diffstat (limited to 'inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef')
42 files changed, 3156 insertions, 0 deletions
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS.php new file mode 100644 index 00000000..81afcf96 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS.php | |||
@@ -0,0 +1,106 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the HTML attribute style, otherwise known as CSS. | ||
5 | * @note We don't implement the whole CSS specification, so it might be | ||
6 | * difficult to reuse this component in the context of validating | ||
7 | * actual stylesheet declarations. | ||
8 | * @note If we were really serious about validating the CSS, we would | ||
9 | * tokenize the styles and then parse the tokens. Obviously, we | ||
10 | * are not doing that. Doing that could seriously harm performance, | ||
11 | * but would make these components a lot more viable for a CSS | ||
12 | * filtering solution. | ||
13 | */ | ||
14 | class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef | ||
15 | { | ||
16 | |||
17 | /** | ||
18 | * @param string $css | ||
19 | * @param HTMLPurifier_Config $config | ||
20 | * @param HTMLPurifier_Context $context | ||
21 | * @return bool|string | ||
22 | */ | ||
23 | public function validate($css, $config, $context) | ||
24 | { | ||
25 | $css = $this->parseCDATA($css); | ||
26 | |||
27 | $definition = $config->getCSSDefinition(); | ||
28 | |||
29 | // we're going to break the spec and explode by semicolons. | ||
30 | // This is because semicolon rarely appears in escaped form | ||
31 | // Doing this is generally flaky but fast | ||
32 | // IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI | ||
33 | // for details | ||
34 | |||
35 | $declarations = explode(';', $css); | ||
36 | $propvalues = array(); | ||
37 | |||
38 | /** | ||
39 | * Name of the current CSS property being validated. | ||
40 | */ | ||
41 | $property = false; | ||
42 | $context->register('CurrentCSSProperty', $property); | ||
43 | |||
44 | foreach ($declarations as $declaration) { | ||
45 | if (!$declaration) { | ||
46 | continue; | ||
47 | } | ||
48 | if (!strpos($declaration, ':')) { | ||
49 | continue; | ||
50 | } | ||
51 | list($property, $value) = explode(':', $declaration, 2); | ||
52 | $property = trim($property); | ||
53 | $value = trim($value); | ||
54 | $ok = false; | ||
55 | do { | ||
56 | if (isset($definition->info[$property])) { | ||
57 | $ok = true; | ||
58 | break; | ||
59 | } | ||
60 | if (ctype_lower($property)) { | ||
61 | break; | ||
62 | } | ||
63 | $property = strtolower($property); | ||
64 | if (isset($definition->info[$property])) { | ||
65 | $ok = true; | ||
66 | break; | ||
67 | } | ||
68 | } while (0); | ||
69 | if (!$ok) { | ||
70 | continue; | ||
71 | } | ||
72 | // inefficient call, since the validator will do this again | ||
73 | if (strtolower(trim($value)) !== 'inherit') { | ||
74 | // inherit works for everything (but only on the base property) | ||
75 | $result = $definition->info[$property]->validate( | ||
76 | $value, | ||
77 | $config, | ||
78 | $context | ||
79 | ); | ||
80 | } else { | ||
81 | $result = 'inherit'; | ||
82 | } | ||
83 | if ($result === false) { | ||
84 | continue; | ||
85 | } | ||
86 | $propvalues[$property] = $result; | ||
87 | } | ||
88 | |||
89 | $context->destroy('CurrentCSSProperty'); | ||
90 | |||
91 | // procedure does not write the new CSS simultaneously, so it's | ||
92 | // slightly inefficient, but it's the only way of getting rid of | ||
93 | // duplicates. Perhaps config to optimize it, but not now. | ||
94 | |||
95 | $new_declarations = ''; | ||
96 | foreach ($propvalues as $prop => $value) { | ||
97 | $new_declarations .= "$prop:$value;"; | ||
98 | } | ||
99 | |||
100 | return $new_declarations ? $new_declarations : false; | ||
101 | |||
102 | } | ||
103 | |||
104 | } | ||
105 | |||
106 | // vim: et sw=4 sts=4 | ||
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 | |||
3 | class 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 | */ | ||
7 | class 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 | */ | ||
44 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
12 | class 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 | */ | ||
6 | class 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 | */ | ||
8 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
7 | class 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 | */ | ||
14 | class 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 | */ | ||
6 | class 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 | */ | ||
6 | class 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 | */ | ||
8 | class 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 | */ | ||
12 | class 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 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Clone.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Clone.php new file mode 100644 index 00000000..b181d1bc --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Clone.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Dummy AttrDef that mimics another AttrDef, BUT it generates clones | ||
5 | * with make. | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | /** | ||
10 | * What we're cloning. | ||
11 | * @type HTMLPurifier_AttrDef | ||
12 | */ | ||
13 | protected $clone; | ||
14 | |||
15 | /** | ||
16 | * @param HTMLPurifier_AttrDef $clone | ||
17 | */ | ||
18 | public function __construct($clone) | ||
19 | { | ||
20 | $this->clone = $clone; | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * @param string $v | ||
25 | * @param HTMLPurifier_Config $config | ||
26 | * @param HTMLPurifier_Context $context | ||
27 | * @return bool|string | ||
28 | */ | ||
29 | public function validate($v, $config, $context) | ||
30 | { | ||
31 | return $this->clone->validate($v, $config, $context); | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * @param string $string | ||
36 | * @return HTMLPurifier_AttrDef | ||
37 | */ | ||
38 | public function make($string) | ||
39 | { | ||
40 | return clone $this->clone; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Enum.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Enum.php new file mode 100644 index 00000000..b40122b6 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Enum.php | |||
@@ -0,0 +1,73 @@ | |||
1 | <?php | ||
2 | |||
3 | // Enum = Enumerated | ||
4 | /** | ||
5 | * Validates a keyword against a list of valid values. | ||
6 | * @warning The case-insensitive compare of this function uses PHP's | ||
7 | * built-in strtolower and ctype_lower functions, which may | ||
8 | * cause problems with international comparisons | ||
9 | */ | ||
10 | class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef | ||
11 | { | ||
12 | |||
13 | /** | ||
14 | * Lookup table of valid values. | ||
15 | * @type array | ||
16 | * @todo Make protected | ||
17 | */ | ||
18 | public $valid_values = array(); | ||
19 | |||
20 | /** | ||
21 | * Bool indicating whether or not enumeration is case sensitive. | ||
22 | * @note In general this is always case insensitive. | ||
23 | */ | ||
24 | protected $case_sensitive = false; // values according to W3C spec | ||
25 | |||
26 | /** | ||
27 | * @param array $valid_values List of valid values | ||
28 | * @param bool $case_sensitive Whether or not case sensitive | ||
29 | */ | ||
30 | public function __construct($valid_values = array(), $case_sensitive = false) | ||
31 | { | ||
32 | $this->valid_values = array_flip($valid_values); | ||
33 | $this->case_sensitive = $case_sensitive; | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * @param string $string | ||
38 | * @param HTMLPurifier_Config $config | ||
39 | * @param HTMLPurifier_Context $context | ||
40 | * @return bool|string | ||
41 | */ | ||
42 | public function validate($string, $config, $context) | ||
43 | { | ||
44 | $string = trim($string); | ||
45 | if (!$this->case_sensitive) { | ||
46 | // we may want to do full case-insensitive libraries | ||
47 | $string = ctype_lower($string) ? $string : strtolower($string); | ||
48 | } | ||
49 | $result = isset($this->valid_values[$string]); | ||
50 | |||
51 | return $result ? $string : false; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * @param string $string In form of comma-delimited list of case-insensitive | ||
56 | * valid values. Example: "foo,bar,baz". Prepend "s:" to make | ||
57 | * case sensitive | ||
58 | * @return HTMLPurifier_AttrDef_Enum | ||
59 | */ | ||
60 | public function make($string) | ||
61 | { | ||
62 | if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { | ||
63 | $string = substr($string, 2); | ||
64 | $sensitive = true; | ||
65 | } else { | ||
66 | $sensitive = false; | ||
67 | } | ||
68 | $values = explode(',', $string); | ||
69 | return new HTMLPurifier_AttrDef_Enum($values, $sensitive); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Bool.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Bool.php new file mode 100644 index 00000000..1463c647 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Bool.php | |||
@@ -0,0 +1,51 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a boolean attribute | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @type bool | ||
11 | */ | ||
12 | protected $name; | ||
13 | |||
14 | /** | ||
15 | * @type bool | ||
16 | */ | ||
17 | public $minimized = true; | ||
18 | |||
19 | /** | ||
20 | * @param bool $name | ||
21 | */ | ||
22 | public function __construct($name = false) | ||
23 | { | ||
24 | $this->name = $name; | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @param string $string | ||
29 | * @param HTMLPurifier_Config $config | ||
30 | * @param HTMLPurifier_Context $context | ||
31 | * @return bool|string | ||
32 | */ | ||
33 | public function validate($string, $config, $context) | ||
34 | { | ||
35 | if (empty($string)) { | ||
36 | return false; | ||
37 | } | ||
38 | return $this->name; | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * @param string $string Name of attribute | ||
43 | * @return HTMLPurifier_AttrDef_HTML_Bool | ||
44 | */ | ||
45 | public function make($string) | ||
46 | { | ||
47 | return new HTMLPurifier_AttrDef_HTML_Bool($string); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Class.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 00000000..b874c7e1 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Class.php | |||
@@ -0,0 +1,48 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Implements special behavior for class attribute (normally NMTOKENS) | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens | ||
7 | { | ||
8 | /** | ||
9 | * @param string $string | ||
10 | * @param HTMLPurifier_Config $config | ||
11 | * @param HTMLPurifier_Context $context | ||
12 | * @return bool|string | ||
13 | */ | ||
14 | protected function split($string, $config, $context) | ||
15 | { | ||
16 | // really, this twiddle should be lazy loaded | ||
17 | $name = $config->getDefinition('HTML')->doctype->name; | ||
18 | if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { | ||
19 | return parent::split($string, $config, $context); | ||
20 | } else { | ||
21 | return preg_split('/\s+/', $string); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @param array $tokens | ||
27 | * @param HTMLPurifier_Config $config | ||
28 | * @param HTMLPurifier_Context $context | ||
29 | * @return array | ||
30 | */ | ||
31 | protected function filter($tokens, $config, $context) | ||
32 | { | ||
33 | $allowed = $config->get('Attr.AllowedClasses'); | ||
34 | $forbidden = $config->get('Attr.ForbiddenClasses'); | ||
35 | $ret = array(); | ||
36 | foreach ($tokens as $token) { | ||
37 | if (($allowed === null || isset($allowed[$token])) && | ||
38 | !isset($forbidden[$token]) && | ||
39 | // We need this O(n) check because of PHP's array | ||
40 | // implementation that casts -0 to 0. | ||
41 | !in_array($token, $ret, true) | ||
42 | ) { | ||
43 | $ret[] = $token; | ||
44 | } | ||
45 | } | ||
46 | return $ret; | ||
47 | } | ||
48 | } | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Color.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Color.php new file mode 100644 index 00000000..25c93fc6 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Color.php | |||
@@ -0,0 +1,51 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a color according to the HTML spec. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_Color 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 | static $colors = null; | ||
18 | if ($colors === null) { | ||
19 | $colors = $config->get('Core.ColorKeywords'); | ||
20 | } | ||
21 | |||
22 | $string = trim($string); | ||
23 | |||
24 | if (empty($string)) { | ||
25 | return false; | ||
26 | } | ||
27 | $lower = strtolower($string); | ||
28 | if (isset($colors[$lower])) { | ||
29 | return $colors[$lower]; | ||
30 | } | ||
31 | if ($string[0] === '#') { | ||
32 | $hex = substr($string, 1); | ||
33 | } else { | ||
34 | $hex = $string; | ||
35 | } | ||
36 | |||
37 | $length = strlen($hex); | ||
38 | if ($length !== 3 && $length !== 6) { | ||
39 | return false; | ||
40 | } | ||
41 | if (!ctype_xdigit($hex)) { | ||
42 | return false; | ||
43 | } | ||
44 | if ($length === 3) { | ||
45 | $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; | ||
46 | } | ||
47 | return "#$hex"; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php new file mode 100644 index 00000000..7446b6da --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php | |||
@@ -0,0 +1,38 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Special-case enum attribute definition that lazy loads allowed frame targets | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @type array | ||
11 | */ | ||
12 | public $valid_values = false; // uninitialized value | ||
13 | |||
14 | /** | ||
15 | * @type bool | ||
16 | */ | ||
17 | protected $case_sensitive = false; | ||
18 | |||
19 | public function __construct() | ||
20 | { | ||
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 | if ($this->valid_values === false) { | ||
32 | $this->valid_values = $config->get('Attr.AllowedFrameTargets'); | ||
33 | } | ||
34 | return parent::validate($string, $config, $context); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/ID.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/ID.php new file mode 100644 index 00000000..ccd4a24a --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/ID.php | |||
@@ -0,0 +1,105 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the HTML attribute ID. | ||
5 | * @warning Even though this is the id processor, it | ||
6 | * will ignore the directive Attr:IDBlacklist, since it will only | ||
7 | * go according to the ID accumulator. Since the accumulator is | ||
8 | * automatically generated, it will have already absorbed the | ||
9 | * blacklist. If you're hacking around, make sure you use load()! | ||
10 | */ | ||
11 | |||
12 | class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef | ||
13 | { | ||
14 | |||
15 | // selector is NOT a valid thing to use for IDREFs, because IDREFs | ||
16 | // *must* target IDs that exist, whereas selector #ids do not. | ||
17 | |||
18 | /** | ||
19 | * Determines whether or not we're validating an ID in a CSS | ||
20 | * selector context. | ||
21 | * @type bool | ||
22 | */ | ||
23 | protected $selector; | ||
24 | |||
25 | /** | ||
26 | * @param bool $selector | ||
27 | */ | ||
28 | public function __construct($selector = false) | ||
29 | { | ||
30 | $this->selector = $selector; | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * @param string $id | ||
35 | * @param HTMLPurifier_Config $config | ||
36 | * @param HTMLPurifier_Context $context | ||
37 | * @return bool|string | ||
38 | */ | ||
39 | public function validate($id, $config, $context) | ||
40 | { | ||
41 | if (!$this->selector && !$config->get('Attr.EnableID')) { | ||
42 | return false; | ||
43 | } | ||
44 | |||
45 | $id = trim($id); // trim it first | ||
46 | |||
47 | if ($id === '') { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | $prefix = $config->get('Attr.IDPrefix'); | ||
52 | if ($prefix !== '') { | ||
53 | $prefix .= $config->get('Attr.IDPrefixLocal'); | ||
54 | // prevent re-appending the prefix | ||
55 | if (strpos($id, $prefix) !== 0) { | ||
56 | $id = $prefix . $id; | ||
57 | } | ||
58 | } elseif ($config->get('Attr.IDPrefixLocal') !== '') { | ||
59 | trigger_error( | ||
60 | '%Attr.IDPrefixLocal cannot be used unless ' . | ||
61 | '%Attr.IDPrefix is set', | ||
62 | E_USER_WARNING | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | if (!$this->selector) { | ||
67 | $id_accumulator =& $context->get('IDAccumulator'); | ||
68 | if (isset($id_accumulator->ids[$id])) { | ||
69 | return false; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | // we purposely avoid using regex, hopefully this is faster | ||
74 | |||
75 | if (ctype_alpha($id)) { | ||
76 | $result = true; | ||
77 | } else { | ||
78 | if (!ctype_alpha(@$id[0])) { | ||
79 | return false; | ||
80 | } | ||
81 | // primitive style of regexps, I suppose | ||
82 | $trim = trim( | ||
83 | $id, | ||
84 | 'A..Za..z0..9:-._' | ||
85 | ); | ||
86 | $result = ($trim === ''); | ||
87 | } | ||
88 | |||
89 | $regexp = $config->get('Attr.IDBlacklistRegexp'); | ||
90 | if ($regexp && preg_match($regexp, $id)) { | ||
91 | return false; | ||
92 | } | ||
93 | |||
94 | if (!$this->selector && $result) { | ||
95 | $id_accumulator->add($id); | ||
96 | } | ||
97 | |||
98 | // if no change was made to the ID, return the result | ||
99 | // else, return the new id if stripping whitespace made it | ||
100 | // valid, or return false. | ||
101 | return $result ? $id : false; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Length.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Length.php new file mode 100644 index 00000000..c8f51886 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Length.php | |||
@@ -0,0 +1,56 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the HTML type length (not to be confused with CSS's length). | ||
5 | * | ||
6 | * This accepts integer pixels or percentages as lengths for certain | ||
7 | * HTML attributes. | ||
8 | */ | ||
9 | |||
10 | class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels | ||
11 | { | ||
12 | |||
13 | /** | ||
14 | * @param string $string | ||
15 | * @param HTMLPurifier_Config $config | ||
16 | * @param HTMLPurifier_Context $context | ||
17 | * @return bool|string | ||
18 | */ | ||
19 | public function validate($string, $config, $context) | ||
20 | { | ||
21 | $string = trim($string); | ||
22 | if ($string === '') { | ||
23 | return false; | ||
24 | } | ||
25 | |||
26 | $parent_result = parent::validate($string, $config, $context); | ||
27 | if ($parent_result !== false) { | ||
28 | return $parent_result; | ||
29 | } | ||
30 | |||
31 | $length = strlen($string); | ||
32 | $last_char = $string[$length - 1]; | ||
33 | |||
34 | if ($last_char !== '%') { | ||
35 | return false; | ||
36 | } | ||
37 | |||
38 | $points = substr($string, 0, $length - 1); | ||
39 | |||
40 | if (!is_numeric($points)) { | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | $points = (int)$points; | ||
45 | |||
46 | if ($points < 0) { | ||
47 | return '0%'; | ||
48 | } | ||
49 | if ($points > 100) { | ||
50 | return '100%'; | ||
51 | } | ||
52 | return ((string)$points) . '%'; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 00000000..3f56934f --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php | |||
@@ -0,0 +1,72 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a rel/rev link attribute against a directive of allowed values | ||
5 | * @note We cannot use Enum because link types allow multiple | ||
6 | * values. | ||
7 | * @note Assumes link types are ASCII text | ||
8 | */ | ||
9 | class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef | ||
10 | { | ||
11 | |||
12 | /** | ||
13 | * Name config attribute to pull. | ||
14 | * @type string | ||
15 | */ | ||
16 | protected $name; | ||
17 | |||
18 | /** | ||
19 | * @param string $name | ||
20 | */ | ||
21 | public function __construct($name) | ||
22 | { | ||
23 | $configLookup = array( | ||
24 | 'rel' => 'AllowedRel', | ||
25 | 'rev' => 'AllowedRev' | ||
26 | ); | ||
27 | if (!isset($configLookup[$name])) { | ||
28 | trigger_error( | ||
29 | 'Unrecognized attribute name for link ' . | ||
30 | 'relationship.', | ||
31 | E_USER_ERROR | ||
32 | ); | ||
33 | return; | ||
34 | } | ||
35 | $this->name = $configLookup[$name]; | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * @param string $string | ||
40 | * @param HTMLPurifier_Config $config | ||
41 | * @param HTMLPurifier_Context $context | ||
42 | * @return bool|string | ||
43 | */ | ||
44 | public function validate($string, $config, $context) | ||
45 | { | ||
46 | $allowed = $config->get('Attr.' . $this->name); | ||
47 | if (empty($allowed)) { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | $string = $this->parseCDATA($string); | ||
52 | $parts = explode(' ', $string); | ||
53 | |||
54 | // lookup to prevent duplicates | ||
55 | $ret_lookup = array(); | ||
56 | foreach ($parts as $part) { | ||
57 | $part = strtolower(trim($part)); | ||
58 | if (!isset($allowed[$part])) { | ||
59 | continue; | ||
60 | } | ||
61 | $ret_lookup[$part] = true; | ||
62 | } | ||
63 | |||
64 | if (empty($ret_lookup)) { | ||
65 | return false; | ||
66 | } | ||
67 | $string = implode(' ', array_keys($ret_lookup)); | ||
68 | return $string; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php new file mode 100644 index 00000000..eb713e15 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php | |||
@@ -0,0 +1,60 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a MultiLength as defined by the HTML spec. | ||
5 | * | ||
6 | * A multilength is either a integer (pixel count), a percentage, or | ||
7 | * a relative number. | ||
8 | */ | ||
9 | class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length | ||
10 | { | ||
11 | |||
12 | /** | ||
13 | * @param string $string | ||
14 | * @param HTMLPurifier_Config $config | ||
15 | * @param HTMLPurifier_Context $context | ||
16 | * @return bool|string | ||
17 | */ | ||
18 | public function validate($string, $config, $context) | ||
19 | { | ||
20 | $string = trim($string); | ||
21 | if ($string === '') { | ||
22 | return false; | ||
23 | } | ||
24 | |||
25 | $parent_result = parent::validate($string, $config, $context); | ||
26 | if ($parent_result !== false) { | ||
27 | return $parent_result; | ||
28 | } | ||
29 | |||
30 | $length = strlen($string); | ||
31 | $last_char = $string[$length - 1]; | ||
32 | |||
33 | if ($last_char !== '*') { | ||
34 | return false; | ||
35 | } | ||
36 | |||
37 | $int = substr($string, 0, $length - 1); | ||
38 | |||
39 | if ($int == '') { | ||
40 | return '*'; | ||
41 | } | ||
42 | if (!is_numeric($int)) { | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | $int = (int)$int; | ||
47 | if ($int < 0) { | ||
48 | return false; | ||
49 | } | ||
50 | if ($int == 0) { | ||
51 | return '0'; | ||
52 | } | ||
53 | if ($int == 1) { | ||
54 | return '*'; | ||
55 | } | ||
56 | return ((string)$int) . '*'; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Nmtokens.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Nmtokens.php new file mode 100644 index 00000000..ecb070c3 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Nmtokens.php | |||
@@ -0,0 +1,70 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates contents based on NMTOKENS attribute type. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_Nmtokens 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 | $tokens = $this->split($string, $config, $context); | ||
25 | $tokens = $this->filter($tokens, $config, $context); | ||
26 | if (empty($tokens)) { | ||
27 | return false; | ||
28 | } | ||
29 | return implode(' ', $tokens); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * Splits a space separated list of tokens into its constituent parts. | ||
34 | * @param string $string | ||
35 | * @param HTMLPurifier_Config $config | ||
36 | * @param HTMLPurifier_Context $context | ||
37 | * @return array | ||
38 | */ | ||
39 | protected function split($string, $config, $context) | ||
40 | { | ||
41 | // OPTIMIZABLE! | ||
42 | // do the preg_match, capture all subpatterns for reformulation | ||
43 | |||
44 | // we don't support U+00A1 and up codepoints or | ||
45 | // escaping because I don't know how to do that with regexps | ||
46 | // and plus it would complicate optimization efforts (you never | ||
47 | // see that anyway). | ||
48 | $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start | ||
49 | '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' . | ||
50 | '(?:(?=\s)|\z)/'; // look ahead for space or string end | ||
51 | preg_match_all($pattern, $string, $matches); | ||
52 | return $matches[1]; | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * Template method for removing certain tokens based on arbitrary criteria. | ||
57 | * @note If we wanted to be really functional, we'd do an array_filter | ||
58 | * with a callback. But... we're not. | ||
59 | * @param array $tokens | ||
60 | * @param HTMLPurifier_Config $config | ||
61 | * @param HTMLPurifier_Context $context | ||
62 | * @return array | ||
63 | */ | ||
64 | protected function filter($tokens, $config, $context) | ||
65 | { | ||
66 | return $tokens; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Pixels.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Pixels.php new file mode 100644 index 00000000..1a68f238 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/HTML/Pixels.php | |||
@@ -0,0 +1,76 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates an integer representation of pixels according to the HTML spec. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @type int | ||
11 | */ | ||
12 | protected $max; | ||
13 | |||
14 | /** | ||
15 | * @param int $max | ||
16 | */ | ||
17 | public function __construct($max = null) | ||
18 | { | ||
19 | $this->max = $max; | ||
20 | } | ||
21 | |||
22 | /** | ||
23 | * @param string $string | ||
24 | * @param HTMLPurifier_Config $config | ||
25 | * @param HTMLPurifier_Context $context | ||
26 | * @return bool|string | ||
27 | */ | ||
28 | public function validate($string, $config, $context) | ||
29 | { | ||
30 | $string = trim($string); | ||
31 | if ($string === '0') { | ||
32 | return $string; | ||
33 | } | ||
34 | if ($string === '') { | ||
35 | return false; | ||
36 | } | ||
37 | $length = strlen($string); | ||
38 | if (substr($string, $length - 2) == 'px') { | ||
39 | $string = substr($string, 0, $length - 2); | ||
40 | } | ||
41 | if (!is_numeric($string)) { | ||
42 | return false; | ||
43 | } | ||
44 | $int = (int)$string; | ||
45 | |||
46 | if ($int < 0) { | ||
47 | return '0'; | ||
48 | } | ||
49 | |||
50 | // upper-bound value, extremely high values can | ||
51 | // crash operating systems, see <http://ha.ckers.org/imagecrash.html> | ||
52 | // WARNING, above link WILL crash you if you're using Windows | ||
53 | |||
54 | if ($this->max !== null && $int > $this->max) { | ||
55 | return (string)$this->max; | ||
56 | } | ||
57 | return (string)$int; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * @param string $string | ||
62 | * @return HTMLPurifier_AttrDef | ||
63 | */ | ||
64 | public function make($string) | ||
65 | { | ||
66 | if ($string === '') { | ||
67 | $max = null; | ||
68 | } else { | ||
69 | $max = (int)$string; | ||
70 | } | ||
71 | $class = get_class($this); | ||
72 | return new $class($max); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Integer.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Integer.php new file mode 100644 index 00000000..c98376d7 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Integer.php | |||
@@ -0,0 +1,91 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates an integer. | ||
5 | * @note While this class was modeled off the CSS definition, no currently | ||
6 | * allowed CSS uses this type. The properties that do are: widows, | ||
7 | * orphans, z-index, counter-increment, counter-reset. Some of the | ||
8 | * HTML attributes, however, find use for a non-negative version of this. | ||
9 | */ | ||
10 | class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef | ||
11 | { | ||
12 | |||
13 | /** | ||
14 | * Whether or not negative values are allowed. | ||
15 | * @type bool | ||
16 | */ | ||
17 | protected $negative = true; | ||
18 | |||
19 | /** | ||
20 | * Whether or not zero is allowed. | ||
21 | * @type bool | ||
22 | */ | ||
23 | protected $zero = true; | ||
24 | |||
25 | /** | ||
26 | * Whether or not positive values are allowed. | ||
27 | * @type bool | ||
28 | */ | ||
29 | protected $positive = true; | ||
30 | |||
31 | /** | ||
32 | * @param $negative Bool indicating whether or not negative values are allowed | ||
33 | * @param $zero Bool indicating whether or not zero is allowed | ||
34 | * @param $positive Bool indicating whether or not positive values are allowed | ||
35 | */ | ||
36 | public function __construct($negative = true, $zero = true, $positive = true) | ||
37 | { | ||
38 | $this->negative = $negative; | ||
39 | $this->zero = $zero; | ||
40 | $this->positive = $positive; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * @param string $integer | ||
45 | * @param HTMLPurifier_Config $config | ||
46 | * @param HTMLPurifier_Context $context | ||
47 | * @return bool|string | ||
48 | */ | ||
49 | public function validate($integer, $config, $context) | ||
50 | { | ||
51 | $integer = $this->parseCDATA($integer); | ||
52 | if ($integer === '') { | ||
53 | return false; | ||
54 | } | ||
55 | |||
56 | // we could possibly simply typecast it to integer, but there are | ||
57 | // certain fringe cases that must not return an integer. | ||
58 | |||
59 | // clip leading sign | ||
60 | if ($this->negative && $integer[0] === '-') { | ||
61 | $digits = substr($integer, 1); | ||
62 | if ($digits === '0') { | ||
63 | $integer = '0'; | ||
64 | } // rm minus sign for zero | ||
65 | } elseif ($this->positive && $integer[0] === '+') { | ||
66 | $digits = $integer = substr($integer, 1); // rm unnecessary plus | ||
67 | } else { | ||
68 | $digits = $integer; | ||
69 | } | ||
70 | |||
71 | // test if it's numeric | ||
72 | if (!ctype_digit($digits)) { | ||
73 | return false; | ||
74 | } | ||
75 | |||
76 | // perform scope tests | ||
77 | if (!$this->zero && $integer == 0) { | ||
78 | return false; | ||
79 | } | ||
80 | if (!$this->positive && $integer > 0) { | ||
81 | return false; | ||
82 | } | ||
83 | if (!$this->negative && $integer < 0) { | ||
84 | return false; | ||
85 | } | ||
86 | |||
87 | return $integer; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Lang.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Lang.php new file mode 100644 index 00000000..6ad0f799 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Lang.php | |||
@@ -0,0 +1,86 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the HTML attribute lang, effectively a language code. | ||
5 | * @note Built according to RFC 3066, which obsoleted RFC 1766 | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * @param string $string | ||
12 | * @param HTMLPurifier_Config $config | ||
13 | * @param HTMLPurifier_Context $context | ||
14 | * @return bool|string | ||
15 | */ | ||
16 | public function validate($string, $config, $context) | ||
17 | { | ||
18 | $string = trim($string); | ||
19 | if (!$string) { | ||
20 | return false; | ||
21 | } | ||
22 | |||
23 | $subtags = explode('-', $string); | ||
24 | $num_subtags = count($subtags); | ||
25 | |||
26 | if ($num_subtags == 0) { // sanity check | ||
27 | return false; | ||
28 | } | ||
29 | |||
30 | // process primary subtag : $subtags[0] | ||
31 | $length = strlen($subtags[0]); | ||
32 | switch ($length) { | ||
33 | case 0: | ||
34 | return false; | ||
35 | case 1: | ||
36 | if (!($subtags[0] == 'x' || $subtags[0] == 'i')) { | ||
37 | return false; | ||
38 | } | ||
39 | break; | ||
40 | case 2: | ||
41 | case 3: | ||
42 | if (!ctype_alpha($subtags[0])) { | ||
43 | return false; | ||
44 | } elseif (!ctype_lower($subtags[0])) { | ||
45 | $subtags[0] = strtolower($subtags[0]); | ||
46 | } | ||
47 | break; | ||
48 | default: | ||
49 | return false; | ||
50 | } | ||
51 | |||
52 | $new_string = $subtags[0]; | ||
53 | if ($num_subtags == 1) { | ||
54 | return $new_string; | ||
55 | } | ||
56 | |||
57 | // process second subtag : $subtags[1] | ||
58 | $length = strlen($subtags[1]); | ||
59 | if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) { | ||
60 | return $new_string; | ||
61 | } | ||
62 | if (!ctype_lower($subtags[1])) { | ||
63 | $subtags[1] = strtolower($subtags[1]); | ||
64 | } | ||
65 | |||
66 | $new_string .= '-' . $subtags[1]; | ||
67 | if ($num_subtags == 2) { | ||
68 | return $new_string; | ||
69 | } | ||
70 | |||
71 | // process all other subtags, index 2 and up | ||
72 | for ($i = 2; $i < $num_subtags; $i++) { | ||
73 | $length = strlen($subtags[$i]); | ||
74 | if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { | ||
75 | return $new_string; | ||
76 | } | ||
77 | if (!ctype_lower($subtags[$i])) { | ||
78 | $subtags[$i] = strtolower($subtags[$i]); | ||
79 | } | ||
80 | $new_string .= '-' . $subtags[$i]; | ||
81 | } | ||
82 | return $new_string; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Switch.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Switch.php new file mode 100644 index 00000000..078291f5 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Switch.php | |||
@@ -0,0 +1,53 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Decorator that, depending on a token, switches between two definitions. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_Switch | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @type string | ||
11 | */ | ||
12 | protected $tag; | ||
13 | |||
14 | /** | ||
15 | * @type HTMLPurifier_AttrDef | ||
16 | */ | ||
17 | protected $withTag; | ||
18 | |||
19 | /** | ||
20 | * @type HTMLPurifier_AttrDef | ||
21 | */ | ||
22 | protected $withoutTag; | ||
23 | |||
24 | /** | ||
25 | * @param string $tag Tag name to switch upon | ||
26 | * @param HTMLPurifier_AttrDef $with_tag Call if token matches tag | ||
27 | * @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token | ||
28 | */ | ||
29 | public function __construct($tag, $with_tag, $without_tag) | ||
30 | { | ||
31 | $this->tag = $tag; | ||
32 | $this->withTag = $with_tag; | ||
33 | $this->withoutTag = $without_tag; | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * @param string $string | ||
38 | * @param HTMLPurifier_Config $config | ||
39 | * @param HTMLPurifier_Context $context | ||
40 | * @return bool|string | ||
41 | */ | ||
42 | public function validate($string, $config, $context) | ||
43 | { | ||
44 | $token = $context->get('CurrentToken', true); | ||
45 | if (!$token || $token->name !== $this->tag) { | ||
46 | return $this->withoutTag->validate($string, $config, $context); | ||
47 | } else { | ||
48 | return $this->withTag->validate($string, $config, $context); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Text.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Text.php new file mode 100644 index 00000000..9f23bac4 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/Text.php | |||
@@ -0,0 +1,21 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates arbitrary text according to the HTML spec. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_Text 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 | return $this->parseCDATA($string); | ||
18 | } | ||
19 | } | ||
20 | |||
21 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI.php new file mode 100644 index 00000000..a1097cd9 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI.php | |||
@@ -0,0 +1,111 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a URI as defined by RFC 3986. | ||
5 | * @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * @type HTMLPurifier_URIParser | ||
12 | */ | ||
13 | protected $parser; | ||
14 | |||
15 | /** | ||
16 | * @type bool | ||
17 | */ | ||
18 | protected $embedsResource; | ||
19 | |||
20 | /** | ||
21 | * @param bool $embeds_resource Does the URI here result in an extra HTTP request? | ||
22 | */ | ||
23 | public function __construct($embeds_resource = false) | ||
24 | { | ||
25 | $this->parser = new HTMLPurifier_URIParser(); | ||
26 | $this->embedsResource = (bool)$embeds_resource; | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @param string $string | ||
31 | * @return HTMLPurifier_AttrDef_URI | ||
32 | */ | ||
33 | public function make($string) | ||
34 | { | ||
35 | $embeds = ($string === 'embedded'); | ||
36 | return new HTMLPurifier_AttrDef_URI($embeds); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @param string $uri | ||
41 | * @param HTMLPurifier_Config $config | ||
42 | * @param HTMLPurifier_Context $context | ||
43 | * @return bool|string | ||
44 | */ | ||
45 | public function validate($uri, $config, $context) | ||
46 | { | ||
47 | if ($config->get('URI.Disable')) { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | $uri = $this->parseCDATA($uri); | ||
52 | |||
53 | // parse the URI | ||
54 | $uri = $this->parser->parse($uri); | ||
55 | if ($uri === false) { | ||
56 | return false; | ||
57 | } | ||
58 | |||
59 | // add embedded flag to context for validators | ||
60 | $context->register('EmbeddedURI', $this->embedsResource); | ||
61 | |||
62 | $ok = false; | ||
63 | do { | ||
64 | |||
65 | // generic validation | ||
66 | $result = $uri->validate($config, $context); | ||
67 | if (!$result) { | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | // chained filtering | ||
72 | $uri_def = $config->getDefinition('URI'); | ||
73 | $result = $uri_def->filter($uri, $config, $context); | ||
74 | if (!$result) { | ||
75 | break; | ||
76 | } | ||
77 | |||
78 | // scheme-specific validation | ||
79 | $scheme_obj = $uri->getSchemeObj($config, $context); | ||
80 | if (!$scheme_obj) { | ||
81 | break; | ||
82 | } | ||
83 | if ($this->embedsResource && !$scheme_obj->browsable) { | ||
84 | break; | ||
85 | } | ||
86 | $result = $scheme_obj->validate($uri, $config, $context); | ||
87 | if (!$result) { | ||
88 | break; | ||
89 | } | ||
90 | |||
91 | // Post chained filtering | ||
92 | $result = $uri_def->postFilter($uri, $config, $context); | ||
93 | if (!$result) { | ||
94 | break; | ||
95 | } | ||
96 | |||
97 | // survived gauntlet | ||
98 | $ok = true; | ||
99 | |||
100 | } while (false); | ||
101 | |||
102 | $context->destroy('EmbeddedURI'); | ||
103 | if (!$ok) { | ||
104 | return false; | ||
105 | } | ||
106 | // back to string | ||
107 | return $uri->toString(); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php new file mode 100644 index 00000000..846d3881 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php | |||
@@ -0,0 +1,20 @@ | |||
1 | <?php | ||
2 | |||
3 | abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef | ||
4 | { | ||
5 | |||
6 | /** | ||
7 | * Unpacks a mailbox into its display-name and address | ||
8 | * @param string $string | ||
9 | * @return mixed | ||
10 | */ | ||
11 | public function unpack($string) | ||
12 | { | ||
13 | // needs to be implemented | ||
14 | } | ||
15 | |||
16 | } | ||
17 | |||
18 | // sub-implementations | ||
19 | |||
20 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php new file mode 100644 index 00000000..3b041ce8 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php | |||
@@ -0,0 +1,29 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Primitive email validation class based on the regexp found at | ||
5 | * http://www.regular-expressions.info/email.html | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * @param string $string | ||
12 | * @param HTMLPurifier_Config $config | ||
13 | * @param HTMLPurifier_Context $context | ||
14 | * @return bool|string | ||
15 | */ | ||
16 | public function validate($string, $config, $context) | ||
17 | { | ||
18 | // no support for named mailboxes i.e. "Bob <bob@example.com>" | ||
19 | // that needs more percent encoding to be done | ||
20 | if ($string == '') { | ||
21 | return false; | ||
22 | } | ||
23 | $string = trim($string); | ||
24 | $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); | ||
25 | return $result ? $string : false; | ||
26 | } | ||
27 | } | ||
28 | |||
29 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php new file mode 100644 index 00000000..01457785 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php | |||
@@ -0,0 +1,128 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a host according to the IPv4, IPv6 and DNS (future) specifications. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * IPv4 sub-validator. | ||
11 | * @type HTMLPurifier_AttrDef_URI_IPv4 | ||
12 | */ | ||
13 | protected $ipv4; | ||
14 | |||
15 | /** | ||
16 | * IPv6 sub-validator. | ||
17 | * @type HTMLPurifier_AttrDef_URI_IPv6 | ||
18 | */ | ||
19 | protected $ipv6; | ||
20 | |||
21 | public function __construct() | ||
22 | { | ||
23 | $this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); | ||
24 | $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @param string $string | ||
29 | * @param HTMLPurifier_Config $config | ||
30 | * @param HTMLPurifier_Context $context | ||
31 | * @return bool|string | ||
32 | */ | ||
33 | public function validate($string, $config, $context) | ||
34 | { | ||
35 | $length = strlen($string); | ||
36 | // empty hostname is OK; it's usually semantically equivalent: | ||
37 | // the default host as defined by a URI scheme is used: | ||
38 | // | ||
39 | // If the URI scheme defines a default for host, then that | ||
40 | // default applies when the host subcomponent is undefined | ||
41 | // or when the registered name is empty (zero length). | ||
42 | if ($string === '') { | ||
43 | return ''; | ||
44 | } | ||
45 | if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') { | ||
46 | //IPv6 | ||
47 | $ip = substr($string, 1, $length - 2); | ||
48 | $valid = $this->ipv6->validate($ip, $config, $context); | ||
49 | if ($valid === false) { | ||
50 | return false; | ||
51 | } | ||
52 | return '[' . $valid . ']'; | ||
53 | } | ||
54 | |||
55 | // need to do checks on unusual encodings too | ||
56 | $ipv4 = $this->ipv4->validate($string, $config, $context); | ||
57 | if ($ipv4 !== false) { | ||
58 | return $ipv4; | ||
59 | } | ||
60 | |||
61 | // A regular domain name. | ||
62 | |||
63 | // This doesn't match I18N domain names, but we don't have proper IRI support, | ||
64 | // so force users to insert Punycode. | ||
65 | |||
66 | // There is not a good sense in which underscores should be | ||
67 | // allowed, since it's technically not! (And if you go as | ||
68 | // far to allow everything as specified by the DNS spec... | ||
69 | // well, that's literally everything, modulo some space limits | ||
70 | // for the components and the overall name (which, by the way, | ||
71 | // we are NOT checking!). So we (arbitrarily) decide this: | ||
72 | // let's allow underscores wherever we would have allowed | ||
73 | // hyphens, if they are enabled. This is a pretty good match | ||
74 | // for browser behavior, for example, a large number of browsers | ||
75 | // cannot handle foo_.example.com, but foo_bar.example.com is | ||
76 | // fairly well supported. | ||
77 | $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; | ||
78 | |||
79 | // The productions describing this are: | ||
80 | $a = '[a-z]'; // alpha | ||
81 | $an = '[a-z0-9]'; // alphanum | ||
82 | $and = "[a-z0-9-$underscore]"; // alphanum | "-" | ||
83 | // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum | ||
84 | $domainlabel = "$an($and*$an)?"; | ||
85 | // toplabel = alpha | alpha *( alphanum | "-" ) alphanum | ||
86 | $toplabel = "$a($and*$an)?"; | ||
87 | // hostname = *( domainlabel "." ) toplabel [ "." ] | ||
88 | if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { | ||
89 | return $string; | ||
90 | } | ||
91 | |||
92 | // If we have Net_IDNA2 support, we can support IRIs by | ||
93 | // punycoding them. (This is the most portable thing to do, | ||
94 | // since otherwise we have to assume browsers support | ||
95 | |||
96 | if ($config->get('Core.EnableIDNA')) { | ||
97 | $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); | ||
98 | // we need to encode each period separately | ||
99 | $parts = explode('.', $string); | ||
100 | try { | ||
101 | $new_parts = array(); | ||
102 | foreach ($parts as $part) { | ||
103 | $encodable = false; | ||
104 | for ($i = 0, $c = strlen($part); $i < $c; $i++) { | ||
105 | if (ord($part[$i]) > 0x7a) { | ||
106 | $encodable = true; | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | if (!$encodable) { | ||
111 | $new_parts[] = $part; | ||
112 | } else { | ||
113 | $new_parts[] = $idna->encode($part); | ||
114 | } | ||
115 | } | ||
116 | $string = implode('.', $new_parts); | ||
117 | if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { | ||
118 | return $string; | ||
119 | } | ||
120 | } catch (Exception $e) { | ||
121 | // XXX error reporting | ||
122 | } | ||
123 | } | ||
124 | return false; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php new file mode 100644 index 00000000..bbc8a77e --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php | |||
@@ -0,0 +1,45 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates an IPv4 address | ||
5 | * @author Feyd @ forums.devnetwork.net (public domain) | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * IPv4 regex, protected so that IPv6 can reuse it. | ||
12 | * @type string | ||
13 | */ | ||
14 | protected $ip4; | ||
15 | |||
16 | /** | ||
17 | * @param string $aIP | ||
18 | * @param HTMLPurifier_Config $config | ||
19 | * @param HTMLPurifier_Context $context | ||
20 | * @return bool|string | ||
21 | */ | ||
22 | public function validate($aIP, $config, $context) | ||
23 | { | ||
24 | if (!$this->ip4) { | ||
25 | $this->_loadRegex(); | ||
26 | } | ||
27 | |||
28 | if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { | ||
29 | return $aIP; | ||
30 | } | ||
31 | return false; | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * Lazy load function to prevent regex from being stuffed in | ||
36 | * cache. | ||
37 | */ | ||
38 | protected function _loadRegex() | ||
39 | { | ||
40 | $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 | ||
41 | $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php new file mode 100644 index 00000000..67f148bd --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php | |||
@@ -0,0 +1,89 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates an IPv6 address. | ||
5 | * @author Feyd @ forums.devnetwork.net (public domain) | ||
6 | * @note This function requires brackets to have been removed from address | ||
7 | * in URI. | ||
8 | */ | ||
9 | class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 | ||
10 | { | ||
11 | |||
12 | /** | ||
13 | * @param string $aIP | ||
14 | * @param HTMLPurifier_Config $config | ||
15 | * @param HTMLPurifier_Context $context | ||
16 | * @return bool|string | ||
17 | */ | ||
18 | public function validate($aIP, $config, $context) | ||
19 | { | ||
20 | if (!$this->ip4) { | ||
21 | $this->_loadRegex(); | ||
22 | } | ||
23 | |||
24 | $original = $aIP; | ||
25 | |||
26 | $hex = '[0-9a-fA-F]'; | ||
27 | $blk = '(?:' . $hex . '{1,4})'; | ||
28 | $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 | ||
29 | |||
30 | // prefix check | ||
31 | if (strpos($aIP, '/') !== false) { | ||
32 | if (preg_match('#' . $pre . '$#s', $aIP, $find)) { | ||
33 | $aIP = substr($aIP, 0, 0 - strlen($find[0])); | ||
34 | unset($find); | ||
35 | } else { | ||
36 | return false; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | // IPv4-compatiblity check | ||
41 | if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) { | ||
42 | $aIP = substr($aIP, 0, 0 - strlen($find[0])); | ||
43 | $ip = explode('.', $find[0]); | ||
44 | $ip = array_map('dechex', $ip); | ||
45 | $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; | ||
46 | unset($find, $ip); | ||
47 | } | ||
48 | |||
49 | // compression check | ||
50 | $aIP = explode('::', $aIP); | ||
51 | $c = count($aIP); | ||
52 | if ($c > 2) { | ||
53 | return false; | ||
54 | } elseif ($c == 2) { | ||
55 | list($first, $second) = $aIP; | ||
56 | $first = explode(':', $first); | ||
57 | $second = explode(':', $second); | ||
58 | |||
59 | if (count($first) + count($second) > 8) { | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | while (count($first) < 8) { | ||
64 | array_push($first, '0'); | ||
65 | } | ||
66 | |||
67 | array_splice($first, 8 - count($second), 8, $second); | ||
68 | $aIP = $first; | ||
69 | unset($first, $second); | ||
70 | } else { | ||
71 | $aIP = explode(':', $aIP[0]); | ||
72 | } | ||
73 | $c = count($aIP); | ||
74 | |||
75 | if ($c != 8) { | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | // All the pieces should be 16-bit hex strings. Are they? | ||
80 | foreach ($aIP as $piece) { | ||
81 | if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) { | ||
82 | return false; | ||
83 | } | ||
84 | } | ||
85 | return $original; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // vim: et sw=4 sts=4 | ||