]>
Commit | Line | Data |
---|---|---|
d4949327 NL |
1 | <?php\r |
2 | \r | |
3 | /**\r | |
4 | * Error collection class that enables HTML Purifier to report HTML\r | |
5 | * problems back to the user\r | |
6 | */\r | |
7 | class HTMLPurifier_ErrorCollector\r | |
8 | {\r | |
9 | \r | |
10 | /**\r | |
11 | * Identifiers for the returned error array. These are purposely numeric\r | |
12 | * so list() can be used.\r | |
13 | */\r | |
14 | const LINENO = 0;\r | |
15 | const SEVERITY = 1;\r | |
16 | const MESSAGE = 2;\r | |
17 | const CHILDREN = 3;\r | |
18 | \r | |
19 | /**\r | |
20 | * @type array\r | |
21 | */\r | |
22 | protected $errors;\r | |
23 | \r | |
24 | /**\r | |
25 | * @type array\r | |
26 | */\r | |
27 | protected $_current;\r | |
28 | \r | |
29 | /**\r | |
30 | * @type array\r | |
31 | */\r | |
32 | protected $_stacks = array(array());\r | |
33 | \r | |
34 | /**\r | |
35 | * @type HTMLPurifier_Language\r | |
36 | */\r | |
37 | protected $locale;\r | |
38 | \r | |
39 | /**\r | |
40 | * @type HTMLPurifier_Generator\r | |
41 | */\r | |
42 | protected $generator;\r | |
43 | \r | |
44 | /**\r | |
45 | * @type HTMLPurifier_Context\r | |
46 | */\r | |
47 | protected $context;\r | |
48 | \r | |
49 | /**\r | |
50 | * @type array\r | |
51 | */\r | |
52 | protected $lines = array();\r | |
53 | \r | |
54 | /**\r | |
55 | * @param HTMLPurifier_Context $context\r | |
56 | */\r | |
57 | public function __construct($context)\r | |
58 | {\r | |
59 | $this->locale =& $context->get('Locale');\r | |
60 | $this->context = $context;\r | |
61 | $this->_current =& $this->_stacks[0];\r | |
62 | $this->errors =& $this->_stacks[0];\r | |
63 | }\r | |
64 | \r | |
65 | /**\r | |
66 | * Sends an error message to the collector for later use\r | |
67 | * @param int $severity Error severity, PHP error style (don't use E_USER_)\r | |
68 | * @param string $msg Error message text\r | |
69 | */\r | |
70 | public function send($severity, $msg)\r | |
71 | {\r | |
72 | $args = array();\r | |
73 | if (func_num_args() > 2) {\r | |
74 | $args = func_get_args();\r | |
75 | array_shift($args);\r | |
76 | unset($args[0]);\r | |
77 | }\r | |
78 | \r | |
79 | $token = $this->context->get('CurrentToken', true);\r | |
80 | $line = $token ? $token->line : $this->context->get('CurrentLine', true);\r | |
81 | $col = $token ? $token->col : $this->context->get('CurrentCol', true);\r | |
82 | $attr = $this->context->get('CurrentAttr', true);\r | |
83 | \r | |
84 | // perform special substitutions, also add custom parameters\r | |
85 | $subst = array();\r | |
86 | if (!is_null($token)) {\r | |
87 | $args['CurrentToken'] = $token;\r | |
88 | }\r | |
89 | if (!is_null($attr)) {\r | |
90 | $subst['$CurrentAttr.Name'] = $attr;\r | |
91 | if (isset($token->attr[$attr])) {\r | |
92 | $subst['$CurrentAttr.Value'] = $token->attr[$attr];\r | |
93 | }\r | |
94 | }\r | |
95 | \r | |
96 | if (empty($args)) {\r | |
97 | $msg = $this->locale->getMessage($msg);\r | |
98 | } else {\r | |
99 | $msg = $this->locale->formatMessage($msg, $args);\r | |
100 | }\r | |
101 | \r | |
102 | if (!empty($subst)) {\r | |
103 | $msg = strtr($msg, $subst);\r | |
104 | }\r | |
105 | \r | |
106 | // (numerically indexed)\r | |
107 | $error = array(\r | |
108 | self::LINENO => $line,\r | |
109 | self::SEVERITY => $severity,\r | |
110 | self::MESSAGE => $msg,\r | |
111 | self::CHILDREN => array()\r | |
112 | );\r | |
113 | $this->_current[] = $error;\r | |
114 | \r | |
115 | // NEW CODE BELOW ...\r | |
116 | // Top-level errors are either:\r | |
117 | // TOKEN type, if $value is set appropriately, or\r | |
118 | // "syntax" type, if $value is null\r | |
119 | $new_struct = new HTMLPurifier_ErrorStruct();\r | |
120 | $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN;\r | |
121 | if ($token) {\r | |
122 | $new_struct->value = clone $token;\r | |
123 | }\r | |
124 | if (is_int($line) && is_int($col)) {\r | |
125 | if (isset($this->lines[$line][$col])) {\r | |
126 | $struct = $this->lines[$line][$col];\r | |
127 | } else {\r | |
128 | $struct = $this->lines[$line][$col] = $new_struct;\r | |
129 | }\r | |
130 | // These ksorts may present a performance problem\r | |
131 | ksort($this->lines[$line], SORT_NUMERIC);\r | |
132 | } else {\r | |
133 | if (isset($this->lines[-1])) {\r | |
134 | $struct = $this->lines[-1];\r | |
135 | } else {\r | |
136 | $struct = $this->lines[-1] = $new_struct;\r | |
137 | }\r | |
138 | }\r | |
139 | ksort($this->lines, SORT_NUMERIC);\r | |
140 | \r | |
141 | // Now, check if we need to operate on a lower structure\r | |
142 | if (!empty($attr)) {\r | |
143 | $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr);\r | |
144 | if (!$struct->value) {\r | |
145 | $struct->value = array($attr, 'PUT VALUE HERE');\r | |
146 | }\r | |
147 | }\r | |
148 | if (!empty($cssprop)) {\r | |
149 | $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop);\r | |
150 | if (!$struct->value) {\r | |
151 | // if we tokenize CSS this might be a little more difficult to do\r | |
152 | $struct->value = array($cssprop, 'PUT VALUE HERE');\r | |
153 | }\r | |
154 | }\r | |
155 | \r | |
156 | // Ok, structs are all setup, now time to register the error\r | |
157 | $struct->addError($severity, $msg);\r | |
158 | }\r | |
159 | \r | |
160 | /**\r | |
161 | * Retrieves raw error data for custom formatter to use\r | |
162 | */\r | |
163 | public function getRaw()\r | |
164 | {\r | |
165 | return $this->errors;\r | |
166 | }\r | |
167 | \r | |
168 | /**\r | |
169 | * Default HTML formatting implementation for error messages\r | |
170 | * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature\r | |
171 | * @param array $errors Errors array to display; used for recursion.\r | |
172 | * @return string\r | |
173 | */\r | |
174 | public function getHTMLFormatted($config, $errors = null)\r | |
175 | {\r | |
176 | $ret = array();\r | |
177 | \r | |
178 | $this->generator = new HTMLPurifier_Generator($config, $this->context);\r | |
179 | if ($errors === null) {\r | |
180 | $errors = $this->errors;\r | |
181 | }\r | |
182 | \r | |
183 | // 'At line' message needs to be removed\r | |
184 | \r | |
185 | // generation code for new structure goes here. It needs to be recursive.\r | |
186 | foreach ($this->lines as $line => $col_array) {\r | |
187 | if ($line == -1) {\r | |
188 | continue;\r | |
189 | }\r | |
190 | foreach ($col_array as $col => $struct) {\r | |
191 | $this->_renderStruct($ret, $struct, $line, $col);\r | |
192 | }\r | |
193 | }\r | |
194 | if (isset($this->lines[-1])) {\r | |
195 | $this->_renderStruct($ret, $this->lines[-1]);\r | |
196 | }\r | |
197 | \r | |
198 | if (empty($errors)) {\r | |
199 | return '<p>' . $this->locale->getMessage('ErrorCollector: No errors') . '</p>';\r | |
200 | } else {\r | |
201 | return '<ul><li>' . implode('</li><li>', $ret) . '</li></ul>';\r | |
202 | }\r | |
203 | \r | |
204 | }\r | |
205 | \r | |
206 | private function _renderStruct(&$ret, $struct, $line = null, $col = null)\r | |
207 | {\r | |
208 | $stack = array($struct);\r | |
209 | $context_stack = array(array());\r | |
210 | while ($current = array_pop($stack)) {\r | |
211 | $context = array_pop($context_stack);\r | |
212 | foreach ($current->errors as $error) {\r | |
213 | list($severity, $msg) = $error;\r | |
214 | $string = '';\r | |
215 | $string .= '<div>';\r | |
216 | // W3C uses an icon to indicate the severity of the error.\r | |
217 | $error = $this->locale->getErrorName($severity);\r | |
218 | $string .= "<span class=\"error e$severity\"><strong>$error</strong></span> ";\r | |
219 | if (!is_null($line) && !is_null($col)) {\r | |
220 | $string .= "<em class=\"location\">Line $line, Column $col: </em> ";\r | |
221 | } else {\r | |
222 | $string .= '<em class="location">End of Document: </em> ';\r | |
223 | }\r | |
224 | $string .= '<strong class="description">' . $this->generator->escape($msg) . '</strong> ';\r | |
225 | $string .= '</div>';\r | |
226 | // Here, have a marker for the character on the column appropriate.\r | |
227 | // Be sure to clip extremely long lines.\r | |
228 | //$string .= '<pre>';\r | |
229 | //$string .= '';\r | |
230 | //$string .= '</pre>';\r | |
231 | $ret[] = $string;\r | |
232 | }\r | |
233 | foreach ($current->children as $array) {\r | |
234 | $context[] = $current;\r | |
235 | $stack = array_merge($stack, array_reverse($array, true));\r | |
236 | for ($i = count($array); $i > 0; $i--) {\r | |
237 | $context_stack[] = $context;\r | |
238 | }\r | |
239 | }\r | |
240 | }\r | |
241 | }\r | |
242 | }\r | |
243 | \r | |
244 | // vim: et sw=4 sts=4\r |