VarParser.php 5.1 KB

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