You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.8 KiB
198 lines
5.8 KiB
<?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
|
|
|