Fixing "method not found" for BSApp::GetType()
[isso.git] / Input.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # Blue Static ISSO Framework
5 || # Copyright ©2002-[#]year[#] 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 [#]gpl[#] 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 * Constants:
78 * ISSO_CHECK_POST_REFERER - Will check to make sure that on POSTed
79 * data, the referer matches the host
80 *
81 * @author Blue Static
82 * @copyright Copyright ©2002 - [#]year[#], Blue Static
83 * @version $Revision$
84 * @package ISSO
85 *
86 */
87 class BSInput
88 {
89 /**
90 * An array of sanitized variables that have been cleaned for HTML tag openers and double quotes
91 * @var array
92 */
93 public $in = array();
94
95 /**
96 * If we are running with magic_quotes_gpc on or off
97 * @var int
98 */
99 private $magicquotes = 0;
100
101 // ###################################################################
102 /**
103 * Constructor: set instance variables and execute input cleaning
104 */
105 public function __construct()
106 {
107 // magic quotes
108 $this->magicquotes = get_magic_quotes_gpc();
109 set_magic_quotes_runtime(0);
110
111 // some debug info that's always useful
112 BSApp::Debug('magic_quotes_gpc = ' . $this->magicquotes);
113 BSApp::Debug('register_globals = ' . ini_get('register_globals'));
114
115 $this->_sanitizeInputData();
116
117 if (defined('ISSO_CHECK_POST_REFERER'))
118 {
119 $this->_checkPostReferer();
120 }
121 }
122
123 // ###################################################################
124 /**
125 * Recursive XSS cleaner
126 *
127 * @param mixed Unsanitized REQUEST data
128 *
129 * @return mixed Sanitized data
130 */
131 private function _sanitizeDataRecursive($data)
132 {
133 foreach ($data AS $key => $value)
134 {
135 if (is_array($value))
136 {
137 $data["$key"] = $this->_sanitizeDataRecursive($value);
138 }
139 else
140 {
141 if ($this->magicquotes)
142 {
143 $value = str_replace("\'", "'", $value);
144 }
145 $data["$key"] = $this->sanitize($value);
146 }
147 }
148 return $data;
149 }
150
151 // ###################################################################
152 /**
153 * Simple way to protect against HTML attacks with Unicode support
154 *
155 * @param string Unsanitzed text
156 *
157 * @return string Properly protected text that only encodes potential threats
158 */
159 public function sanitize($text)
160 {
161 if ($this->magicquotes)
162 {
163 return str_replace(array('<', '>', '\"', '"'), array('&lt;', '&gt;', '&quot;', '&quot;'), $text);
164 }
165 else
166 {
167 return str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $text);
168 }
169 }
170
171 // ###################################################################
172 /**
173 * Unicode-safe entity encoding system; similar to sanitize()
174 *
175 * @param string Unsanitized text
176 *
177 * @return string Unicode-safe sanitized text with entities preserved
178 */
179 public function entityEncode($text)
180 {
181 $text = str_replace('&', '&amp;', $text);
182 $text = $this->sanitize($text);
183 return $text;
184 }
185
186 // ###################################################################
187 /**
188 * Takes text that has been processed for HTML and unsanitizes it
189 *
190 * @param string Text that needs to be turned back into HTML
191 *
192 * @return string Unsanitized text
193 */
194 public function unsanitize($text)
195 {
196 return str_replace(array('&lt;', '&gt;', '&quot;'), array('<', '>', '"'), $text);
197 }
198
199 // ###################################################################
200 /**
201 * Smart addslashes() that only applies itself it the Magic Quotes GPC
202 * is off. This should only be run on database query values that come
203 * from ISSO->in[] input; data that needs sanitization should be run
204 * through Db->escapeString()
205 *
206 * @param string Some string
207 * @param bool Force magic quotes to be off
208 *
209 * @return string String that has slashes added
210 */
211 public function escape($str, $force = true)
212 {
213 $db = BSApp::Registry()->getType('Db');
214 if ($this->magicquotes AND !$force)
215 {
216 if ($db)
217 {
218 return $db->escapeString(str_replace(array("\'", '\"'), array("'", '"'), $str));
219 }
220 return $str;
221 }
222 else
223 {
224 if ($db)
225 {
226 return $db->escapeString($str);
227 }
228 return addslashes($str);
229 }
230 }
231
232 // ###################################################################
233 /**
234 * Runs through all of the input data and sanitizes it.
235 */
236 private function _sanitizeInputData()
237 {
238 $this->in = $this->_sanitizeDataRecursive(array_merge($_GET, $_POST, $_COOKIE));
239 }
240
241 // ###################################################################
242 /**
243 * Sanitize function for something other than a string (which
244 * everything is sanitized for if you use _sanitizeInputData(). Cleaned
245 * data is placed back into Input->in; this makes it so you don't have
246 * to constantly intval() [etc.] data.
247 *
248 * @param array Array of elements to clean as varname => type
249 */
250 public function inputCleanArray($vars)
251 {
252 foreach ($vars AS $varname => $type)
253 {
254 $this->inputClean($varname, $type);
255 }
256 }
257
258 // ###################################################################
259 /**
260 * Sanitize function that does a single variable as oppoesd to an array
261 * (see inputCleanArray() for more details)
262 *
263 * @param string Variable name in ISSO->in[]
264 * @param integer Sanitization type constant
265 */
266 public function inputClean($varname, $type)
267 {
268 if (isset($this->in["$varname"]))
269 {
270 $this->in["$varname"] = $this->clean($this->in["$varname"], $type);
271 }
272 else
273 {
274 $this->in["$varname"] = $this->clean(null, $type);
275 }
276
277 return $this->in["$varname"];
278 }
279
280 // ###################################################################
281 /**
282 * Runs Input->escape() on a variable on Input->in[]. This is just a
283 * short-hand wrapper so that queries can be shortened. When this is used,
284 * the actual value in Input->in[] is not changed, only the return value
285 * is escaped.
286 *
287 * @param string Input variable
288 *
289 * @return string Escaped input
290 */
291 public function inputEscape($varname)
292 {
293 if (isset($this->in["$varname"]))
294 {
295 return $this->escape($this->in["$varname"]);
296 }
297 else
298 {
299 return $this->escape(null);
300 }
301 }
302
303 // ###################################################################
304 /**
305 * Cleaning function that does the work for inputClean(); this is
306 * moved here so it can be used to clean things that aren't in
307 * Input->in[]
308 *
309 * @param mixed Data
310 * @param integer Sanitization type constant
311 *
312 * @return mixed Cleaned data
313 */
314 public function clean($value, $type)
315 {
316 if (is_array($value))
317 {
318 return $this->_cleanArray($value, $type);
319 }
320
321 if ($type == TYPE_INT)
322 {
323 $value = intval($value);
324 }
325 else if ($type == TYPE_UINT)
326 {
327 $value = (($val = intval($value)) < 0 ? 0 : $val);
328 }
329 else if ($type == TYPE_FLOAT)
330 {
331 $value = floatval($value);
332 }
333 else if ($type == TYPE_BOOL)
334 {
335 $value = (bool)$value;
336 }
337 else if ($type == TYPE_STR)
338 {
339 $value = $value;
340 }
341 else if ($type == TYPE_STRUN)
342 {
343 $value = $this->unsanitize($value);
344 }
345 else if ($type == TYPE_NONE)
346 {
347 if ($this->magicquotes)
348 {
349 $value = str_replace(array('\"', "\'"), array('"', "'"), $value);
350 }
351 else
352 {
353 $value = $value;
354 }
355 }
356 else if ($type == TYPE_BIN)
357 {
358 $value = $value;
359 }
360 else
361 {
362 throw new Exception('Invalid clean type specified in BSInput::clean()');
363 return;
364 }
365
366 return $value;
367 }
368
369 // ###################################################################
370 /**
371 * Recursion function for Input->clean()
372 *
373 * @param array Uncleaned array
374 * @param integer Sanitization type constant
375 *
376 * @return array Cleaned array of data
377 */
378 private function _cleanArray($array, $type)
379 {
380 foreach ($array AS $key => $value)
381 {
382 $array["$key"] = $this->clean($value, $type);
383 }
384
385 return $array;
386 }
387
388 // ###################################################################
389 /**
390 * Returns the lowercase version of the HTTP method (post or get)
391 *
392 * @return string HTTP method
393 */
394 public function getHttpMethod()
395 {
396 $method = strtolower($_SERVER['REQUEST_METHOD']);
397 if (!in_array($method, array('get', 'post')))
398 {
399 throw new Exception('Invalid server request method: ' . $method);
400 }
401 return $method;
402 }
403
404 // ###################################################################
405 /**
406 * Checks to see if a POST refer is actually from us
407 */
408 private function _checkPostReferer()
409 {
410 if ($this->getHttpMethod() == 'post')
411 {
412 $host = ($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_ENV['HTTP_HOST'];
413
414 if ($host AND $_SERVER['HTTP_REFERER'])
415 {
416 $parts = parse_url($_SERVER['HTTP_REFERER']);
417 $ourhost = $parts['host'] . (isset($parts['port']) ? ":$parts[port]" : '');
418
419 if ($ourhost != $host)
420 {
421 throw new Exception('No external hosts are allowed to POST to this application');
422 exit;
423 }
424 BSApp::Debug('remote post check = ok');
425 }
426 else
427 {
428 BSApp::Debug('remote post check = FAILED');
429 }
430 }
431 }
432 }
433
434 /*=====================================================================*\
435 || ###################################################################
436 || # $HeadURL$
437 || # $Id$
438 || ###################################################################
439 \*=====================================================================*/
440 ?>