Handle FastCGI situations where PATH_INFO is not available.
[hoplite.git] / http / input.php
1 <?php
2 // Hoplite
3 // Copyright (c) 2013 Blue Static
4 //
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 // more details.
13 //
14 // You should have received a copy of the GNU General Public License along with
15 // this program. If not, see <http://www.gnu.org/licenses/>.
16
17 namespace hoplite\http;
18
19 require_once HOPLITE_ROOT . '/base/filter.php';
20
21 /*!
22 The Input class is responsible for sanitizing data from untrusted incoming
23 HTTP requests.
24
25 This class was designed to be used either in a PHP 5.4 environment, or one in
26 which both magic_quotes (and all its flavors) and register_globals are Off.
27 */
28 class Input
29 {
30 /*! @const The raw input value, unsanitized and unsafe. */
31 const TYPE_RAW = 1;
32 /*! @const The value as a string with whitespace trimmed. */
33 const TYPE_STR = 2;
34 /*! @const The value as an integer. */
35 const TYPE_INT = 3;
36 /*! @const The value as an unsigned integer. */
37 const TYPE_UINT = 4;
38 /*! @const The value as a floating point number. */
39 const TYPE_FLOAT = 5;
40 /*! @const The string value parsed as a boolean expression. */
41 const TYPE_BOOL = 6;
42 /*! @const The string sanitized for HTML characters. */
43 const TYPE_HTML = 7;
44
45 /*! @const The $_REQUEST array. */
46 const SOURCE_REQUEST = 'r';
47 /*! @const The $_GET array. */
48 const SOURCE_GET = 'g';
49 /*! @const The $_POST array. */
50 const SOURCE_POST = 'p';
51 /*! @const The $_COOKIE array. */
52 const SOURCE_COOKIE = 'c';
53
54 /*! The sanitized input data. */
55 public $in = array();
56
57 /*!
58 The constructor for the input sanitizer class. By default, this will escape
59 all the data in _REQUEST into the ->in array using |$default_mode|.
60 */
61 public function __construct($default_mode = self::TYPE_STR)
62 {
63 if ($default_mode != self::TYPE_RAW) {
64 $this->in = $this->_CleanArray($_REQUEST, $default_mode);
65 }
66 }
67
68 /*!
69 Cleans a variable of a given type from the _REQUEST source and returns the
70 sanitized result. This is the most convenient way to access incoming data.
71 */
72 public function Clean($variable, $type)
73 {
74 return $this->InputClean(self::SOURCE_REQUEST, $variable, $type);
75 }
76
77 /*!
78 Convenience function that takes an array of variable => type pairs and
79 calls ::Clean() on each.
80 */
81 public function CleanArray($pairs)
82 {
83 $this->InputCleanArray(self::SOURCE_REQUEST, $pairs);
84 }
85
86 /*! @brief Fully qualified cleaning method.
87 This method will clean a variable in a specific source array to the
88 specified type.
89 */
90 public function InputClean($source, $variable, $type)
91 {
92 $global = $this->_GetSource($source);
93 $value = $this->SanitizeScalar($global["$variable"], $type);
94 $this->in["$variable"] = $value;
95 return $value;
96 }
97
98 /*! Convenience function like ::CleanArray but specifies the source array. */
99 public function InputCleanArray($source, $pairs)
100 {
101 foreach ($pairs as $variable => $type) {
102 $this->InputClean($source, $variable, $type);
103 }
104 }
105
106 /*! Recursive variant of ::InputClean. */
107 public function InputCleanDeep($source, $variable, $type)
108 {
109 $global = $this->_GetSource($source);
110 $array = $global["$variable"];
111 $this->in["$variable"] = $this->_CleanArray($array, $type);
112 return $this->in["$variable"];
113 }
114
115 private function _CleanArray($array, $type)
116 {
117 $out = array();
118 foreach ($array as $key => $value) {
119 if (is_array($value)) {
120 $out["$key"] = $this->_CleanArray($value, $type);
121 } else {
122 $out["$key"] = $this->SanitizeScalar($value, $type);
123 }
124 }
125 return $out;
126 }
127
128 /*!
129 Routine that transforms an unclean input to its cleaned output.
130 */
131 public function SanitizeScalar($in, $type)
132 {
133 if (is_array($in) || is_object($in))
134 throw new InputException('Cannot clean non-scalar value');
135
136 static $is_true = array('true', 'yes', 'y', '1');
137
138 switch ($type) {
139 case self::TYPE_RAW: return $in;
140 case self::TYPE_STR: return trim($in);
141 case self::TYPE_INT: return intval($in);
142 case self::TYPE_UINT: return ($data = intval($in)) < 0 ? 0 : $data;
143 case self::TYPE_FLOAT: return floatval($in);
144 case self::TYPE_BOOL: return in_array(strtolower(trim($in)), $is_true);
145 case self::TYPE_HTML: return \hoplite\base\filter\String($in);
146 default:
147 throw new InputException('Cannot clean scalar to unknown type ' . $type);
148 }
149 }
150
151 /*! Gets the source array associated with its short type. */
152 private function & _GetSource($source)
153 {
154 switch ($source) {
155 case self::SOURCE_REQUEST: return $_REQUEST;
156 case self::SOURCE_GET: return $_GET;
157 case self::SOURCE_POST: return $_POST;
158 case self::SOURCE_COOKIE: return $_COOKIE;
159 default:
160 throw new InputException('Unknown source array ' . $source);
161 }
162 }
163 }
164
165 class InputException extends \Exception {}