| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | /** |
|---|
| 4 | * Parses string representations into their corresponding native PHP |
|---|
| 5 | * variable type. The base implementation does a simple type-check. |
|---|
| 6 | */ |
|---|
| 7 | class HTMLPurifier_VarParser |
|---|
| 8 | { |
|---|
| 9 | |
|---|
| 10 | /** |
|---|
| 11 | * Lookup table of allowed types. |
|---|
| 12 | */ |
|---|
| 13 | static public $types = array( |
|---|
| 14 | 'string' => true, |
|---|
| 15 | 'istring' => true, |
|---|
| 16 | 'text' => true, |
|---|
| 17 | 'itext' => true, |
|---|
| 18 | 'int' => true, |
|---|
| 19 | 'float' => true, |
|---|
| 20 | 'bool' => true, |
|---|
| 21 | 'lookup' => true, |
|---|
| 22 | 'list' => true, |
|---|
| 23 | 'hash' => true, |
|---|
| 24 | 'mixed' => true |
|---|
| 25 | ); |
|---|
| 26 | |
|---|
| 27 | /** |
|---|
| 28 | * Lookup table of types that are string, and can have aliases or |
|---|
| 29 | * allowed value lists. |
|---|
| 30 | */ |
|---|
| 31 | static public $stringTypes = array( |
|---|
| 32 | 'string' => true, |
|---|
| 33 | 'istring' => true, |
|---|
| 34 | 'text' => true, |
|---|
| 35 | 'itext' => true, |
|---|
| 36 | ); |
|---|
| 37 | |
|---|
| 38 | /** |
|---|
| 39 | * Validate a variable according to type. Throws |
|---|
| 40 | * HTMLPurifier_VarParserException if invalid. |
|---|
| 41 | * It may return NULL as a valid type if $allow_null is true. |
|---|
| 42 | * |
|---|
| 43 | * @param $var Variable to validate |
|---|
| 44 | * @param $type Type of variable, see HTMLPurifier_VarParser->types |
|---|
| 45 | * @param $allow_null Whether or not to permit null as a value |
|---|
| 46 | * @return Validated and type-coerced variable |
|---|
| 47 | */ |
|---|
| 48 | final public function parse($var, $type, $allow_null = false) { |
|---|
| 49 | if (!isset(HTMLPurifier_VarParser::$types[$type])) { |
|---|
| 50 | throw new HTMLPurifier_VarParserException("Invalid type '$type'"); |
|---|
| 51 | } |
|---|
| 52 | $var = $this->parseImplementation($var, $type, $allow_null); |
|---|
| 53 | if ($allow_null && $var === null) return null; |
|---|
| 54 | // These are basic checks, to make sure nothing horribly wrong |
|---|
| 55 | // happened in our implementations. |
|---|
| 56 | switch ($type) { |
|---|
| 57 | case 'string': |
|---|
| 58 | case 'istring': |
|---|
| 59 | case 'text': |
|---|
| 60 | case 'itext': |
|---|
| 61 | if (!is_string($var)) break; |
|---|
| 62 | if ($type[0] == 'i') $var = strtolower($var); |
|---|
| 63 | return $var; |
|---|
| 64 | case 'int': |
|---|
| 65 | if (!is_int($var)) break; |
|---|
| 66 | return $var; |
|---|
| 67 | case 'float': |
|---|
| 68 | if (!is_float($var)) break; |
|---|
| 69 | return $var; |
|---|
| 70 | case 'bool': |
|---|
| 71 | if (!is_bool($var)) break; |
|---|
| 72 | return $var; |
|---|
| 73 | case 'lookup': |
|---|
| 74 | case 'list': |
|---|
| 75 | case 'hash': |
|---|
| 76 | if (!is_array($var)) break; |
|---|
| 77 | if ($type === 'lookup') { |
|---|
| 78 | foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); |
|---|
| 79 | } elseif ($type === 'list') { |
|---|
| 80 | $keys = array_keys($var); |
|---|
| 81 | if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); |
|---|
| 82 | } |
|---|
| 83 | return $var; |
|---|
| 84 | case 'mixed': |
|---|
| 85 | return $var; |
|---|
| 86 | default: |
|---|
| 87 | $this->errorInconsistent(get_class($this), $type); |
|---|
| 88 | } |
|---|
| 89 | $this->errorGeneric($var, $type); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | /** |
|---|
| 93 | * Actually implements the parsing. Base implementation is to not |
|---|
| 94 | * do anything to $var. Subclasses should overload this! |
|---|
| 95 | */ |
|---|
| 96 | protected function parseImplementation($var, $type, $allow_null) { |
|---|
| 97 | return $var; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | /** |
|---|
| 101 | * Throws an exception. |
|---|
| 102 | */ |
|---|
| 103 | protected function error($msg) { |
|---|
| 104 | throw new HTMLPurifier_VarParserException($msg); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | /** |
|---|
| 108 | * Throws an inconsistency exception. |
|---|
| 109 | * @note This should not ever be called. It would be called if we |
|---|
| 110 | * extend the allowed values of HTMLPurifier_VarParser without |
|---|
| 111 | * updating subclasses. |
|---|
| 112 | */ |
|---|
| 113 | protected function errorInconsistent($class, $type) { |
|---|
| 114 | throw new HTMLPurifier_Exception("Inconsistency in $class: $type not implemented"); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | /** |
|---|
| 118 | * Generic error for if a type didn't work. |
|---|
| 119 | */ |
|---|
| 120 | protected function errorGeneric($var, $type) { |
|---|
| 121 | $vtype = gettype($var); |
|---|
| 122 | $this->error("Expected type $type, got $vtype"); |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | } |
|---|