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