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