]> git.immae.eu Git - github/wallabag/wallabag.git/blame - inc/3rdparty/htmlpurifier/HTMLPurifier/ConfigSchema/Validator.php
[add] HTML Purifier added to clean code
[github/wallabag/wallabag.git] / inc / 3rdparty / htmlpurifier / HTMLPurifier / ConfigSchema / Validator.php
CommitLineData
d4949327
NL
1<?php\r
2\r
3/**\r
4 * Performs validations on HTMLPurifier_ConfigSchema_Interchange\r
5 *\r
6 * @note If you see '// handled by InterchangeBuilder', that means a\r
7 * design decision in that class would prevent this validation from\r
8 * ever being necessary. We have them anyway, however, for\r
9 * redundancy.\r
10 */\r
11class HTMLPurifier_ConfigSchema_Validator\r
12{\r
13\r
14 /**\r
15 * @type HTMLPurifier_ConfigSchema_Interchange\r
16 */\r
17 protected $interchange;\r
18\r
19 /**\r
20 * @type array\r
21 */\r
22 protected $aliases;\r
23\r
24 /**\r
25 * Context-stack to provide easy to read error messages.\r
26 * @type array\r
27 */\r
28 protected $context = array();\r
29\r
30 /**\r
31 * to test default's type.\r
32 * @type HTMLPurifier_VarParser\r
33 */\r
34 protected $parser;\r
35\r
36 public function __construct()\r
37 {\r
38 $this->parser = new HTMLPurifier_VarParser();\r
39 }\r
40\r
41 /**\r
42 * Validates a fully-formed interchange object.\r
43 * @param HTMLPurifier_ConfigSchema_Interchange $interchange\r
44 * @return bool\r
45 */\r
46 public function validate($interchange)\r
47 {\r
48 $this->interchange = $interchange;\r
49 $this->aliases = array();\r
50 // PHP is a bit lax with integer <=> string conversions in\r
51 // arrays, so we don't use the identical !== comparison\r
52 foreach ($interchange->directives as $i => $directive) {\r
53 $id = $directive->id->toString();\r
54 if ($i != $id) {\r
55 $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");\r
56 }\r
57 $this->validateDirective($directive);\r
58 }\r
59 return true;\r
60 }\r
61\r
62 /**\r
63 * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object.\r
64 * @param HTMLPurifier_ConfigSchema_Interchange_Id $id\r
65 */\r
66 public function validateId($id)\r
67 {\r
68 $id_string = $id->toString();\r
69 $this->context[] = "id '$id_string'";\r
70 if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) {\r
71 // handled by InterchangeBuilder\r
72 $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id');\r
73 }\r
74 // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.)\r
75 // we probably should check that it has at least one namespace\r
76 $this->with($id, 'key')\r
77 ->assertNotEmpty()\r
78 ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder\r
79 array_pop($this->context);\r
80 }\r
81\r
82 /**\r
83 * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object.\r
84 * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d\r
85 */\r
86 public function validateDirective($d)\r
87 {\r
88 $id = $d->id->toString();\r
89 $this->context[] = "directive '$id'";\r
90 $this->validateId($d->id);\r
91\r
92 $this->with($d, 'description')\r
93 ->assertNotEmpty();\r
94\r
95 // BEGIN - handled by InterchangeBuilder\r
96 $this->with($d, 'type')\r
97 ->assertNotEmpty();\r
98 $this->with($d, 'typeAllowsNull')\r
99 ->assertIsBool();\r
100 try {\r
101 // This also tests validity of $d->type\r
102 $this->parser->parse($d->default, $d->type, $d->typeAllowsNull);\r
103 } catch (HTMLPurifier_VarParserException $e) {\r
104 $this->error('default', 'had error: ' . $e->getMessage());\r
105 }\r
106 // END - handled by InterchangeBuilder\r
107\r
108 if (!is_null($d->allowed) || !empty($d->valueAliases)) {\r
109 // allowed and valueAliases require that we be dealing with\r
110 // strings, so check for that early.\r
111 $d_int = HTMLPurifier_VarParser::$types[$d->type];\r
112 if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) {\r
113 $this->error('type', 'must be a string type when used with allowed or value aliases');\r
114 }\r
115 }\r
116\r
117 $this->validateDirectiveAllowed($d);\r
118 $this->validateDirectiveValueAliases($d);\r
119 $this->validateDirectiveAliases($d);\r
120\r
121 array_pop($this->context);\r
122 }\r
123\r
124 /**\r
125 * Extra validation if $allowed member variable of\r
126 * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.\r
127 * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d\r
128 */\r
129 public function validateDirectiveAllowed($d)\r
130 {\r
131 if (is_null($d->allowed)) {\r
132 return;\r
133 }\r
134 $this->with($d, 'allowed')\r
135 ->assertNotEmpty()\r
136 ->assertIsLookup(); // handled by InterchangeBuilder\r
137 if (is_string($d->default) && !isset($d->allowed[$d->default])) {\r
138 $this->error('default', 'must be an allowed value');\r
139 }\r
140 $this->context[] = 'allowed';\r
141 foreach ($d->allowed as $val => $x) {\r
142 if (!is_string($val)) {\r
143 $this->error("value $val", 'must be a string');\r
144 }\r
145 }\r
146 array_pop($this->context);\r
147 }\r
148\r
149 /**\r
150 * Extra validation if $valueAliases member variable of\r
151 * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.\r
152 * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d\r
153 */\r
154 public function validateDirectiveValueAliases($d)\r
155 {\r
156 if (is_null($d->valueAliases)) {\r
157 return;\r
158 }\r
159 $this->with($d, 'valueAliases')\r
160 ->assertIsArray(); // handled by InterchangeBuilder\r
161 $this->context[] = 'valueAliases';\r
162 foreach ($d->valueAliases as $alias => $real) {\r
163 if (!is_string($alias)) {\r
164 $this->error("alias $alias", 'must be a string');\r
165 }\r
166 if (!is_string($real)) {\r
167 $this->error("alias target $real from alias '$alias'", 'must be a string');\r
168 }\r
169 if ($alias === $real) {\r
170 $this->error("alias '$alias'", "must not be an alias to itself");\r
171 }\r
172 }\r
173 if (!is_null($d->allowed)) {\r
174 foreach ($d->valueAliases as $alias => $real) {\r
175 if (isset($d->allowed[$alias])) {\r
176 $this->error("alias '$alias'", 'must not be an allowed value');\r
177 } elseif (!isset($d->allowed[$real])) {\r
178 $this->error("alias '$alias'", 'must be an alias to an allowed value');\r
179 }\r
180 }\r
181 }\r
182 array_pop($this->context);\r
183 }\r
184\r
185 /**\r
186 * Extra validation if $aliases member variable of\r
187 * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.\r
188 * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d\r
189 */\r
190 public function validateDirectiveAliases($d)\r
191 {\r
192 $this->with($d, 'aliases')\r
193 ->assertIsArray(); // handled by InterchangeBuilder\r
194 $this->context[] = 'aliases';\r
195 foreach ($d->aliases as $alias) {\r
196 $this->validateId($alias);\r
197 $s = $alias->toString();\r
198 if (isset($this->interchange->directives[$s])) {\r
199 $this->error("alias '$s'", 'collides with another directive');\r
200 }\r
201 if (isset($this->aliases[$s])) {\r
202 $other_directive = $this->aliases[$s];\r
203 $this->error("alias '$s'", "collides with alias for directive '$other_directive'");\r
204 }\r
205 $this->aliases[$s] = $d->id->toString();\r
206 }\r
207 array_pop($this->context);\r
208 }\r
209\r
210 // protected helper functions\r
211\r
212 /**\r
213 * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom\r
214 * for validating simple member variables of objects.\r
215 * @param $obj\r
216 * @param $member\r
217 * @return HTMLPurifier_ConfigSchema_ValidatorAtom\r
218 */\r
219 protected function with($obj, $member)\r
220 {\r
221 return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member);\r
222 }\r
223\r
224 /**\r
225 * Emits an error, providing helpful context.\r
226 * @throws HTMLPurifier_ConfigSchema_Exception\r
227 */\r
228 protected function error($target, $msg)\r
229 {\r
230 if ($target !== false) {\r
231 $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();\r
232 } else {\r
233 $prefix = ucfirst($this->getFormattedContext());\r
234 }\r
235 throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg));\r
236 }\r
237\r
238 /**\r
239 * Returns a formatted context string.\r
240 * @return string\r
241 */\r
242 protected function getFormattedContext()\r
243 {\r
244 return implode(' in ', array_reverse($this->context));\r
245 }\r
246}\r
247\r
248// vim: et sw=4 sts=4\r