245 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			245 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
| 
								 | 
							
								<?php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Error collection class that enables HTML Purifier to report HTML
							 | 
						||
| 
								 | 
							
								 * problems back to the user
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class HTMLPurifier_ErrorCollector
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Identifiers for the returned error array. These are purposely numeric
							 | 
						||
| 
								 | 
							
								     * so list() can be used.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    const LINENO   = 0;
							 | 
						||
| 
								 | 
							
								    const SEVERITY = 1;
							 | 
						||
| 
								 | 
							
								    const MESSAGE  = 2;
							 | 
						||
| 
								 | 
							
								    const CHILDREN = 3;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type array
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $errors;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type array
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $_current;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type array
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $_stacks = array(array());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type HTMLPurifier_Language
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $locale;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type HTMLPurifier_Generator
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $generator;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type HTMLPurifier_Context
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $context;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @type array
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected $lines = array();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @param HTMLPurifier_Context $context
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public function __construct($context)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        $this->locale    =& $context->get('Locale');
							 | 
						||
| 
								 | 
							
								        $this->context   = $context;
							 | 
						||
| 
								 | 
							
								        $this->_current  =& $this->_stacks[0];
							 | 
						||
| 
								 | 
							
								        $this->errors    =& $this->_stacks[0];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Sends an error message to the collector for later use
							 | 
						||
| 
								 | 
							
								     * @param int $severity Error severity, PHP error style (don't use E_USER_)
							 | 
						||
| 
								 | 
							
								     * @param string $msg Error message text
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public function send($severity, $msg)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        $args = array();
							 | 
						||
| 
								 | 
							
								        if (func_num_args() > 2) {
							 | 
						||
| 
								 | 
							
								            $args = func_get_args();
							 | 
						||
| 
								 | 
							
								            array_shift($args);
							 | 
						||
| 
								 | 
							
								            unset($args[0]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        $token = $this->context->get('CurrentToken', true);
							 | 
						||
| 
								 | 
							
								        $line  = $token ? $token->line : $this->context->get('CurrentLine', true);
							 | 
						||
| 
								 | 
							
								        $col   = $token ? $token->col  : $this->context->get('CurrentCol', true);
							 | 
						||
| 
								 | 
							
								        $attr  = $this->context->get('CurrentAttr', true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // perform special substitutions, also add custom parameters
							 | 
						||
| 
								 | 
							
								        $subst = array();
							 | 
						||
| 
								 | 
							
								        if (!is_null($token)) {
							 | 
						||
| 
								 | 
							
								            $args['CurrentToken'] = $token;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!is_null($attr)) {
							 | 
						||
| 
								 | 
							
								            $subst['$CurrentAttr.Name'] = $attr;
							 | 
						||
| 
								 | 
							
								            if (isset($token->attr[$attr])) {
							 | 
						||
| 
								 | 
							
								                $subst['$CurrentAttr.Value'] = $token->attr[$attr];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (empty($args)) {
							 | 
						||
| 
								 | 
							
								            $msg = $this->locale->getMessage($msg);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            $msg = $this->locale->formatMessage($msg, $args);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!empty($subst)) {
							 | 
						||
| 
								 | 
							
								            $msg = strtr($msg, $subst);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // (numerically indexed)
							 | 
						||
| 
								 | 
							
								        $error = array(
							 | 
						||
| 
								 | 
							
								            self::LINENO   => $line,
							 | 
						||
| 
								 | 
							
								            self::SEVERITY => $severity,
							 | 
						||
| 
								 | 
							
								            self::MESSAGE  => $msg,
							 | 
						||
| 
								 | 
							
								            self::CHILDREN => array()
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								        $this->_current[] = $error;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // NEW CODE BELOW ...
							 | 
						||
| 
								 | 
							
								        // Top-level errors are either:
							 | 
						||
| 
								 | 
							
								        //  TOKEN type, if $value is set appropriately, or
							 | 
						||
| 
								 | 
							
								        //  "syntax" type, if $value is null
							 | 
						||
| 
								 | 
							
								        $new_struct = new HTMLPurifier_ErrorStruct();
							 | 
						||
| 
								 | 
							
								        $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN;
							 | 
						||
| 
								 | 
							
								        if ($token) {
							 | 
						||
| 
								 | 
							
								            $new_struct->value = clone $token;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (is_int($line) && is_int($col)) {
							 | 
						||
| 
								 | 
							
								            if (isset($this->lines[$line][$col])) {
							 | 
						||
| 
								 | 
							
								                $struct = $this->lines[$line][$col];
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                $struct = $this->lines[$line][$col] = $new_struct;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            // These ksorts may present a performance problem
							 | 
						||
| 
								 | 
							
								            ksort($this->lines[$line], SORT_NUMERIC);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            if (isset($this->lines[-1])) {
							 | 
						||
| 
								 | 
							
								                $struct = $this->lines[-1];
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                $struct = $this->lines[-1] = $new_struct;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        ksort($this->lines, SORT_NUMERIC);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Now, check if we need to operate on a lower structure
							 | 
						||
| 
								 | 
							
								        if (!empty($attr)) {
							 | 
						||
| 
								 | 
							
								            $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr);
							 | 
						||
| 
								 | 
							
								            if (!$struct->value) {
							 | 
						||
| 
								 | 
							
								                $struct->value = array($attr, 'PUT VALUE HERE');
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!empty($cssprop)) {
							 | 
						||
| 
								 | 
							
								            $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop);
							 | 
						||
| 
								 | 
							
								            if (!$struct->value) {
							 | 
						||
| 
								 | 
							
								                // if we tokenize CSS this might be a little more difficult to do
							 | 
						||
| 
								 | 
							
								                $struct->value = array($cssprop, 'PUT VALUE HERE');
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Ok, structs are all setup, now time to register the error
							 | 
						||
| 
								 | 
							
								        $struct->addError($severity, $msg);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Retrieves raw error data for custom formatter to use
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public function getRaw()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return $this->errors;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Default HTML formatting implementation for error messages
							 | 
						||
| 
								 | 
							
								     * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature
							 | 
						||
| 
								 | 
							
								     * @param array $errors Errors array to display; used for recursion.
							 | 
						||
| 
								 | 
							
								     * @return string
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public function getHTMLFormatted($config, $errors = null)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        $ret = array();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        $this->generator = new HTMLPurifier_Generator($config, $this->context);
							 | 
						||
| 
								 | 
							
								        if ($errors === null) {
							 | 
						||
| 
								 | 
							
								            $errors = $this->errors;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // 'At line' message needs to be removed
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // generation code for new structure goes here. It needs to be recursive.
							 | 
						||
| 
								 | 
							
								        foreach ($this->lines as $line => $col_array) {
							 | 
						||
| 
								 | 
							
								            if ($line == -1) {
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            foreach ($col_array as $col => $struct) {
							 | 
						||
| 
								 | 
							
								                $this->_renderStruct($ret, $struct, $line, $col);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (isset($this->lines[-1])) {
							 | 
						||
| 
								 | 
							
								            $this->_renderStruct($ret, $this->lines[-1]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (empty($errors)) {
							 | 
						||
| 
								 | 
							
								            return '<p>' . $this->locale->getMessage('ErrorCollector: No errors') . '</p>';
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return '<ul><li>' . implode('</li><li>', $ret) . '</li></ul>';
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    private function _renderStruct(&$ret, $struct, $line = null, $col = null)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        $stack = array($struct);
							 | 
						||
| 
								 | 
							
								        $context_stack = array(array());
							 | 
						||
| 
								 | 
							
								        while ($current = array_pop($stack)) {
							 | 
						||
| 
								 | 
							
								            $context = array_pop($context_stack);
							 | 
						||
| 
								 | 
							
								            foreach ($current->errors as $error) {
							 | 
						||
| 
								 | 
							
								                list($severity, $msg) = $error;
							 | 
						||
| 
								 | 
							
								                $string = '';
							 | 
						||
| 
								 | 
							
								                $string .= '<div>';
							 | 
						||
| 
								 | 
							
								                // W3C uses an icon to indicate the severity of the error.
							 | 
						||
| 
								 | 
							
								                $error = $this->locale->getErrorName($severity);
							 | 
						||
| 
								 | 
							
								                $string .= "<span class=\"error e$severity\"><strong>$error</strong></span> ";
							 | 
						||
| 
								 | 
							
								                if (!is_null($line) && !is_null($col)) {
							 | 
						||
| 
								 | 
							
								                    $string .= "<em class=\"location\">Line $line, Column $col: </em> ";
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    $string .= '<em class="location">End of Document: </em> ';
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                $string .= '<strong class="description">' . $this->generator->escape($msg) . '</strong> ';
							 | 
						||
| 
								 | 
							
								                $string .= '</div>';
							 | 
						||
| 
								 | 
							
								                // Here, have a marker for the character on the column appropriate.
							 | 
						||
| 
								 | 
							
								                // Be sure to clip extremely long lines.
							 | 
						||
| 
								 | 
							
								                //$string .= '<pre>';
							 | 
						||
| 
								 | 
							
								                //$string .= '';
							 | 
						||
| 
								 | 
							
								                //$string .= '</pre>';
							 | 
						||
| 
								 | 
							
								                $ret[] = $string;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            foreach ($current->children as $array) {
							 | 
						||
| 
								 | 
							
								                $context[] = $current;
							 | 
						||
| 
								 | 
							
								                $stack = array_merge($stack, array_reverse($array, true));
							 | 
						||
| 
								 | 
							
								                for ($i = count($array); $i > 0; $i--) {
							 | 
						||
| 
								 | 
							
								                    $context_stack[] = $context;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// vim: et sw=4 sts=4
							 |