You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

559 lines
16 KiB

7 years ago
  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 - 2017, 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 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://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/user_guide/
  49. */
  50. /**
  51. * CodeIgniter Version
  52. *
  53. * @var string
  54. *
  55. */
  56. const CI_VERSION = '3.1.5';
  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. * Security procedures
  79. * ------------------------------------------------------
  80. */
  81. if ( ! is_php('5.4'))
  82. {
  83. ini_set('magic_quotes_runtime', 0);
  84. if ((bool) ini_get('register_globals'))
  85. {
  86. $_protected = array(
  87. '_SERVER',
  88. '_GET',
  89. '_POST',
  90. '_FILES',
  91. '_REQUEST',
  92. '_SESSION',
  93. '_ENV',
  94. '_COOKIE',
  95. 'GLOBALS',
  96. 'HTTP_RAW_POST_DATA',
  97. 'system_path',
  98. 'application_folder',
  99. 'view_folder',
  100. '_protected',
  101. '_registered'
  102. );
  103. $_registered = ini_get('variables_order');
  104. foreach (array('E' => '_ENV', 'G' => '_GET', 'P' => '_POST', 'C' => '_COOKIE', 'S' => '_SERVER') as $key => $superglobal)
  105. {
  106. if (strpos($_registered, $key) === FALSE)
  107. {
  108. continue;
  109. }
  110. foreach (array_keys($$superglobal) as $var)
  111. {
  112. if (isset($GLOBALS[$var]) && ! in_array($var, $_protected, TRUE))
  113. {
  114. $GLOBALS[$var] = NULL;
  115. }
  116. }
  117. }
  118. }
  119. }
  120. /*
  121. * ------------------------------------------------------
  122. * Define a custom error handler so we can log PHP errors
  123. * ------------------------------------------------------
  124. */
  125. set_error_handler('_error_handler');
  126. set_exception_handler('_exception_handler');
  127. register_shutdown_function('_shutdown_handler');
  128. /*
  129. * ------------------------------------------------------
  130. * Set the subclass_prefix
  131. * ------------------------------------------------------
  132. *
  133. * Normally the "subclass_prefix" is set in the config file.
  134. * The subclass prefix allows CI to know if a core class is
  135. * being extended via a library in the local application
  136. * "libraries" folder. Since CI allows config items to be
  137. * overridden via data set in the main index.php file,
  138. * before proceeding we need to know if a subclass_prefix
  139. * override exists. If so, we will set this value now,
  140. * before any classes are loaded
  141. * Note: Since the config file data is cached it doesn't
  142. * hurt to load it here.
  143. */
  144. if ( ! empty($assign_to_config['subclass_prefix']))
  145. {
  146. get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));
  147. }
  148. /*
  149. * ------------------------------------------------------
  150. * Should we use a Composer autoloader?
  151. * ------------------------------------------------------
  152. */
  153. if ($composer_autoload = config_item('composer_autoload'))
  154. {
  155. if ($composer_autoload === TRUE)
  156. {
  157. file_exists(APPPATH.'vendor/autoload.php')
  158. ? require_once(APPPATH.'vendor/autoload.php')
  159. : log_message('error', '$config[\'composer_autoload\'] is set to TRUE but '.APPPATH.'vendor/autoload.php was not found.');
  160. }
  161. elseif (file_exists($composer_autoload))
  162. {
  163. require_once($composer_autoload);
  164. }
  165. else
  166. {
  167. log_message('error', 'Could not find the specified $config[\'composer_autoload\'] path: '.$composer_autoload);
  168. }
  169. }
  170. /*
  171. * ------------------------------------------------------
  172. * Start the timer... tick tock tick tock...
  173. * ------------------------------------------------------
  174. */
  175. $BM =& load_class('Benchmark', 'core');
  176. $BM->mark('total_execution_time_start');
  177. $BM->mark('loading_time:_base_classes_start');
  178. /*
  179. * ------------------------------------------------------
  180. * Instantiate the hooks class
  181. * ------------------------------------------------------
  182. */
  183. $EXT =& load_class('Hooks', 'core');
  184. /*
  185. * ------------------------------------------------------
  186. * Is there a "pre_system" hook?
  187. * ------------------------------------------------------
  188. */
  189. $EXT->call_hook('pre_system');
  190. /*
  191. * ------------------------------------------------------
  192. * Instantiate the config class
  193. * ------------------------------------------------------
  194. *
  195. * Note: It is important that Config is loaded first as
  196. * most other classes depend on it either directly or by
  197. * depending on another class that uses it.
  198. *
  199. */
  200. $CFG =& load_class('Config', 'core');
  201. // Do we have any manually set config items in the index.php file?
  202. if (isset($assign_to_config) && is_array($assign_to_config))
  203. {
  204. foreach ($assign_to_config as $key => $value)
  205. {
  206. $CFG->set_item($key, $value);
  207. }
  208. }
  209. /*
  210. * ------------------------------------------------------
  211. * Important charset-related stuff
  212. * ------------------------------------------------------
  213. *
  214. * Configure mbstring and/or iconv if they are enabled
  215. * and set MB_ENABLED and ICONV_ENABLED constants, so
  216. * that we don't repeatedly do extension_loaded() or
  217. * function_exists() calls.
  218. *
  219. * Note: UTF-8 class depends on this. It used to be done
  220. * in it's constructor, but it's _not_ class-specific.
  221. *
  222. */
  223. $charset = strtoupper(config_item('charset'));
  224. ini_set('default_charset', $charset);
  225. if (extension_loaded('mbstring'))
  226. {
  227. define('MB_ENABLED', TRUE);
  228. // mbstring.internal_encoding is deprecated starting with PHP 5.6
  229. // and it's usage triggers E_DEPRECATED messages.
  230. @ini_set('mbstring.internal_encoding', $charset);
  231. // This is required for mb_convert_encoding() to strip invalid characters.
  232. // That's utilized by CI_Utf8, but it's also done for consistency with iconv.
  233. mb_substitute_character('none');
  234. }
  235. else
  236. {
  237. define('MB_ENABLED', FALSE);
  238. }
  239. // There's an ICONV_IMPL constant, but the PHP manual says that using
  240. // iconv's predefined constants is "strongly discouraged".
  241. if (extension_loaded('iconv'))
  242. {
  243. define('ICONV_ENABLED', TRUE);
  244. // iconv.internal_encoding is deprecated starting with PHP 5.6
  245. // and it's usage triggers E_DEPRECATED messages.
  246. @ini_set('iconv.internal_encoding', $charset);
  247. }
  248. else
  249. {
  250. define('ICONV_ENABLED', FALSE);
  251. }
  252. if (is_php('5.6'))
  253. {
  254. ini_set('php.internal_encoding', $charset);
  255. }
  256. /*
  257. * ------------------------------------------------------
  258. * Load compatibility features
  259. * ------------------------------------------------------
  260. */
  261. require_once(BASEPATH.'core/compat/mbstring.php');
  262. require_once(BASEPATH.'core/compat/hash.php');
  263. require_once(BASEPATH.'core/compat/password.php');
  264. require_once(BASEPATH.'core/compat/standard.php');
  265. /*
  266. * ------------------------------------------------------
  267. * Instantiate the UTF-8 class
  268. * ------------------------------------------------------
  269. */
  270. $UNI =& load_class('Utf8', 'core');
  271. /*
  272. * ------------------------------------------------------
  273. * Instantiate the URI class
  274. * ------------------------------------------------------
  275. */
  276. $URI =& load_class('URI', 'core');
  277. /*
  278. * ------------------------------------------------------
  279. * Instantiate the routing class and set the routing
  280. * ------------------------------------------------------
  281. */
  282. $RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);
  283. /*
  284. * ------------------------------------------------------
  285. * Instantiate the output class
  286. * ------------------------------------------------------
  287. */
  288. $OUT =& load_class('Output', 'core');
  289. /*
  290. * ------------------------------------------------------
  291. * Is there a valid cache file? If so, we're done...
  292. * ------------------------------------------------------
  293. */
  294. if ($EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE)
  295. {
  296. exit;
  297. }
  298. /*
  299. * -----------------------------------------------------
  300. * Load the security class for xss and csrf support
  301. * -----------------------------------------------------
  302. */
  303. $SEC =& load_class('Security', 'core');
  304. /*
  305. * ------------------------------------------------------
  306. * Load the Input class and sanitize globals
  307. * ------------------------------------------------------
  308. */
  309. $IN =& load_class('Input', 'core');
  310. /*
  311. * ------------------------------------------------------
  312. * Load the Language class
  313. * ------------------------------------------------------
  314. */
  315. $LANG =& load_class('Lang', 'core');
  316. /*
  317. * ------------------------------------------------------
  318. * Load the app controller and local controller
  319. * ------------------------------------------------------
  320. *
  321. */
  322. // Load the base controller class
  323. require_once BASEPATH.'core/Controller.php';
  324. /**
  325. * Reference to the CI_Controller method.
  326. *
  327. * Returns current CI instance object
  328. *
  329. * @return CI_Controller
  330. */
  331. function &get_instance()
  332. {
  333. return CI_Controller::get_instance();
  334. }
  335. if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'))
  336. {
  337. require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
  338. }
  339. // Set a mark point for benchmarking
  340. $BM->mark('loading_time:_base_classes_end');
  341. /*
  342. * ------------------------------------------------------
  343. * Sanity checks
  344. * ------------------------------------------------------
  345. *
  346. * The Router class has already validated the request,
  347. * leaving us with 3 options here:
  348. *
  349. * 1) an empty class name, if we reached the default
  350. * controller, but it didn't exist;
  351. * 2) a query string which doesn't go through a
  352. * file_exists() check
  353. * 3) a regular request for a non-existing page
  354. *
  355. * We handle all of these as a 404 error.
  356. *
  357. * Furthermore, none of the methods in the app controller
  358. * or the loader class can be called via the URI, nor can
  359. * controller methods that begin with an underscore.
  360. */
  361. $e404 = FALSE;
  362. $class = ucfirst($RTR->class);
  363. $method = $RTR->method;
  364. if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
  365. {
  366. $e404 = TRUE;
  367. }
  368. else
  369. {
  370. require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');
  371. if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
  372. {
  373. $e404 = TRUE;
  374. }
  375. elseif (method_exists($class, '_remap'))
  376. {
  377. $params = array($method, array_slice($URI->rsegments, 2));
  378. $method = '_remap';
  379. }
  380. elseif ( ! method_exists($class, $method))
  381. {
  382. $e404 = TRUE;
  383. }
  384. /**
  385. * DO NOT CHANGE THIS, NOTHING ELSE WORKS!
  386. *
  387. * - method_exists() returns true for non-public methods, which passes the previous elseif
  388. * - is_callable() returns false for PHP 4-style constructors, even if there's a __construct()
  389. * - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited
  390. * - People will only complain if this doesn't work, even though it is documented that it shouldn't.
  391. *
  392. * ReflectionMethod::isConstructor() is the ONLY reliable check,
  393. * knowing which method will be executed as a constructor.
  394. */
  395. elseif ( ! is_callable(array($class, $method)))
  396. {
  397. $reflection = new ReflectionMethod($class, $method);
  398. if ( ! $reflection->isPublic() OR $reflection->isConstructor())
  399. {
  400. $e404 = TRUE;
  401. }
  402. }
  403. }
  404. if ($e404)
  405. {
  406. if ( ! empty($RTR->routes['404_override']))
  407. {
  408. if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2)
  409. {
  410. $error_method = 'index';
  411. }
  412. $error_class = ucfirst($error_class);
  413. if ( ! class_exists($error_class, FALSE))
  414. {
  415. if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'))
  416. {
  417. require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php');
  418. $e404 = ! class_exists($error_class, FALSE);
  419. }
  420. // Were we in a directory? If so, check for a global override
  421. elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php'))
  422. {
  423. require_once(APPPATH.'controllers/'.$error_class.'.php');
  424. if (($e404 = ! class_exists($error_class, FALSE)) === FALSE)
  425. {
  426. $RTR->directory = '';
  427. }
  428. }
  429. }
  430. else
  431. {
  432. $e404 = FALSE;
  433. }
  434. }
  435. // Did we reset the $e404 flag? If so, set the rsegments, starting from index 1
  436. if ( ! $e404)
  437. {
  438. $class = $error_class;
  439. $method = $error_method;
  440. $URI->rsegments = array(
  441. 1 => $class,
  442. 2 => $method
  443. );
  444. }
  445. else
  446. {
  447. show_404($RTR->directory.$class.'/'.$method);
  448. }
  449. }
  450. if ($method !== '_remap')
  451. {
  452. $params = array_slice($URI->rsegments, 2);
  453. }
  454. /*
  455. * ------------------------------------------------------
  456. * Is there a "pre_controller" hook?
  457. * ------------------------------------------------------
  458. */
  459. $EXT->call_hook('pre_controller');
  460. /*
  461. * ------------------------------------------------------
  462. * Instantiate the requested controller
  463. * ------------------------------------------------------
  464. */
  465. // Mark a start point so we can benchmark the controller
  466. $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start');
  467. $CI = new $class();
  468. /*
  469. * ------------------------------------------------------
  470. * Is there a "post_controller_constructor" hook?
  471. * ------------------------------------------------------
  472. */
  473. $EXT->call_hook('post_controller_constructor');
  474. /*
  475. * ------------------------------------------------------
  476. * Call the requested method
  477. * ------------------------------------------------------
  478. */
  479. call_user_func_array(array(&$CI, $method), $params);
  480. // Mark a benchmark end point
  481. $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end');
  482. /*
  483. * ------------------------------------------------------
  484. * Is there a "post_controller" hook?
  485. * ------------------------------------------------------
  486. */
  487. $EXT->call_hook('post_controller');
  488. /*
  489. * ------------------------------------------------------
  490. * Send the final rendered output to the browser
  491. * ------------------------------------------------------
  492. */
  493. if ($EXT->call_hook('display_override') === FALSE)
  494. {
  495. $OUT->_display();
  496. }
  497. /*
  498. * ------------------------------------------------------
  499. * Is there a "post_system" hook?
  500. * ------------------------------------------------------
  501. */
  502. $EXT->call_hook('post_system');