Added a parameter to ISSO::unsanitize to force magic quotes to be off (which is neede...
[isso.git] / kernel.php
1 <?php
2 /*=====================================================================*\
3 || ################################################################### ||
4 || # Iris Studios Shared Object Framework [#]version[#]
5 || # --------------------------------------------------------------- # ||
6 || # All parts of this file are ©2003-[#]year[#] Iris Studios, Inc. No # ||
7 || # part of this file may be reproduced in any way: part or whole. # ||
8 || # --------------------------------------------------------------- # ||
9 || # ©2003 - [#]year[#] Iris Studios, Inc. | http://www.iris-studios.com # ||
10 || ################################################################### ||
11 \*=====================================================================*/
12
13 define('ERR_FATAL', E_USER_ERROR);
14 define('ERR_ALERT', E_USER_WARNING);
15 define('ERR_WARNING', E_USER_NOTICE);
16
17 if (PHP_VERSION < '4.1.0')
18 {
19 trigger_error('You need PHP version 4.1.0 or newer to run ISSO', ERR_FATAL);
20 exit;
21 }
22
23 if (PHP_VERSION > '5.0.0')
24 {
25 if (ini_get('error_reporting') & E_USER_NOTICE)
26 {
27 error_reporting(ini_get('error_reporting') - E_USER_NOTICE);
28 }
29 }
30
31 if (!(ini_get('error_reporting') & E_NOTICE))
32 {
33 error_reporting(ini_get('error_reporting') - E_USER_NOTICE);
34 }
35
36 if (!(ini_get('error_reporting') & E_WARNING))
37 {
38 error_reporting(ini_get('error_reporting') - E_USER_WARNING);
39 }
40
41 if (!(ini_get('error_reporting') & E_ERROR))
42 {
43 error_reporting(ini_get('error_reporting') - E_USER_ERROR);
44 }
45
46 if ((bool)ini_get('register_globals') === true)
47 {
48 $superglobals = array('_GET', '_COOKIE', '_FILES', '_POST', '_SERVER', '_ENV');
49 foreach ($superglobals AS $global)
50 {
51 if (is_array(${$global}))
52 {
53 foreach (${$global} AS $_key => $_val)
54 {
55 if (isset(${$_key}))
56 {
57 unset(${$_key});
58 }
59 }
60 }
61 }
62 }
63
64 /**
65 * Iris Studios Shared Object Framework (ISSO)
66 *
67 * This framework allows a common backend to be used amongst all Iris
68 * Studios applications and can is built to be abstract and flexible.
69 * The base framework handles all loading and module management.
70 *
71 * @author Iris Studios, Inc.
72 * @copyright Copyright ©2003 - [#]year[#], Iris Studios, Inc.
73 * @version $Revision$
74 *
75 */
76 class Shared_Object_Framework
77 {
78 /**
79 * Global environment variables
80 *
81 * This is where we keep the global variables that are used within the shared framework
82 *
83 * @var version ISSO version
84 * @var sourcepath The location of the framework sources
85 * @var appath The path to the application's location
86 * @var application The name of the application that is using the framework
87 * @var appversion The version of the application
88 * @var debug Variable for debug mode
89 * @var debuginfo Listing of all debug notices
90 * @var modules An array of loaded framework modules
91 * @var input All input data for the system
92 * @var i Short-hand reference to $isso::input
93 * @var in Short-hand reference to $isso::input
94 * @var magicquotes Status of Magic Quotes GPC
95 * @var escapestrings Sets whether or not we escape strings automatically
96 */
97 var $version = '[#]version[#]';
98 var $sourcepath = '';
99 var $apppath = '';
100 var $application = '';
101 var $appversion = '';
102 var $debug = false;
103 var $debuginfo = array();
104 var $modules = array();
105 var $input = array();
106 var $i = array();
107 var $in = array();
108 var $magicquotes = 0;
109 var $escapestrings = false;
110
111 /**
112 * Constructor
113 */
114 function Shared_Object_Framework()
115 {
116 // error reporting
117 set_error_handler(array(&$this, '_error_handler'));
118
119 // magic quotes
120 $this->magicquotes = get_magic_quotes_gpc();
121 set_magic_quotes_runtime(0);
122
123 if (defined('ISSO_ESCAPE_STRINGS'))
124 {
125 $this->escapestrings = (bool)constant('ISSO_ESCAPE_STRINGS');
126 }
127
128 // start input sanitize using variable_order GP
129 if (!$this->escapestrings)
130 {
131 $this->exec_sanitize_data();
132 }
133
134 $this->modules['kernel'] = 'Shared Object Framework Core';
135 }
136
137 /**
138 * Prepares a path for being set as the sourcepath
139 *
140 * @param str Source path or URL
141 *
142 * @return str Prepared source path
143 */
144 function fetch_sourcepath($source)
145 {
146 if (substr($source, strlen($source) - 1) != '/')
147 {
148 $source .= '/';
149 }
150 return $source;
151 }
152
153 /**
154 * Loads a framework extension
155 *
156 * @param str Name of the framework
157 */
158 function load($framework)
159 {
160 if (!$this->is_loaded($framework))
161 {
162 $newobj = $this->locate($framework);
163 $this->$newobj['OBJ'] = new $newobj['CLASS']();
164 $GLOBALS["$newobj[OBJ]"] =& $this->$newobj['OBJ'];
165 $this->modules["$framework"] = $newobj['OBJECT'];
166 }
167 }
168
169 /**
170 * Includes a framework module. Module definitions need three variables:
171 * class, object, and obj. Class is the name of the class, object is
172 * the name human-readable name, and obj is the name that the module
173 * should be initialized as; this is used in class extensions.
174 *
175 * @param str Name of the framework
176 *
177 * @return array List of initialization variables
178 */
179 function locate($framework)
180 {
181 if ($this->sourcepath == '')
182 {
183 trigger_error('Invalid sourcepath specified', ERR_FATAL);
184 }
185
186 if (file_exists($this->sourcepath . $framework . '.php'))
187 {
188 require_once($this->sourcepath . $framework . '.php');
189 return array('CLASS' => $CLASS, 'OBJECT' => $OBJECT, 'OBJ' => $OBJ);
190 }
191 else
192 {
193 trigger_error('Could not find the framework ' . $this->sourcepath . $framework . '.php', ERR_FATAL);
194 exit;
195 }
196 }
197
198 /**
199 * Prints a list of all currently loaded framework modules
200 *
201 * @param bool Return the data as an array?
202 *
203 * @return mixed HTML output or an array of loaded modules
204 */
205 function show_modules($return = false)
206 {
207 if ($return)
208 {
209 return $this->modules;
210 }
211 else
212 {
213 $output = "\n\n<ul>\n\t<li>";
214 $output .= implode("</li>\n\t<li>", $this->modules);
215 $output .= "</li>\n</ul>\n\n";
216 $this->_message('Loaded Modules', $output, 1);
217 }
218 }
219
220 /**
221 * Verifies to see if a framework has been loaded
222 *
223 * @param str Framework name
224 *
225 * @return bool Whether or not the framework has been loaded
226 */
227 function is_loaded($framework)
228 {
229 if (isset($this->modules["$framework"]))
230 {
231 return true;
232 }
233 else
234 {
235 return false;
236 }
237 }
238
239 /**
240 * Prints an ISSO message
241 *
242 * @param str The title of the message
243 * @param str The content of the message
244 * @param int Type of message to be printed
245 * @param bool Return the output?
246 *
247 * @return mixed Output or null
248 */
249 function _message($title, $message, $type, $return = false)
250 {
251 switch ($type)
252 {
253 // Message
254 case 1:
255 $prefix = 'Message';
256 $color = '#669900';
257 $font = '#000000';
258 break;
259
260 // Warning
261 case 2:
262 $prefix = 'Warning';
263 $color = '#003399';
264 $font = '#FFFFFF';
265 break;
266
267 case 3:
268 $prefix = 'Error';
269 $color = '#990000';
270 $font = '#EFEFEF';
271 break;
272 }
273
274 $output = "\n<br />\n<table cellpadding=\"4\" cellspacing=\"1\" border=\"0\" width=\"500\" style=\"background-color: $color; font-family: Verdana, sans-serif; font-size: 12px;\">";
275 $output .= "\n<tr style=\"color: $font\">\n\t<td><strong>$prefix: $title</strong></td>\n</tr>";
276 $output .= "\n<tr style=\"background-color: #FFFFFF\">\n\t<td>$message</td>\n</tr>\n</table>\n<br />\n";
277
278 if ($return)
279 {
280 return $output;
281 }
282 else
283 {
284 print($output);
285 }
286 }
287
288 /**
289 * Custom error handler for ISSO
290 *
291 * @param int Error number
292 * @param str Error message string
293 * @param str File that contains the error
294 * @param str The line number of the error
295 * @param str The active symbol table at which point the error occurred
296 */
297 function _error_handler($errno, $errstr, $errfile, $errline)
298 {
299 switch ($errno)
300 {
301 // Fatal
302 case ERR_FATAL:
303 $title = 'Fatal';
304 if (!(ini_get('error_reporting') & ERR_FATAL))
305 {
306 return;
307 }
308 break;
309
310 // Error
311 case ERR_ALERT:
312 $title = 'Alert';
313 if (!(ini_get('error_reporting') & ERR_ALERT))
314 {
315 return;
316 }
317 break;
318
319 // Warning
320 case ERR_WARNING:
321 default:
322 $title = 'Warning';
323 if (!(ini_get('error_reporting') & ERR_WARNING))
324 {
325 return;
326 }
327 break;
328 }
329
330 $errstr .= " in <strong>$errfile</strong> on line <strong>$errline</strong>";
331
332 $this->_message($title, $errstr, 3);
333
334 if ($errno == ERR_FATAL)
335 {
336 exit;
337 }
338 }
339
340 /**
341 * Logs a debug message for verbose output
342 *
343 * @param str Message
344 */
345 function debug($message)
346 {
347 if ($this->debug)
348 {
349 $this->debuginfo[] = $message;
350 }
351 }
352
353 /**
354 * Recursive XSS cleaner
355 *
356 * @param mixed Unsanitized REQUEST data
357 *
358 * @return mixed Sanitized data
359 */
360 function _sanitize_input_recursive($data)
361 {
362 foreach($data AS $key => $value)
363 {
364 if (is_array($value))
365 {
366 $data["$key"] = $this->_sanitize_input_recursive($value);
367 }
368 else
369 {
370 if ($this->escapestrings)
371 {
372 $data["$key"] = $this->escape($this->sanitize($value));
373 }
374 else
375 {
376 $data["$key"] = $this->sanitize($value);
377 }
378 }
379 }
380 return $data;
381 }
382
383 /**
384 * Simple way to protect against HTML attacks with Unicode support
385 *
386 * @param str Unsanitzed text
387 *
388 * @return str Properly protected text that only encodes potential threats
389 */
390 function sanitize($text)
391 {
392 if ($this->magicquotes)
393 {
394 return str_replace(array('<', '>', '\"', '"'), array('&lt;', '&gt;', '&quot;', '&quot;'), $text);
395 }
396 else
397 {
398 return str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $text);
399 }
400 }
401
402 /**
403 * Takes text that has been processed for HTML and unsanitizes it
404 *
405 * @param str Text that needs to be turned back into HTML
406 * @param bool Force magicquotes off
407 *
408 * @return str Unsanitized text
409 */
410 function unsanitize($text, $force = false)
411 {
412 if ($this->magicquotes AND !$force)
413 {
414 return str_replace(array('&lt;', '&gt;', '&quot;'), array('<', '>', '\"'), $text);
415 }
416 else
417 {
418 return str_replace(array('&lt;', '&gt;', '&quot;'), array('<', '>', '"'), $text);
419 }
420 }
421
422 /**
423 * Smart addslashes() that only applies itself it the Magic Quotes GPC is off
424 *
425 * @param str Some string
426 *
427 * @return str String that has slashes added
428 */
429 function escape($str)
430 {
431 global $_isso;
432
433 if ($this->magicquotes)
434 {
435 if (isset($_isso->db))
436 {
437 if (is_resource($_isso->db->link_id))
438 {
439 return $_isso->db->escape_string(stripslashes($str));
440 }
441 else
442 {
443 return $str;
444 }
445 }
446 else
447 {
448 return $str;
449 }
450 }
451 else
452 {
453 if (isset($_isso->db))
454 {
455 if (is_resource($_isso->db->link_id))
456 {
457 return $_isso->db->escape_string($str);
458 }
459 else
460 {
461 return addslashes($str);
462 }
463 }
464 else
465 {
466 return addslashes($str);
467 }
468 }
469 }
470
471 /**
472 * Runs through all of the input data and sanitizes it.
473 */
474 function exec_sanitize_data()
475 {
476 $this->input = $this->_sanitize_input_recursive(array_merge($_GET, $_POST));
477 $this->i =& $this->input;
478 $this->in =& $this->input;
479 // we're now using magic quotes
480 $this->magicquotes = 1;
481 }
482 }
483
484 /**
485 * Global callback used for module calls back to the kernel
486 */
487 $_isso = new Shared_Object_Framework();
488
489 /**
490 * Wrapper for ternary operator that has to be in the global scope
491 *
492 * @param expr Expression
493 * @param mixed If the expression is true
494 * @param mixed If the expression is false
495 *
496 * @return mixed True or false data
497 */
498 function iff($condition, $iftrue, $iffalse = null)
499 {
500 return ($condition) ? ($iftrue) : ($iffalse);
501 }
502
503 /*=====================================================================*\
504 || ###################################################################
505 || # $HeadURL$
506 || # $Id$
507 || ###################################################################
508 \*=====================================================================*/
509 ?>