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
title
Description
Body
title
Description
Body
title
Description
Body
title
Body