HTMLPurifier 4.4.0
/home/ezyang/Dev/htmlpurifier/library/HTMLPurifier/ErrorCollector.php
Go to the documentation of this file.
00001 <?php
00002 
00007 class HTMLPurifier_ErrorCollector
00008 {
00009 
00014     const LINENO   = 0;
00015     const SEVERITY = 1;
00016     const MESSAGE  = 2;
00017     const CHILDREN = 3;
00018 
00019     protected $errors;
00020     protected $_current;
00021     protected $_stacks = array(array());
00022     protected $locale;
00023     protected $generator;
00024     protected $context;
00025 
00026     protected $lines = array();
00027 
00028     public function __construct($context) {
00029         $this->locale    =& $context->get('Locale');
00030         $this->context   = $context;
00031         $this->_current  =& $this->_stacks[0];
00032         $this->errors    =& $this->_stacks[0];
00033     }
00034 
00042     public function send($severity, $msg) {
00043 
00044         $args = array();
00045         if (func_num_args() > 2) {
00046             $args = func_get_args();
00047             array_shift($args);
00048             unset($args[0]);
00049         }
00050 
00051         $token = $this->context->get('CurrentToken', true);
00052         $line  = $token ? $token->line : $this->context->get('CurrentLine', true);
00053         $col   = $token ? $token->col  : $this->context->get('CurrentCol',  true);
00054         $attr  = $this->context->get('CurrentAttr', true);
00055 
00056         // perform special substitutions, also add custom parameters
00057         $subst = array();
00058         if (!is_null($token)) {
00059             $args['CurrentToken'] = $token;
00060         }
00061         if (!is_null($attr)) {
00062             $subst['$CurrentAttr.Name'] = $attr;
00063             if (isset($token->attr[$attr])) $subst['$CurrentAttr.Value'] = $token->attr[$attr];
00064         }
00065 
00066         if (empty($args)) {
00067             $msg = $this->locale->getMessage($msg);
00068         } else {
00069             $msg = $this->locale->formatMessage($msg, $args);
00070         }
00071 
00072         if (!empty($subst)) $msg = strtr($msg, $subst);
00073 
00074         // (numerically indexed)
00075         $error = array(
00076             self::LINENO   => $line,
00077             self::SEVERITY => $severity,
00078             self::MESSAGE  => $msg,
00079             self::CHILDREN => array()
00080         );
00081         $this->_current[] = $error;
00082 
00083 
00084         // NEW CODE BELOW ...
00085 
00086         $struct = null;
00087         // Top-level errors are either:
00088         //  TOKEN type, if $value is set appropriately, or
00089         //  "syntax" type, if $value is null
00090         $new_struct = new HTMLPurifier_ErrorStruct();
00091         $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN;
00092         if ($token) $new_struct->value = clone $token;
00093         if (is_int($line) && is_int($col)) {
00094             if (isset($this->lines[$line][$col])) {
00095                 $struct = $this->lines[$line][$col];
00096             } else {
00097                 $struct = $this->lines[$line][$col] = $new_struct;
00098             }
00099             // These ksorts may present a performance problem
00100             ksort($this->lines[$line], SORT_NUMERIC);
00101         } else {
00102             if (isset($this->lines[-1])) {
00103                 $struct = $this->lines[-1];
00104             } else {
00105                 $struct = $this->lines[-1] = $new_struct;
00106             }
00107         }
00108         ksort($this->lines, SORT_NUMERIC);
00109 
00110         // Now, check if we need to operate on a lower structure
00111         if (!empty($attr)) {
00112             $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr);
00113             if (!$struct->value) {
00114                 $struct->value = array($attr, 'PUT VALUE HERE');
00115             }
00116         }
00117         if (!empty($cssprop)) {
00118             $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop);
00119             if (!$struct->value) {
00120                 // if we tokenize CSS this might be a little more difficult to do
00121                 $struct->value = array($cssprop, 'PUT VALUE HERE');
00122             }
00123         }
00124 
00125         // Ok, structs are all setup, now time to register the error
00126         $struct->addError($severity, $msg);
00127     }
00128 
00135     public function getRaw() {
00136         return $this->errors;
00137     }
00138 
00144     public function getHTMLFormatted($config, $errors = null) {
00145         $ret = array();
00146 
00147         $this->generator = new HTMLPurifier_Generator($config, $this->context);
00148         if ($errors === null) $errors = $this->errors;
00149 
00150         // 'At line' message needs to be removed
00151 
00152         // generation code for new structure goes here. It needs to be recursive.
00153         foreach ($this->lines as $line => $col_array) {
00154             if ($line == -1) continue;
00155             foreach ($col_array as $col => $struct) {
00156                 $this->_renderStruct($ret, $struct, $line, $col);
00157             }
00158         }
00159         if (isset($this->lines[-1])) {
00160             $this->_renderStruct($ret, $this->lines[-1]);
00161         }
00162 
00163         if (empty($errors)) {
00164             return '<p>' . $this->locale->getMessage('ErrorCollector: No errors') . '</p>';
00165         } else {
00166             return '<ul><li>' . implode('</li><li>', $ret) . '</li></ul>';
00167         }
00168 
00169     }
00170 
00171     private function _renderStruct(&$ret, $struct, $line = null, $col = null) {
00172         $stack = array($struct);
00173         $context_stack = array(array());
00174         while ($current = array_pop($stack)) {
00175             $context = array_pop($context_stack);
00176             foreach ($current->errors as $error) {
00177                 list($severity, $msg) = $error;
00178                 $string = '';
00179                 $string .= '<div>';
00180                 // W3C uses an icon to indicate the severity of the error.
00181                 $error = $this->locale->getErrorName($severity);
00182                 $string .= "<span class=\"error e$severity\"><strong>$error</strong></span> ";
00183                 if (!is_null($line) && !is_null($col)) {
00184                     $string .= "<em class=\"location\">Line $line, Column $col: </em> ";
00185                 } else {
00186                     $string .= '<em class="location">End of Document: </em> ';
00187                 }
00188                 $string .= '<strong class="description">' . $this->generator->escape($msg) . '</strong> ';
00189                 $string .= '</div>';
00190                 // Here, have a marker for the character on the column appropriate.
00191                 // Be sure to clip extremely long lines.
00192                 //$string .= '<pre>';
00193                 //$string .= '';
00194                 //$string .= '</pre>';
00195                 $ret[] = $string;
00196             }
00197             foreach ($current->children as $type => $array) {
00198                 $context[] = $current;
00199                 $stack = array_merge($stack, array_reverse($array, true));
00200                 for ($i = count($array); $i > 0; $i--) {
00201                     $context_stack[] = $context;
00202                 }
00203             }
00204         }
00205     }
00206 
00207 }
00208 
00209 // vim: et sw=4 sts=4