Update version.php to 3.3.0
[isso.git] / Input.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # Blue Static ISSO Framework
5 || # Copyright (c)2005-2009 Iris Studios, Inc.
6 || #
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version 2 of the License.
10 || #
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 || # more details.
15 || #
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
21
22 /**
23 * Input sanitizer (Input.php)
24 *
25 * @package ISSO
26 */
27
28 /**#@+
29 * Input cleaning type constant
30 */
31 /**
32 * Integer type
33 */
34 define('TYPE_INT', 1);
35
36 /**
37 * Unsigned integer
38 */
39 define('TYPE_UINT', 2);
40
41 /**
42 * Float type
43 */
44 define('TYPE_FLOAT', 4);
45
46 /**
47 * Boolean type
48 */
49 define('TYPE_BOOL', 8);
50
51 /**
52 * String - cleaned
53 */
54 define('TYPE_STR', 16);
55
56 /**
57 * String - deliberate unclean
58 */
59 define('TYPE_STRUN', 32);
60
61 /**
62 * No cleaning - here for use in API
63 */
64 define('TYPE_NONE', 64);
65
66 /**
67 * Macro for using DB->escape_binary() without cleaning - used in API
68 */
69 define('TYPE_BIN', 128);
70 /**#@-*/
71
72 /**
73 * Input Sanitizer
74 *
75 * This class is responsible for cleaning input.
76 *
77 * @author Blue Static
78 * @copyright Copyright (c)2005 - 2009, Blue Static
79 * @package ISSO
80 *
81 */
82 class BSInput
83 {
84 /**
85 * An array of sanitized variables that have been cleaned for HTML tag openers and double quotes
86 * @var array
87 */
88 public $in = array();
89
90 /**
91 * If we are running with magic_quotes_gpc on or off
92 * @var int
93 */
94 private $magicquotes = 0;
95
96 /**
97 * Constructor: set instance variables and execute input cleaning
98 */
99 public function __construct()
100 {
101 // magic quotes
102 $this->magicquotes = get_magic_quotes_gpc();
103 set_magic_quotes_runtime(0);
104
105 // some debug info that's always useful
106 BSApp::debug('magic_quotes_gpc = ' . $this->magicquotes);
107 BSApp::debug('register_globals = ' . ini_get('register_globals'));
108
109 $this->_sanitizeInputData();
110 }
111
112 /**
113 * Recursive XSS cleaner
114 *
115 * @param mixed Unsanitized REQUEST data
116 *
117 * @return mixed Sanitized data
118 */
119 private function _sanitizeDataRecursive($data)
120 {
121 foreach ($data as $key => $value)
122 {
123 if (is_array($value))
124 {
125 $data["$key"] = $this->_sanitizeDataRecursive($value);
126 }
127 else
128 {
129 if ($this->magicquotes)
130 {
131 $value = str_replace("\'", "'", $value);
132 }
133 $data["$key"] = $this->sanitize($value);
134 }
135 }
136 return $data;
137 }
138
139 /**
140 * Simple way to protect against HTML attacks with Unicode support
141 *
142 * @param string Unsanitzed text
143 *
144 * @return string Properly protected text that only encodes potential threats
145 */
146 public function sanitize($text)
147 {
148 if ($this->magicquotes)
149 {
150 return str_replace(array('<', '>', '\"', '"'), array('&lt;', '&gt;', '&quot;', '&quot;'), $text);
151 }
152 else
153 {
154 return str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $text);
155 }
156 }
157
158 /**
159 * Unicode-safe entity encoding system; similar to sanitize()
160 *
161 * @param string Unsanitized text
162 *
163 * @return string Unicode-safe sanitized text with entities preserved
164 */
165 public function entityEncode($text)
166 {
167 $text = str_replace('&', '&amp;', $text);
168 $text = $this->sanitize($text);
169 return $text;
170 }
171
172 /**
173 * Takes text that has been processed for HTML and unsanitizes it
174 *
175 * @param string Text that needs to be turned back into HTML
176 *
177 * @return string Unsanitized text
178 */
179 public function unsanitize($text)
180 {
181 return str_replace(array('&lt;', '&gt;', '&quot;'), array('<', '>', '"'), $text);
182 }
183
184 /**
185 * Smart addslashes() that only applies itself it the Magic Quotes GPC
186 * is off. This should only be run on database query values that come
187 * from ISSO->in[] input; data that needs sanitization should be run
188 * through Db->escapeString()
189 *
190 * @param string Some string
191 * @param bool Force magic quotes to be off
192 *
193 * @return string String that has slashes added
194 */
195 public function escape($str, $force = true)
196 {
197 $db = BSApp::$db;
198 if ($this->magicquotes && !$force)
199 {
200 if ($db)
201 {
202 return $db->escapeString(str_replace(array("\'", '\"'), array("'", '"'), $str));
203 }
204 return $str;
205 }
206 else
207 {
208 if ($db)
209 {
210 return $db->escapeString($str);
211 }
212 return addslashes($str);
213 }
214 }
215
216 /**
217 * Runs through all of the input data and sanitizes it.
218 */
219 private function _sanitizeInputData()
220 {
221 $this->in = $this->_sanitizeDataRecursive(array_merge($_GET, $_POST, $_COOKIE));
222 }
223
224 /**
225 * Sanitize function for something other than a string (which
226 * everything is sanitized for if you use _sanitizeInputData(). Cleaned
227 * data is placed back into Input->in; this makes it so you don't have
228 * to constantly intval() [etc.] data.
229 *
230 * @param array Array of elements to clean as varname => type
231 */
232 public function inputCleanArray($vars)
233 {
234 foreach ($vars as $varname => $type)
235 {
236 $this->inputClean($varname, $type);
237 }
238 }
239
240 /**
241 * Sanitize function that does a single variable as oppoesd to an array
242 * (see inputCleanArray() for more details)
243 *
244 * @param string Variable name in ISSO->in[]
245 * @param integer Sanitization type constant
246 */
247 public function inputClean($varname, $type)
248 {
249 if (isset($this->in["$varname"]))
250 {
251 $this->in["$varname"] = $this->clean($this->in["$varname"], $type);
252 }
253 else
254 {
255 $this->in["$varname"] = $this->clean(null, $type);
256 }
257
258 return $this->in["$varname"];
259 }
260
261 /**
262 * Runs Input->escape() on a variable on Input->in[]. This is just a
263 * short-hand wrapper so that queries can be shortened. When this is used,
264 * the actual value in Input->in[] is not changed, only the return value
265 * is escaped.
266 *
267 * @param string Input variable
268 *
269 * @return string Escaped input
270 */
271 public function inputEscape($varname)
272 {
273 if (isset($this->in["$varname"]))
274 {
275 return $this->escape($this->in["$varname"]);
276 }
277 else
278 {
279 return $this->escape(null);
280 }
281 }
282
283 /**
284 * Cleaning function that does the work for inputClean(); this is
285 * moved here so it can be used to clean things that aren't in
286 * Input->in[]
287 *
288 * @param mixed Data
289 * @param integer Sanitization type constant
290 *
291 * @return mixed Cleaned data
292 */
293 public function clean($value, $type)
294 {
295 if (is_array($value))
296 {
297 return $this->_cleanArray($value, $type);
298 }
299
300 if ($type == TYPE_INT)
301 {
302 $value = intval($value);
303 }
304 else if ($type == TYPE_UINT)
305 {
306 $value = (($val = intval($value)) < 0 ? 0 : $val);
307 }
308 else if ($type == TYPE_FLOAT)
309 {
310 $value = floatval($value);
311 }
312 else if ($type == TYPE_BOOL)
313 {
314 $value = (bool)$value;
315 }
316 else if ($type == TYPE_STR)
317 {
318 $value = $value;
319 }
320 else if ($type == TYPE_STRUN)
321 {
322 $value = $this->unsanitize($value);
323 }
324 else if ($type == TYPE_NONE)
325 {
326 if ($this->magicquotes)
327 {
328 $value = str_replace(array('\"', "\'"), array('"', "'"), $value);
329 }
330 else
331 {
332 $value = $value;
333 }
334 }
335 else if ($type == TYPE_BIN)
336 {
337 $value = $value;
338 }
339 else
340 {
341 throw new Exception('Invalid clean type specified in BSInput::clean()');
342 return;
343 }
344
345 return $value;
346 }
347
348 /**
349 * Recursion function for Input->clean()
350 *
351 * @param array Uncleaned array
352 * @param integer Sanitization type constant
353 *
354 * @return array Cleaned array of data
355 */
356 private function _cleanArray($array, $type)
357 {
358 foreach ($array as $key => $value)
359 {
360 $array["$key"] = $this->clean($value, $type);
361 }
362
363 return $array;
364 }
365
366 /**
367 * Returns the lowercase version of the HTTP method (post or get)
368 *
369 * @return string HTTP method
370 */
371 public function getHttpMethod()
372 {
373 $method = strtolower($_SERVER['REQUEST_METHOD']);
374 if (!in_array($method, array('get', 'post')))
375 {
376 throw new Exception('Invalid server request method: ' . $method);
377 }
378 return $method;
379 }
380
381 /**
382 * Checks to see if a POST refer is actually from us
383 */
384 public function checkPostReferer()
385 {
386 if ($this->getHttpMethod() == 'post')
387 {
388 $host = ($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_ENV['HTTP_HOST'];
389
390 if ($host && $_SERVER['HTTP_REFERER'])
391 {
392 $parts = parse_url($_SERVER['HTTP_REFERER']);
393 $ourhost = $parts['host'] . (isset($parts['port']) ? ":$parts[port]" : '');
394
395 if ($ourhost != $host)
396 {
397 throw new Exception('No external hosts are allowed to POST to this application');
398 exit;
399 }
400 BSApp::debug('remote post check = ok');
401 }
402 else
403 {
404 BSApp::debug('remote post check = FAILED');
405 }
406 }
407 }
408 }
409
410 ?>