PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/system/core/CodeIgniter.php

http://github.com/EllisLab/CodeIgniter
PHP | 508 lines | 191 code | 50 blank | 267 comment | 26 complexity | 517b244f7221a95957c6ec5ed588ede9 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2019, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
  33. * @license https://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * System Initialization File
  41. *
  42. * Loads the base classes and executes the request.
  43. *
  44. * @package CodeIgniter
  45. * @subpackage CodeIgniter
  46. * @category Front-controller
  47. * @author EllisLab Dev Team
  48. * @link https://codeigniter.com/userguide3/
  49. */
  50. /**
  51. * CodeIgniter Version
  52. *
  53. * @var string
  54. *
  55. */
  56. const CI_VERSION = '3.2.0-dev';
  57. /*
  58. * ------------------------------------------------------
  59. * Load the framework constants
  60. * ------------------------------------------------------
  61. */
  62. if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
  63. {
  64. require_once(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
  65. }
  66. if (file_exists(APPPATH.'config/constants.php'))
  67. {
  68. require_once(APPPATH.'config/constants.php');
  69. }
  70. /*
  71. * ------------------------------------------------------
  72. * Load the global functions
  73. * ------------------------------------------------------
  74. */
  75. require_once(BASEPATH.'core/Common.php');
  76. /*
  77. * ------------------------------------------------------
  78. * Define a custom error handler so we can log PHP errors
  79. * ------------------------------------------------------
  80. */
  81. set_error_handler('_error_handler');
  82. set_exception_handler('_exception_handler');
  83. register_shutdown_function('_shutdown_handler');
  84. /*
  85. * ------------------------------------------------------
  86. * Set the subclass_prefix
  87. * ------------------------------------------------------
  88. *
  89. * Normally the "subclass_prefix" is set in the config file.
  90. * The subclass prefix allows CI to know if a core class is
  91. * being extended via a library in the local application
  92. * "libraries" folder. Since CI allows config items to be
  93. * overridden via data set in the main index.php file,
  94. * before proceeding we need to know if a subclass_prefix
  95. * override exists. If so, we will set this value now,
  96. * before any classes are loaded
  97. * Note: Since the config file data is cached it doesn't
  98. * hurt to load it here.
  99. */
  100. if ( ! empty($assign_to_config['subclass_prefix']))
  101. {
  102. get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));
  103. }
  104. /*
  105. * ------------------------------------------------------
  106. * Should we use a Composer autoloader?
  107. * ------------------------------------------------------
  108. */
  109. if ($composer_autoload = config_item('composer_autoload'))
  110. {
  111. if ($composer_autoload === TRUE)
  112. {
  113. file_exists(APPPATH.'vendor/autoload.php')
  114. ? require_once(APPPATH.'vendor/autoload.php')
  115. : log_message('error', '$config[\'composer_autoload\'] is set to TRUE but '.APPPATH.'vendor/autoload.php was not found.');
  116. }
  117. elseif (file_exists($composer_autoload))
  118. {
  119. require_once($composer_autoload);
  120. }
  121. else
  122. {
  123. log_message('error', 'Could not find the specified $config[\'composer_autoload\'] path: '.$composer_autoload);
  124. }
  125. }
  126. /*
  127. * ------------------------------------------------------
  128. * Start the timer... tick tock tick tock...
  129. * ------------------------------------------------------
  130. */
  131. $BM =& load_class('Benchmark', 'core');
  132. $BM->mark('total_execution_time_start');
  133. $BM->mark('loading_time:_base_classes_start');
  134. /*
  135. * ------------------------------------------------------
  136. * Instantiate the config class
  137. * ------------------------------------------------------
  138. *
  139. * Note: It is important that Config is loaded first as
  140. * most other classes depend on it either directly or by
  141. * depending on another class that uses it.
  142. *
  143. */
  144. $CFG =& load_class('Config', 'core');
  145. // Do we have any manually set config items in the index.php file?
  146. if (isset($assign_to_config) && is_array($assign_to_config))
  147. {
  148. foreach ($assign_to_config as $key => $value)
  149. {
  150. $CFG->set_item($key, $value);
  151. }
  152. }
  153. /*
  154. * ------------------------------------------------------
  155. * Instantiate the hooks class
  156. * ------------------------------------------------------
  157. */
  158. $EXT =& load_class('Hooks', 'core', $CFG);
  159. /*
  160. * ------------------------------------------------------
  161. * Is there a "pre_system" hook?
  162. * ------------------------------------------------------
  163. */
  164. $EXT->call_hook('pre_system');
  165. /*
  166. * ------------------------------------------------------
  167. * Important charset-related stuff
  168. * ------------------------------------------------------
  169. *
  170. * Configure mbstring and/or iconv if they are enabled
  171. * and set MB_ENABLED and ICONV_ENABLED constants, so
  172. * that we don't repeatedly do extension_loaded() or
  173. * function_exists() calls.
  174. *
  175. * Note: UTF-8 class depends on this. It used to be done
  176. * in it's constructor, but it's _not_ class-specific.
  177. *
  178. */
  179. $charset = strtoupper(config_item('charset'));
  180. ini_set('default_charset', $charset);
  181. if (extension_loaded('mbstring'))
  182. {
  183. define('MB_ENABLED', TRUE);
  184. // mbstring.internal_encoding is deprecated starting with PHP 5.6
  185. // and it's usage triggers E_DEPRECATED messages.
  186. @ini_set('mbstring.internal_encoding', $charset);
  187. // This is required for mb_convert_encoding() to strip invalid characters.
  188. // That's utilized by CI_Utf8, but it's also done for consistency with iconv.
  189. mb_substitute_character('none');
  190. }
  191. else
  192. {
  193. define('MB_ENABLED', FALSE);
  194. }
  195. // There's an ICONV_IMPL constant, but the PHP manual says that using
  196. // iconv's predefined constants is "strongly discouraged".
  197. if (extension_loaded('iconv'))
  198. {
  199. define('ICONV_ENABLED', TRUE);
  200. // iconv.internal_encoding is deprecated starting with PHP 5.6
  201. // and it's usage triggers E_DEPRECATED messages.
  202. @ini_set('iconv.internal_encoding', $charset);
  203. }
  204. else
  205. {
  206. define('ICONV_ENABLED', FALSE);
  207. }
  208. if (is_php('5.6'))
  209. {
  210. ini_set('php.internal_encoding', $charset);
  211. }
  212. /*
  213. * ------------------------------------------------------
  214. * Load compatibility features
  215. * ------------------------------------------------------
  216. */
  217. require_once(BASEPATH.'core/compat/mbstring.php');
  218. require_once(BASEPATH.'core/compat/hash.php');
  219. require_once(BASEPATH.'core/compat/password.php');
  220. require_once(BASEPATH.'core/compat/standard.php');
  221. /*
  222. * ------------------------------------------------------
  223. * Instantiate the UTF-8 class
  224. * ------------------------------------------------------
  225. */
  226. $UNI =& load_class('Utf8', 'core', $charset);
  227. /*
  228. * ------------------------------------------------------
  229. * Instantiate the URI class
  230. * ------------------------------------------------------
  231. */
  232. $URI =& load_class('URI', 'core', $CFG);
  233. /*
  234. * ------------------------------------------------------
  235. * Instantiate the routing class and set the routing
  236. * ------------------------------------------------------
  237. */
  238. $RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);
  239. /*
  240. * ------------------------------------------------------
  241. * Instantiate the output class
  242. * ------------------------------------------------------
  243. */
  244. $OUT =& load_class('Output', 'core');
  245. /*
  246. * ------------------------------------------------------
  247. * Is there a valid cache file? If so, we're done...
  248. * ------------------------------------------------------
  249. */
  250. if ($EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE)
  251. {
  252. exit;
  253. }
  254. /*
  255. * -----------------------------------------------------
  256. * Load the security class for xss and csrf support
  257. * -----------------------------------------------------
  258. */
  259. $SEC =& load_class('Security', 'core', $charset);
  260. /*
  261. * ------------------------------------------------------
  262. * Load the Input class and sanitize globals
  263. * ------------------------------------------------------
  264. */
  265. $IN =& load_class('Input', 'core', $SEC);
  266. /*
  267. * ------------------------------------------------------
  268. * Load the Language class
  269. * ------------------------------------------------------
  270. */
  271. $LANG =& load_class('Lang', 'core');
  272. /*
  273. * ------------------------------------------------------
  274. * Load the app controller and local controller
  275. * ------------------------------------------------------
  276. *
  277. */
  278. // Load the base controller class
  279. require_once BASEPATH.'core/Controller.php';
  280. /**
  281. * Reference to the CI_Controller method.
  282. *
  283. * Returns current CI instance object
  284. *
  285. * @return CI_Controller
  286. */
  287. function &get_instance()
  288. {
  289. return CI_Controller::get_instance();
  290. }
  291. if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'))
  292. {
  293. require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
  294. }
  295. // Set a mark point for benchmarking
  296. $BM->mark('loading_time:_base_classes_end');
  297. /*
  298. * ------------------------------------------------------
  299. * Sanity checks
  300. * ------------------------------------------------------
  301. *
  302. * The Router class has already validated the request,
  303. * leaving us with 3 options here:
  304. *
  305. * 1) an empty class name, if we reached the default
  306. * controller, but it didn't exist;
  307. * 2) a query string which doesn't go through a
  308. * file_exists() check
  309. * 3) a regular request for a non-existing page
  310. *
  311. * We handle all of these as a 404 error.
  312. *
  313. * Furthermore, none of the methods in the app controller
  314. * or the loader class can be called via the URI, nor can
  315. * controller methods that begin with an underscore.
  316. */
  317. $e404 = FALSE;
  318. $class = ucfirst($RTR->class);
  319. $method = $RTR->method;
  320. if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
  321. {
  322. $e404 = TRUE;
  323. }
  324. else
  325. {
  326. require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');
  327. if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
  328. {
  329. $e404 = TRUE;
  330. }
  331. elseif (method_exists($class, '_remap'))
  332. {
  333. $params = array($method, array_slice($URI->rsegments, 2));
  334. $method = '_remap';
  335. }
  336. elseif ( ! method_exists($class, $method))
  337. {
  338. $e404 = TRUE;
  339. }
  340. /**
  341. * DO NOT CHANGE THIS, NOTHING ELSE WORKS!
  342. *
  343. * - method_exists() returns true for non-public methods, which passes the previous elseif
  344. * - is_callable() returns false for PHP 4-style constructors, even if there's a __construct()
  345. * - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited
  346. * - People will only complain if this doesn't work, even though it is documented that it shouldn't.
  347. *
  348. * ReflectionMethod::isConstructor() is the ONLY reliable check,
  349. * knowing which method will be executed as a constructor.
  350. */
  351. else
  352. {
  353. $reflection = new ReflectionMethod($class, $method);
  354. if ( ! $reflection->isPublic() OR $reflection->isConstructor())
  355. {
  356. $e404 = TRUE;
  357. }
  358. }
  359. }
  360. if ($e404)
  361. {
  362. if ( ! empty($RTR->routes['404_override']))
  363. {
  364. if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2)
  365. {
  366. $error_method = 'index';
  367. }
  368. $error_class = ucfirst($error_class);
  369. if ( ! class_exists($error_class, FALSE))
  370. {
  371. if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'))
  372. {
  373. require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php');
  374. $e404 = ! class_exists($error_class, FALSE);
  375. }
  376. // Were we in a directory? If so, check for a global override
  377. elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php'))
  378. {
  379. require_once(APPPATH.'controllers/'.$error_class.'.php');
  380. if (($e404 = ! class_exists($error_class, FALSE)) === FALSE)
  381. {
  382. $RTR->directory = '';
  383. }
  384. }
  385. }
  386. else
  387. {
  388. $e404 = FALSE;
  389. }
  390. }
  391. // Did we reset the $e404 flag? If so, set the rsegments, starting from index 1
  392. if ( ! $e404)
  393. {
  394. $class = $error_class;
  395. $method = $error_method;
  396. $URI->rsegments = array(
  397. 1 => $class,
  398. 2 => $method
  399. );
  400. }
  401. else
  402. {
  403. show_404($RTR->directory.$class.'/'.$method);
  404. }
  405. }
  406. if ($method !== '_remap')
  407. {
  408. $params = array_slice($URI->rsegments, 2);
  409. }
  410. /*
  411. * ------------------------------------------------------
  412. * Is there a "pre_controller" hook?
  413. * ------------------------------------------------------
  414. */
  415. $EXT->call_hook('pre_controller');
  416. /*
  417. * ------------------------------------------------------
  418. * Instantiate the requested controller
  419. * ------------------------------------------------------
  420. */
  421. // Mark a start point so we can benchmark the controller
  422. $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start');
  423. $CI = new $class();
  424. /*
  425. * ------------------------------------------------------
  426. * Is there a "post_controller_constructor" hook?
  427. * ------------------------------------------------------
  428. */
  429. $EXT->call_hook('post_controller_constructor');
  430. /*
  431. * ------------------------------------------------------
  432. * Call the requested method
  433. * ------------------------------------------------------
  434. */
  435. call_user_func_array(array(&$CI, $method), $params);
  436. // Mark a benchmark end point
  437. $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end');
  438. /*
  439. * ------------------------------------------------------
  440. * Is there a "post_controller" hook?
  441. * ------------------------------------------------------
  442. */
  443. $EXT->call_hook('post_controller');
  444. /*
  445. * ------------------------------------------------------
  446. * Send the final rendered output to the browser
  447. * ------------------------------------------------------
  448. */
  449. if ($EXT->call_hook('display_override') === FALSE)
  450. {
  451. $OUT->_display();
  452. }
  453. /*
  454. * ------------------------------------------------------
  455. * Is there a "post_system" hook?
  456. * ------------------------------------------------------
  457. */
  458. $EXT->call_hook('post_system');