blob: 2b8ad26b1a0347863cc4dd82f9f30683a48f038f [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
Derek Jones7f3719f2010-01-05 13:35:37 +00009 * @copyright Copyright (c) 2008 - 2010, EllisLab, Inc.
Derek Allard2067d1a2008-11-13 22:59:24 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060019 * Common Functions
20 *
21 * Loads the base classes and executes the request.
22 *
23 * @package CodeIgniter
24 * @subpackage codeigniter
25 * @category Common Functions
26 * @author ExpressionEngine Dev Team
27 * @link http://codeigniter.com/user_guide/
28 */
29
30// ------------------------------------------------------------------------
31
32/**
Derek Jones086ee5a2009-07-28 14:42:12 +000033* Determines if the current version of PHP is greater then the supplied value
34*
35* Since there are a few places where we conditionally test for PHP > 5
36* we'll set a static variable.
37*
38* @access public
Derek Jones77b513b2009-08-06 14:39:25 +000039* @param string
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060040* @return bool TRUE if the current version is $version or higher
Derek Jones086ee5a2009-07-28 14:42:12 +000041*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060042 function is_php($version = '5.0.0')
Derek Jones086ee5a2009-07-28 14:42:12 +000043 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060044 static $_is_php;
45 $version = (string)$version;
46
47 if ( ! isset($_is_php[$version]))
48 {
49 $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE;
50 }
Derek Jones086ee5a2009-07-28 14:42:12 +000051
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060052 return $_is_php[$version];
53 }
Derek Jones5bcfd2e2009-07-28 14:42:42 +000054
Derek Jones086ee5a2009-07-28 14:42:12 +000055// ------------------------------------------------------------------------
56
57/**
Derek Allard2067d1a2008-11-13 22:59:24 +000058 * Tests for file writability
59 *
60 * is_writable() returns TRUE on Windows servers when you really can't write to
61 * the file, based on the read-only attribute. is_writable() is also unreliable
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060062 * on Unix servers if safe_mode is on.
Derek Allard2067d1a2008-11-13 22:59:24 +000063 *
64 * @access private
65 * @return void
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060066 */
67 function is_really_writable($file)
Derek Allard2067d1a2008-11-13 22:59:24 +000068 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060069 // If we're on a Unix server with safe_mode off we call is_writable
70 if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE)
71 {
72 return is_writable($file);
73 }
Derek Allard2067d1a2008-11-13 22:59:24 +000074
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060075 // For windows servers and safe_mode "on" installations we'll actually
76 // write a file then read it. Bah...
77 if (is_dir($file))
78 {
79 $file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100));
Derek Allard2067d1a2008-11-13 22:59:24 +000080
Derek Jonesdc8e9ea2010-03-02 13:17:19 -060081 if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
82 {
83 return FALSE;
84 }
85
86 fclose($fp);
87 @chmod($file, DIR_WRITE_MODE);
88 @unlink($file);
89 return TRUE;
90 }
91 elseif (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000092 {
93 return FALSE;
94 }
95
96 fclose($fp);
Derek Allard2067d1a2008-11-13 22:59:24 +000097 return TRUE;
98 }
Derek Allard2067d1a2008-11-13 22:59:24 +000099
100// ------------------------------------------------------------------------
101
102/**
103* Class registry
104*
105* This function acts as a singleton. If the requested class does not
106* exist it is instantiated and set to a static variable. If it has
107* previously been instantiated the variable is returned.
108*
109* @access public
110* @param string the class name being requested
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600111* @param string the directory where the class should be found
112* @param string the class name prefix
Derek Allard2067d1a2008-11-13 22:59:24 +0000113* @return object
114*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600115 function &load_class($class, $directory = 'libraries', $prefix = 'CI_')
Derek Allard2067d1a2008-11-13 22:59:24 +0000116 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600117 static $_classes = array();
118
119 // Does the class exist? If so, we're done...
120 if (isset($_classes[$class]))
Derek Allard2067d1a2008-11-13 22:59:24 +0000121 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600122 return $_classes[$class];
Derek Allard2067d1a2008-11-13 22:59:24 +0000123 }
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600124
125 $name = FALSE;
126
127 // Look for the class first in the native system/libraries folder
128 // thenin the local application/libraries folder
129 foreach (array(BASEPATH, APPPATH) as $path)
130 {
131 if (file_exists($path.$directory.'/'.$class.EXT))
132 {
133 $name = $prefix.$class;
134
135 if (class_exists($name) === FALSE)
136 {
137 require($path.$directory.'/'.$class.EXT);
138 }
139
140 break;
141 }
142 }
143
144 // Is the request a class extension? If so we load it too
Phil Sturgeon3140ad52010-03-12 00:22:42 +0000145 if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.EXT))
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600146 {
147 $name = config_item('subclass_prefix').$class;
148
149 if (class_exists($name) === FALSE)
150 {
Phil Sturgeon3140ad52010-03-12 00:22:42 +0000151 require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.EXT);
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600152 }
153 }
154
155 // Did we find the class?
156 if ($name === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000157 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600158 // Note: We use exit() rather then show_error() in order to avoid a
159 // self-referencing loop with the Excptions class
160 exit('Unable to locate the specified class: '.$class.EXT);
Derek Allard2067d1a2008-11-13 22:59:24 +0000161 }
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600162
163 // Keep track of what we just loaded
164 is_loaded($class);
165
166 $_classes[$class] =& instantiate_class(new $name());
167 return $_classes[$class];
Derek Allard2067d1a2008-11-13 22:59:24 +0000168 }
169
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600170// ------------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000171
172/**
Derek Jonesf0a9b332009-07-29 14:19:18 +0000173 * Instantiate Class
174 *
175 * Returns a new class object by reference, used by load_class() and the DB class.
176 * Required to retain PHP 4 compatibility and also not make PHP 5.3 cry.
177 *
178 * Use: $obj =& instantiate_class(new Foo());
179 *
180 * @access public
181 * @param object
182 * @return object
183 */
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600184 function &instantiate_class(&$class_object)
185 {
186 return $class_object;
187 }
188
189// --------------------------------------------------------------------
190
191/**
192* Keeps track of which libraries have been loaded. This function is
193* called by the load_class() function above
194*
195* @access public
196* @return array
197*/
198 function is_loaded($class = '')
199 {
200 static $_is_loaded = array();
201
202 if ($class != '')
203 {
204 $_is_loaded[strtolower($class)] = $class;
205 }
206
207 return $_is_loaded;
208 }
209
210// ------------------------------------------------------------------------
Derek Jonesf0a9b332009-07-29 14:19:18 +0000211
212/**
Derek Allard2067d1a2008-11-13 22:59:24 +0000213* Loads the main config.php file
214*
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600215* This function lets us grab the config file even if the Config class
216* hasn't been instantiated yet
217*
Derek Allard2067d1a2008-11-13 22:59:24 +0000218* @access private
219* @return array
220*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600221 function &get_config($replace = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000222 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600223 static $_config;
224
225 if (isset($_config))
226 {
227 return $_config[0];
228 }
229
230 // Fetch the config file
Derek Allard2067d1a2008-11-13 22:59:24 +0000231 if ( ! file_exists(APPPATH.'config/config'.EXT))
232 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600233 exit('The configuration file does not exist.');
234 }
235 else
236 {
237 require(APPPATH.'config/config'.EXT);
Derek Allard2067d1a2008-11-13 22:59:24 +0000238 }
239
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600240 // Does the $config array exist in the file?
Derek Allard2067d1a2008-11-13 22:59:24 +0000241 if ( ! isset($config) OR ! is_array($config))
242 {
243 exit('Your config file does not appear to be formatted correctly.');
244 }
245
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600246 // Are any values being dynamically replaced?
247 if (count($replace) > 0)
248 {
249 foreach ($replace as $key => $val)
250 {
251 if (isset($config[$key]))
252 {
253 $config[$key] = $val;
254 }
255 }
256 }
257
258 return $_config[0] =& $config;
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 }
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600260
261// ------------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000262
263/**
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600264* Returns the specified config item
Derek Allard2067d1a2008-11-13 22:59:24 +0000265*
266* @access public
267* @return mixed
268*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600269 function config_item($item)
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600271 static $_config_item = array();
272
273 if ( ! isset($_config_item[$item]))
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600275 $config =& get_config();
276
277 if ( ! isset($config[$item]))
278 {
279 return FALSE;
280 }
281 $_config_item[$item] = $config[$item];
Derek Allard2067d1a2008-11-13 22:59:24 +0000282 }
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600283
284 return $_config_item[$item];
Derek Allard2067d1a2008-11-13 22:59:24 +0000285 }
286
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600287// ------------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000288
289/**
290* Error Handler
291*
292* This function lets us invoke the exception class and
293* display errors using the standard error template located
294* in application/errors/errors.php
295* This function will send the error page directly to the
296* browser and exit.
297*
298* @access public
299* @return void
300*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600301 function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
302 {
303 $_error =& load_class('Exceptions', 'core');
304 echo $_error->show_error($heading, $message, 'error_general', $status_code);
305 exit;
306 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000307
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600308// ------------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000309
310/**
311* 404 Page Handler
312*
313* This function is similar to the show_error() function above
314* However, instead of the standard error template it displays
315* 404 errors.
316*
317* @access public
318* @return void
319*/
Derek Allard2ddc9492010-08-05 10:08:33 -0400320 function show_404($page = '', $log_error = TRUE)
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600321 {
322 $_error =& load_class('Exceptions', 'core');
Derek Allard2ddc9492010-08-05 10:08:33 -0400323 $_error->show_404($page, $log_error);
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600324 exit;
325 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000326
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600327// ------------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +0000328
329/**
330* Error Logging Interface
331*
332* We use this as a simple mechanism to access the logging
333* class and send messages to be logged.
334*
335* @access public
336* @return void
337*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600338 function log_message($level = 'error', $message, $php_error = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000339 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600340 static $_log;
341
342 if (config_item('log_threshold') == 0)
343 {
344 return;
345 }
346
347 $_log =& load_class('Log');
348 $_log->write_log($level, $message, $php_error);
Derek Allard2067d1a2008-11-13 22:59:24 +0000349 }
350
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600351// ------------------------------------------------------------------------
Derek Jones817163a2009-07-11 17:05:58 +0000352
353/**
354 * Set HTTP Status Header
355 *
356 * @access public
357 * @param int the status code
358 * @param string
359 * @return void
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600360 */
361 function set_status_header($code = 200, $text = '')
Derek Jones817163a2009-07-11 17:05:58 +0000362 {
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600363 $stati = array(
364 200 => 'OK',
365 201 => 'Created',
366 202 => 'Accepted',
367 203 => 'Non-Authoritative Information',
368 204 => 'No Content',
369 205 => 'Reset Content',
370 206 => 'Partial Content',
Derek Jones817163a2009-07-11 17:05:58 +0000371
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600372 300 => 'Multiple Choices',
373 301 => 'Moved Permanently',
374 302 => 'Found',
375 304 => 'Not Modified',
376 305 => 'Use Proxy',
377 307 => 'Temporary Redirect',
378
379 400 => 'Bad Request',
380 401 => 'Unauthorized',
381 403 => 'Forbidden',
382 404 => 'Not Found',
383 405 => 'Method Not Allowed',
384 406 => 'Not Acceptable',
385 407 => 'Proxy Authentication Required',
386 408 => 'Request Timeout',
387 409 => 'Conflict',
388 410 => 'Gone',
389 411 => 'Length Required',
390 412 => 'Precondition Failed',
391 413 => 'Request Entity Too Large',
392 414 => 'Request-URI Too Long',
393 415 => 'Unsupported Media Type',
394 416 => 'Requested Range Not Satisfiable',
395 417 => 'Expectation Failed',
396
397 500 => 'Internal Server Error',
398 501 => 'Not Implemented',
399 502 => 'Bad Gateway',
400 503 => 'Service Unavailable',
401 504 => 'Gateway Timeout',
402 505 => 'HTTP Version Not Supported'
403 );
404
405 if ($code == '' OR ! is_numeric($code))
406 {
407 show_error('Status codes must be numeric', 500);
408 }
409
410 if (isset($stati[$code]) AND $text == '')
411 {
412 $text = $stati[$code];
413 }
414
415 if ($text == '')
416 {
417 show_error('No status text available. Please check your status code number or supply your own message text.', 500);
418 }
419
420 $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
421
422 if (substr(php_sapi_name(), 0, 3) == 'cgi')
423 {
424 header("Status: {$code} {$text}", TRUE);
425 }
426 elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0')
427 {
428 header($server_protocol." {$code} {$text}", TRUE, $code);
429 }
430 else
431 {
432 header("HTTP/1.1 {$code} {$text}", TRUE, $code);
433 }
Derek Jones817163a2009-07-11 17:05:58 +0000434 }
435
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600436// --------------------------------------------------------------------
Derek Jones817163a2009-07-11 17:05:58 +0000437
Derek Allard2067d1a2008-11-13 22:59:24 +0000438/**
439* Exception Handler
440*
441* This is the custom exception handler that is declaired at the top
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600442* of Codeigniter.php. The main reason we use this is to permit
443* PHP errors to be logged in our own log files since the user may
Derek Allard2067d1a2008-11-13 22:59:24 +0000444* not have access to server logs. Since this function
445* effectively intercepts PHP errors, however, we also need
446* to display errors based on the current error_reporting level.
447* We do that with the use of a PHP error template.
448*
449* @access private
450* @return void
451*/
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600452 function _exception_handler($severity, $message, $filepath, $line)
453 {
454 // We don't bother with "strict" notices since they tend to fill up
455 // the log file with excess information that isn't normally very helpful.
456 // For example, if you are running PHP 5 and you use version 4 style
457 // class functions (without prefixes like "public", "private", etc.)
458 // you'll get notices telling you that these have been deprecated.
459 if ($severity == E_STRICT)
460 {
461 return;
462 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000463
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600464 $_error =& load_class('Exceptions', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +0000465
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600466 // Should we display the error? We'll get the current error_reporting
467 // level and add its bits with the severity bits to find out.
468 if (($severity & error_reporting()) == $severity)
469 {
470 $_error->show_php_error($severity, $message, $filepath, $line);
471 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000472
Derek Jonesdc8e9ea2010-03-02 13:17:19 -0600473 // Should we log the error? No? We're done...
474 if (config_item('log_threshold') == 0)
475 {
476 return;
477 }
478
479 $_error->log_exception($severity, $message, $filepath, $line);
480 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000481
Greg Aker757dda62010-04-14 19:06:19 -0500482 // --------------------------------------------------------------------
483
484 /**
485 * Remove Invisible Characters
486 *
487 * This prevents sandwiching null characters
488 * between ascii characters, like Java\0script.
489 *
490 * @access public
491 * @param string
492 * @return string
493 */
494 function remove_invisible_characters($str)
495 {
496 static $non_displayables;
497
498 if ( ! isset($non_displayables))
499 {
500 // every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09),
501 $non_displayables = array(
502 '/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15
503 '/%1[0-9a-f]/', // url encoded 16-31
504 '/[\x00-\x08]/', // 00-08
505 '/\x0b/', '/\x0c/', // 11, 12
506 '/[\x0e-\x1f]/' // 14-31
507 );
508 }
509
510 do
511 {
512 $cleaned = $str;
513 $str = preg_replace($non_displayables, '', $str);
514 }
515 while ($cleaned != $str);
516
517 return $str;
518 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000519
520
521/* End of file Common.php */
Derek Jonesc68dfbf2010-03-02 12:59:23 -0600522/* Location: ./system/core/Common.php */