199 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			199 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
| 
								 | 
							
								<?php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Parses string representations into their corresponding native PHP
							 | 
						||
| 
								 | 
							
								 * variable type. The base implementation does a simple type-check.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class HTMLPurifier_VarParser
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const C_STRING = 1;
							 | 
						||
| 
								 | 
							
								    const ISTRING = 2;
							 | 
						||
| 
								 | 
							
								    const TEXT = 3;
							 | 
						||
| 
								 | 
							
								    const ITEXT = 4;
							 | 
						||
| 
								 | 
							
								    const C_INT = 5;
							 | 
						||
| 
								 | 
							
								    const C_FLOAT = 6;
							 | 
						||
| 
								 | 
							
								    const C_BOOL = 7;
							 | 
						||
| 
								 | 
							
								    const LOOKUP = 8;
							 | 
						||
| 
								 | 
							
								    const ALIST = 9;
							 | 
						||
| 
								 | 
							
								    const HASH = 10;
							 | 
						||
| 
								 | 
							
								    const C_MIXED = 11;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Lookup table of allowed types. Mainly for backwards compatibility, but
							 | 
						||
| 
								 | 
							
								     * also convenient for transforming string type names to the integer constants.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public static $types = array(
							 | 
						||
| 
								 | 
							
								        'string' => self::C_STRING,
							 | 
						||
| 
								 | 
							
								        'istring' => self::ISTRING,
							 | 
						||
| 
								 | 
							
								        'text' => self::TEXT,
							 | 
						||
| 
								 | 
							
								        'itext' => self::ITEXT,
							 | 
						||
| 
								 | 
							
								        'int' => self::C_INT,
							 | 
						||
| 
								 | 
							
								        'float' => self::C_FLOAT,
							 | 
						||
| 
								 | 
							
								        'bool' => self::C_BOOL,
							 | 
						||
| 
								 | 
							
								        'lookup' => self::LOOKUP,
							 | 
						||
| 
								 | 
							
								        'list' => self::ALIST,
							 | 
						||
| 
								 | 
							
								        'hash' => self::HASH,
							 | 
						||
| 
								 | 
							
								        'mixed' => self::C_MIXED
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Lookup table of types that are string, and can have aliases or
							 | 
						||
| 
								 | 
							
								     * allowed value lists.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public static $stringTypes = array(
							 | 
						||
| 
								 | 
							
								        self::C_STRING => true,
							 | 
						||
| 
								 | 
							
								        self::ISTRING => true,
							 | 
						||
| 
								 | 
							
								        self::TEXT => true,
							 | 
						||
| 
								 | 
							
								        self::ITEXT => true,
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Validate a variable according to type.
							 | 
						||
| 
								 | 
							
								     * It may return NULL as a valid type if $allow_null is true.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param mixed $var Variable to validate
							 | 
						||
| 
								 | 
							
								     * @param int $type Type of variable, see HTMLPurifier_VarParser->types
							 | 
						||
| 
								 | 
							
								     * @param bool $allow_null Whether or not to permit null as a value
							 | 
						||
| 
								 | 
							
								     * @return string Validated and type-coerced variable
							 | 
						||
| 
								 | 
							
								     * @throws HTMLPurifier_VarParserException
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    final public function parse($var, $type, $allow_null = false)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (is_string($type)) {
							 | 
						||
| 
								 | 
							
								            if (!isset(HTMLPurifier_VarParser::$types[$type])) {
							 | 
						||
| 
								 | 
							
								                throw new HTMLPurifier_VarParserException("Invalid type '$type'");
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                $type = HTMLPurifier_VarParser::$types[$type];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        $var = $this->parseImplementation($var, $type, $allow_null);
							 | 
						||
| 
								 | 
							
								        if ($allow_null && $var === null) {
							 | 
						||
| 
								 | 
							
								            return null;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        // These are basic checks, to make sure nothing horribly wrong
							 | 
						||
| 
								 | 
							
								        // happened in our implementations.
							 | 
						||
| 
								 | 
							
								        switch ($type) {
							 | 
						||
| 
								 | 
							
								            case (self::C_STRING):
							 | 
						||
| 
								 | 
							
								            case (self::ISTRING):
							 | 
						||
| 
								 | 
							
								            case (self::TEXT):
							 | 
						||
| 
								 | 
							
								            case (self::ITEXT):
							 | 
						||
| 
								 | 
							
								                if (!is_string($var)) {
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if ($type == self::ISTRING || $type == self::ITEXT) {
							 | 
						||
| 
								 | 
							
								                    $var = strtolower($var);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            case (self::C_INT):
							 | 
						||
| 
								 | 
							
								                if (!is_int($var)) {
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            case (self::C_FLOAT):
							 | 
						||
| 
								 | 
							
								                if (!is_float($var)) {
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            case (self::C_BOOL):
							 | 
						||
| 
								 | 
							
								                if (!is_bool($var)) {
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            case (self::LOOKUP):
							 | 
						||
| 
								 | 
							
								            case (self::ALIST):
							 | 
						||
| 
								 | 
							
								            case (self::HASH):
							 | 
						||
| 
								 | 
							
								                if (!is_array($var)) {
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if ($type === self::LOOKUP) {
							 | 
						||
| 
								 | 
							
								                    foreach ($var as $k) {
							 | 
						||
| 
								 | 
							
								                        if ($k !== true) {
							 | 
						||
| 
								 | 
							
								                            $this->error('Lookup table contains value other than true');
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                } elseif ($type === self::ALIST) {
							 | 
						||
| 
								 | 
							
								                    $keys = array_keys($var);
							 | 
						||
| 
								 | 
							
								                    if (array_keys($keys) !== $keys) {
							 | 
						||
| 
								 | 
							
								                        $this->error('Indices for list are not uniform');
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            case (self::C_MIXED):
							 | 
						||
| 
								 | 
							
								                return $var;
							 | 
						||
| 
								 | 
							
								            default:
							 | 
						||
| 
								 | 
							
								                $this->errorInconsistent(get_class($this), $type);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        $this->errorGeneric($var, $type);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Actually implements the parsing. Base implementation does not
							 | 
						||
| 
								 | 
							
								     * do anything to $var. Subclasses should overload this!
							 | 
						||
| 
								 | 
							
								     * @param mixed $var
							 | 
						||
| 
								 | 
							
								     * @param int $type
							 | 
						||
| 
								 | 
							
								     * @param bool $allow_null
							 | 
						||
| 
								 | 
							
								     * @return string
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected function parseImplementation($var, $type, $allow_null)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return $var;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Throws an exception.
							 | 
						||
| 
								 | 
							
								     * @throws HTMLPurifier_VarParserException
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected function error($msg)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        throw new HTMLPurifier_VarParserException($msg);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Throws an inconsistency exception.
							 | 
						||
| 
								 | 
							
								     * @note This should not ever be called. It would be called if we
							 | 
						||
| 
								 | 
							
								     *       extend the allowed values of HTMLPurifier_VarParser without
							 | 
						||
| 
								 | 
							
								     *       updating subclasses.
							 | 
						||
| 
								 | 
							
								     * @param string $class
							 | 
						||
| 
								 | 
							
								     * @param int $type
							 | 
						||
| 
								 | 
							
								     * @throws HTMLPurifier_Exception
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected function errorInconsistent($class, $type)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        throw new HTMLPurifier_Exception(
							 | 
						||
| 
								 | 
							
								            "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) .
							 | 
						||
| 
								 | 
							
								            " not implemented"
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Generic error for if a type didn't work.
							 | 
						||
| 
								 | 
							
								     * @param mixed $var
							 | 
						||
| 
								 | 
							
								     * @param int $type
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    protected function errorGeneric($var, $type)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        $vtype = gettype($var);
							 | 
						||
| 
								 | 
							
								        $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @param int $type
							 | 
						||
| 
								 | 
							
								     * @return string
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    public static function getTypeName($type)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        static $lookup;
							 | 
						||
| 
								 | 
							
								        if (!$lookup) {
							 | 
						||
| 
								 | 
							
								            // Lazy load the alternative lookup table
							 | 
						||
| 
								 | 
							
								            $lookup = array_flip(HTMLPurifier_VarParser::$types);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!isset($lookup[$type])) {
							 | 
						||
| 
								 | 
							
								            return 'unknown';
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return $lookup[$type];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// vim: et sw=4 sts=4
							 |