]>
Commit | Line | Data |
---|---|---|
010efc9b AD |
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 | const STRING = 1; | |
11 | const ISTRING = 2; | |
12 | const TEXT = 3; | |
13 | const ITEXT = 4; | |
14 | const INT = 5; | |
15 | const FLOAT = 6; | |
16 | const BOOL = 7; | |
17 | const LOOKUP = 8; | |
18 | const ALIST = 9; | |
19 | const HASH = 10; | |
20 | const MIXED = 11; | |
21 | ||
22 | /** | |
23 | * Lookup table of allowed types. Mainly for backwards compatibility, but | |
24 | * also convenient for transforming string type names to the integer constants. | |
25 | */ | |
26 | static public $types = array( | |
27 | 'string' => self::STRING, | |
28 | 'istring' => self::ISTRING, | |
29 | 'text' => self::TEXT, | |
30 | 'itext' => self::ITEXT, | |
31 | 'int' => self::INT, | |
32 | 'float' => self::FLOAT, | |
33 | 'bool' => self::BOOL, | |
34 | 'lookup' => self::LOOKUP, | |
35 | 'list' => self::ALIST, | |
36 | 'hash' => self::HASH, | |
37 | 'mixed' => self::MIXED | |
38 | ); | |
39 | ||
40 | /** | |
41 | * Lookup table of types that are string, and can have aliases or | |
42 | * allowed value lists. | |
43 | */ | |
44 | static public $stringTypes = array( | |
45 | self::STRING => true, | |
46 | self::ISTRING => true, | |
47 | self::TEXT => true, | |
48 | self::ITEXT => true, | |
49 | ); | |
50 | ||
51 | /** | |
52 | * Validate a variable according to type. Throws | |
53 | * HTMLPurifier_VarParserException if invalid. | |
54 | * It may return NULL as a valid type if $allow_null is true. | |
55 | * | |
56 | * @param $var Variable to validate | |
57 | * @param $type Type of variable, see HTMLPurifier_VarParser->types | |
58 | * @param $allow_null Whether or not to permit null as a value | |
59 | * @return Validated and type-coerced variable | |
60 | */ | |
61 | final public function parse($var, $type, $allow_null = false) { | |
62 | if (is_string($type)) { | |
63 | if (!isset(HTMLPurifier_VarParser::$types[$type])) { | |
64 | throw new HTMLPurifier_VarParserException("Invalid type '$type'"); | |
65 | } else { | |
66 | $type = HTMLPurifier_VarParser::$types[$type]; | |
67 | } | |
68 | } | |
69 | $var = $this->parseImplementation($var, $type, $allow_null); | |
70 | if ($allow_null && $var === null) return null; | |
71 | // These are basic checks, to make sure nothing horribly wrong | |
72 | // happened in our implementations. | |
73 | switch ($type) { | |
74 | case (self::STRING): | |
75 | case (self::ISTRING): | |
76 | case (self::TEXT): | |
77 | case (self::ITEXT): | |
78 | if (!is_string($var)) break; | |
79 | if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var); | |
80 | return $var; | |
81 | case (self::INT): | |
82 | if (!is_int($var)) break; | |
83 | return $var; | |
84 | case (self::FLOAT): | |
85 | if (!is_float($var)) break; | |
86 | return $var; | |
87 | case (self::BOOL): | |
88 | if (!is_bool($var)) break; | |
89 | return $var; | |
90 | case (self::LOOKUP): | |
91 | case (self::ALIST): | |
92 | case (self::HASH): | |
93 | if (!is_array($var)) break; | |
94 | if ($type === self::LOOKUP) { | |
95 | foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); | |
96 | } elseif ($type === self::ALIST) { | |
97 | $keys = array_keys($var); | |
98 | if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); | |
99 | } | |
100 | return $var; | |
101 | case (self::MIXED): | |
102 | return $var; | |
103 | default: | |
104 | $this->errorInconsistent(get_class($this), $type); | |
105 | } | |
106 | $this->errorGeneric($var, $type); | |
107 | } | |
108 | ||
109 | /** | |
110 | * Actually implements the parsing. Base implementation is to not | |
111 | * do anything to $var. Subclasses should overload this! | |
112 | */ | |
113 | protected function parseImplementation($var, $type, $allow_null) { | |
114 | return $var; | |
115 | } | |
116 | ||
117 | /** | |
118 | * Throws an exception. | |
119 | */ | |
120 | protected function error($msg) { | |
121 | throw new HTMLPurifier_VarParserException($msg); | |
122 | } | |
123 | ||
124 | /** | |
125 | * Throws an inconsistency exception. | |
126 | * @note This should not ever be called. It would be called if we | |
127 | * extend the allowed values of HTMLPurifier_VarParser without | |
128 | * updating subclasses. | |
129 | */ | |
130 | protected function errorInconsistent($class, $type) { | |
131 | throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented"); | |
132 | } | |
133 | ||
134 | /** | |
135 | * Generic error for if a type didn't work. | |
136 | */ | |
137 | protected function errorGeneric($var, $type) { | |
138 | $vtype = gettype($var); | |
139 | $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype"); | |
140 | } | |
141 | ||
142 | static public function getTypeName($type) { | |
143 | static $lookup; | |
144 | if (!$lookup) { | |
145 | // Lazy load the alternative lookup table | |
146 | $lookup = array_flip(HTMLPurifier_VarParser::$types); | |
147 | } | |
148 | if (!isset($lookup[$type])) return 'unknown'; | |
149 | return $lookup[$type]; | |
150 | } | |
151 | ||
152 | } | |
153 | ||
154 | // vim: et sw=4 sts=4 |