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 STRING = 1;
 | 
						|
    const ISTRING = 2;
 | 
						|
    const TEXT = 3;
 | 
						|
    const ITEXT = 4;
 | 
						|
    const INT = 5;
 | 
						|
    const FLOAT = 6;
 | 
						|
    const BOOL = 7;
 | 
						|
    const LOOKUP = 8;
 | 
						|
    const ALIST = 9;
 | 
						|
    const HASH = 10;
 | 
						|
    const 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::STRING,
 | 
						|
        'istring' => self::ISTRING,
 | 
						|
        'text' => self::TEXT,
 | 
						|
        'itext' => self::ITEXT,
 | 
						|
        'int' => self::INT,
 | 
						|
        'float' => self::FLOAT,
 | 
						|
        'bool' => self::BOOL,
 | 
						|
        'lookup' => self::LOOKUP,
 | 
						|
        'list' => self::ALIST,
 | 
						|
        'hash' => self::HASH,
 | 
						|
        'mixed' => self::MIXED
 | 
						|
    );
 | 
						|
 | 
						|
    /**
 | 
						|
     * Lookup table of types that are string, and can have aliases or
 | 
						|
     * allowed value lists.
 | 
						|
     */
 | 
						|
    public static $stringTypes = array(
 | 
						|
        self::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::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::INT):
 | 
						|
                if (!is_int($var)) {
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                return $var;
 | 
						|
            case (self::FLOAT):
 | 
						|
                if (!is_float($var)) {
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                return $var;
 | 
						|
            case (self::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::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
 |