File indexing completed on 2024-12-22 05:36:22
0001 <?php 0002 0003 /** 0004 * Parses string representations into their corresponding native PHP 0005 * variable type. The base implementation does a simple type-check. 0006 */ 0007 class HTMLPurifier_VarParser 0008 { 0009 0010 const STRING = 1; 0011 const ISTRING = 2; 0012 const TEXT = 3; 0013 const ITEXT = 4; 0014 const INT = 5; 0015 const FLOAT = 6; 0016 const BOOL = 7; 0017 const LOOKUP = 8; 0018 const ALIST = 9; 0019 const HASH = 10; 0020 const MIXED = 11; 0021 0022 /** 0023 * Lookup table of allowed types. Mainly for backwards compatibility, but 0024 * also convenient for transforming string type names to the integer constants. 0025 */ 0026 public static $types = array( 0027 'string' => self::STRING, 0028 'istring' => self::ISTRING, 0029 'text' => self::TEXT, 0030 'itext' => self::ITEXT, 0031 'int' => self::INT, 0032 'float' => self::FLOAT, 0033 'bool' => self::BOOL, 0034 'lookup' => self::LOOKUP, 0035 'list' => self::ALIST, 0036 'hash' => self::HASH, 0037 'mixed' => self::MIXED 0038 ); 0039 0040 /** 0041 * Lookup table of types that are string, and can have aliases or 0042 * allowed value lists. 0043 */ 0044 public static $stringTypes = array( 0045 self::STRING => true, 0046 self::ISTRING => true, 0047 self::TEXT => true, 0048 self::ITEXT => true, 0049 ); 0050 0051 /** 0052 * Validate a variable according to type. 0053 * It may return NULL as a valid type if $allow_null is true. 0054 * 0055 * @param mixed $var Variable to validate 0056 * @param int $type Type of variable, see HTMLPurifier_VarParser->types 0057 * @param bool $allow_null Whether or not to permit null as a value 0058 * @return string Validated and type-coerced variable 0059 * @throws HTMLPurifier_VarParserException 0060 */ 0061 final public function parse($var, $type, $allow_null = false) 0062 { 0063 if (is_string($type)) { 0064 if (!isset(HTMLPurifier_VarParser::$types[$type])) { 0065 throw new HTMLPurifier_VarParserException("Invalid type '$type'"); 0066 } else { 0067 $type = HTMLPurifier_VarParser::$types[$type]; 0068 } 0069 } 0070 $var = $this->parseImplementation($var, $type, $allow_null); 0071 if ($allow_null && $var === null) { 0072 return null; 0073 } 0074 // These are basic checks, to make sure nothing horribly wrong 0075 // happened in our implementations. 0076 switch ($type) { 0077 case (self::STRING): 0078 case (self::ISTRING): 0079 case (self::TEXT): 0080 case (self::ITEXT): 0081 if (!is_string($var)) { 0082 break; 0083 } 0084 if ($type == self::ISTRING || $type == self::ITEXT) { 0085 $var = strtolower($var); 0086 } 0087 return $var; 0088 case (self::INT): 0089 if (!is_int($var)) { 0090 break; 0091 } 0092 return $var; 0093 case (self::FLOAT): 0094 if (!is_float($var)) { 0095 break; 0096 } 0097 return $var; 0098 case (self::BOOL): 0099 if (!is_bool($var)) { 0100 break; 0101 } 0102 return $var; 0103 case (self::LOOKUP): 0104 case (self::ALIST): 0105 case (self::HASH): 0106 if (!is_array($var)) { 0107 break; 0108 } 0109 if ($type === self::LOOKUP) { 0110 foreach ($var as $k) { 0111 if ($k !== true) { 0112 $this->error('Lookup table contains value other than true'); 0113 } 0114 } 0115 } elseif ($type === self::ALIST) { 0116 $keys = array_keys($var); 0117 if (array_keys($keys) !== $keys) { 0118 $this->error('Indices for list are not uniform'); 0119 } 0120 } 0121 return $var; 0122 case (self::MIXED): 0123 return $var; 0124 default: 0125 $this->errorInconsistent(get_class($this), $type); 0126 } 0127 $this->errorGeneric($var, $type); 0128 } 0129 0130 /** 0131 * Actually implements the parsing. Base implementation does not 0132 * do anything to $var. Subclasses should overload this! 0133 * @param mixed $var 0134 * @param int $type 0135 * @param bool $allow_null 0136 * @return string 0137 */ 0138 protected function parseImplementation($var, $type, $allow_null) 0139 { 0140 return $var; 0141 } 0142 0143 /** 0144 * Throws an exception. 0145 * @throws HTMLPurifier_VarParserException 0146 */ 0147 protected function error($msg) 0148 { 0149 throw new HTMLPurifier_VarParserException($msg); 0150 } 0151 0152 /** 0153 * Throws an inconsistency exception. 0154 * @note This should not ever be called. It would be called if we 0155 * extend the allowed values of HTMLPurifier_VarParser without 0156 * updating subclasses. 0157 * @param string $class 0158 * @param int $type 0159 * @throws HTMLPurifier_Exception 0160 */ 0161 protected function errorInconsistent($class, $type) 0162 { 0163 throw new HTMLPurifier_Exception( 0164 "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) . 0165 " not implemented" 0166 ); 0167 } 0168 0169 /** 0170 * Generic error for if a type didn't work. 0171 * @param mixed $var 0172 * @param int $type 0173 */ 0174 protected function errorGeneric($var, $type) 0175 { 0176 $vtype = gettype($var); 0177 $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype"); 0178 } 0179 0180 /** 0181 * @param int $type 0182 * @return string 0183 */ 0184 public static function getTypeName($type) 0185 { 0186 static $lookup; 0187 if (!$lookup) { 0188 // Lazy load the alternative lookup table 0189 $lookup = array_flip(HTMLPurifier_VarParser::$types); 0190 } 0191 if (!isset($lookup[$type])) { 0192 return 'unknown'; 0193 } 0194 return $lookup[$type]; 0195 } 0196 } 0197 0198 // vim: et sw=4 sts=4