PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/system/classes/kohana/core.php

https://bitbucket.org/SinSiXX/tickets
PHP | 1040 lines | 599 code | 104 blank | 337 comment | 42 complexity | 7d5cc9cb435d2a9ddafbf8445a487159 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Contains the most low-level helpers methods in Kohana:
  4. *
  5. * - Environment initialization
  6. * - Locating files within the cascading filesystem
  7. * - Auto-loading and transparent extension of classes
  8. * - Variable and path debugging
  9. *
  10. * @package Kohana
  11. * @category Base
  12. * @author Kohana Team
  13. * @copyright (c) 2008-2011 Kohana Team
  14. * @license http://kohanaframework.org/license
  15. */
  16. class Kohana_Core {
  17. // Release version and codename
  18. const VERSION = '3.1.3.1';
  19. const CODENAME = 'araea';
  20. // Common environment type constants for consistency and convenience
  21. const PRODUCTION = 1;
  22. const STAGING = 2;
  23. const TESTING = 3;
  24. const DEVELOPMENT = 4;
  25. // Security check that is added to all generated PHP files
  26. const FILE_SECURITY = '<?php defined(\'SYSPATH\') or die(\'No direct script access.\');';
  27. // Format of cache files: header, cache name, and data
  28. const FILE_CACHE = ":header \n\n// :name\n\n:data\n";
  29. /**
  30. * @var string Current environment name
  31. */
  32. public static $environment = Kohana::DEVELOPMENT;
  33. /**
  34. * @var boolean True if Kohana is running from the command line
  35. */
  36. public static $is_cli = FALSE;
  37. /**
  38. * @var boolean True if Kohana is running on windows
  39. */
  40. public static $is_windows = FALSE;
  41. /**
  42. * @var boolean True if [magic quotes](http://php.net/manual/en/security.magicquotes.php) is enabled.
  43. */
  44. public static $magic_quotes = FALSE;
  45. /**
  46. * @var boolean Should errors and exceptions be logged
  47. */
  48. public static $log_errors = FALSE;
  49. /**
  50. * @var boolean TRUE if PHP safe mode is on
  51. */
  52. public static $safe_mode = FALSE;
  53. /**
  54. * @var string
  55. */
  56. public static $content_type = 'text/html';
  57. /**
  58. * @var string character set of input and output
  59. */
  60. public static $charset = 'utf-8';
  61. /**
  62. * @var string the name of the server Kohana is hosted upon
  63. */
  64. public static $server_name = '';
  65. /**
  66. * @var array list of valid host names for this instance
  67. */
  68. public static $hostnames = array();
  69. /**
  70. * @var string base URL to the application
  71. */
  72. public static $base_url = '/';
  73. /**
  74. * @var string Application index file, added to links generated by Kohana. Set by [Kohana::init]
  75. */
  76. public static $index_file = 'index.php';
  77. /**
  78. * @var string Cache directory, used by [Kohana::cache]. Set by [Kohana::init]
  79. */
  80. public static $cache_dir;
  81. /**
  82. * @var integer Default lifetime for caching, in seconds, used by [Kohana::cache]. Set by [Kohana::init]
  83. */
  84. public static $cache_life = 60;
  85. /**
  86. * @var boolean Whether to use internal caching for [Kohana::find_file], does not apply to [Kohana::cache]. Set by [Kohana::init]
  87. */
  88. public static $caching = FALSE;
  89. /**
  90. * @var boolean Whether to enable [profiling](kohana/profiling). Set by [Kohana::init]
  91. */
  92. public static $profiling = TRUE;
  93. /**
  94. * @var boolean Enable Kohana catching and displaying PHP errors and exceptions. Set by [Kohana::init]
  95. */
  96. public static $errors = TRUE;
  97. /**
  98. * @var array Types of errors to display at shutdown
  99. */
  100. public static $shutdown_errors = array(E_PARSE, E_ERROR, E_USER_ERROR);
  101. /**
  102. * @var boolean set the X-Powered-By header
  103. */
  104. public static $expose = FALSE;
  105. /**
  106. * @var Log logging object
  107. */
  108. public static $log;
  109. /**
  110. * @var Config config object
  111. */
  112. public static $config;
  113. /**
  114. * @var boolean Has [Kohana::init] been called?
  115. */
  116. protected static $_init = FALSE;
  117. /**
  118. * @var array Currently active modules
  119. */
  120. protected static $_modules = array();
  121. /**
  122. * @var array Include paths that are used to find files
  123. */
  124. protected static $_paths = array(APPPATH, SYSPATH);
  125. /**
  126. * @var array File path cache, used when caching is true in [Kohana::init]
  127. */
  128. protected static $_files = array();
  129. /**
  130. * @var boolean Has the file path cache changed during this execution? Used internally when when caching is true in [Kohana::init]
  131. */
  132. protected static $_files_changed = FALSE;
  133. /**
  134. * Initializes the environment:
  135. *
  136. * - Disables register_globals and magic_quotes_gpc
  137. * - Determines the current environment
  138. * - Set global settings
  139. * - Sanitizes GET, POST, and COOKIE variables
  140. * - Converts GET, POST, and COOKIE variables to the global character set
  141. *
  142. * The following settings can be set:
  143. *
  144. * Type | Setting | Description | Default Value
  145. * ----------|------------|------------------------------------------------|---------------
  146. * `string` | base_url | The base URL for your application. This should be the *relative* path from your DOCROOT to your `index.php` file, in other words, if Kohana is in a subfolder, set this to the subfolder name, otherwise leave it as the default. **The leading slash is required**, trailing slash is optional. | `"/"`
  147. * `string` | index_file | The name of the [front controller](http://en.wikipedia.org/wiki/Front_Controller_pattern). This is used by Kohana to generate relative urls like [HTML::anchor()] and [URL::base()]. This is usually `index.php`. To [remove index.php from your urls](tutorials/clean-urls), set this to `FALSE`. | `"index.php"`
  148. * `string` | charset | Character set used for all input and output | `"utf-8"`
  149. * `string` | cache_dir | Kohana's cache directory. Used by [Kohana::cache] for simple internal caching, like [Fragments](kohana/fragments) and **\[caching database queries](this should link somewhere)**. This has nothing to do with the [Cache module](cache). | `APPPATH."cache"`
  150. * `integer` | cache_life | Lifetime, in seconds, of items cached by [Kohana::cache] | `60`
  151. * `boolean` | errors | Should Kohana catch PHP errors and uncaught Exceptions and show the `error_view`. See [Error Handling](kohana/errors) for more info. <br /> <br /> Recommended setting: `TRUE` while developing, `FALSE` on production servers. | `TRUE`
  152. * `boolean` | profile | Whether to enable the [Profiler](kohana/profiling). <br /> <br />Recommended setting: `TRUE` while developing, `FALSE` on production servers. | `TRUE` * `boolean` | caching | Cache file locations to speed up [Kohana::find_file]. This has nothing to do with [Kohana::cache], [Fragments](kohana/fragments) or the [Cache module](cache). <br /> <br /> Recommended setting: `FALSE` while developing, `TRUE` on production servers. | `FALSE`
  153. *
  154. * @throws Kohana_Exception
  155. * @param array Array of settings. See above.
  156. * @return void
  157. * @uses Kohana::globals
  158. * @uses Kohana::sanitize
  159. * @uses Kohana::cache
  160. * @uses Profiler
  161. */
  162. public static function init(array $settings = NULL)
  163. {
  164. if (Kohana::$_init)
  165. {
  166. // Do not allow execution twice
  167. return;
  168. }
  169. // Kohana is now initialized
  170. Kohana::$_init = TRUE;
  171. if (isset($settings['profile']))
  172. {
  173. // Enable profiling
  174. Kohana::$profiling = (bool) $settings['profile'];
  175. }
  176. // Start an output buffer
  177. ob_start();
  178. if (isset($settings['errors']))
  179. {
  180. // Enable error handling
  181. Kohana::$errors = (bool) $settings['errors'];
  182. }
  183. if (Kohana::$errors === TRUE)
  184. {
  185. // Enable Kohana exception handling, adds stack traces and error source.
  186. set_exception_handler(array('Kohana_Exception', 'handler'));
  187. // Enable Kohana error handling, converts all PHP errors to exceptions.
  188. set_error_handler(array('Kohana', 'error_handler'));
  189. }
  190. // Enable the Kohana shutdown handler, which catches E_FATAL errors.
  191. register_shutdown_function(array('Kohana', 'shutdown_handler'));
  192. if (ini_get('register_globals'))
  193. {
  194. // Reverse the effects of register_globals
  195. Kohana::globals();
  196. }
  197. if (isset($settings['expose']))
  198. {
  199. Kohana::$expose = (bool) $settings['expose'];
  200. }
  201. // Determine if we are running in a command line environment
  202. Kohana::$is_cli = (PHP_SAPI === 'cli');
  203. // Determine if we are running in a Windows environment
  204. Kohana::$is_windows = (DIRECTORY_SEPARATOR === '\\');
  205. // Determine if we are running in safe mode
  206. Kohana::$safe_mode = (bool) ini_get('safe_mode');
  207. if (isset($settings['cache_dir']))
  208. {
  209. if ( ! is_dir($settings['cache_dir']))
  210. {
  211. try
  212. {
  213. // Create the cache directory
  214. mkdir($settings['cache_dir'], 0755, TRUE);
  215. // Set permissions (must be manually set to fix umask issues)
  216. chmod($settings['cache_dir'], 0755);
  217. }
  218. catch (Exception $e)
  219. {
  220. throw new Kohana_Exception('Could not create cache directory :dir',
  221. array(':dir' => Debug::path($settings['cache_dir'])));
  222. }
  223. }
  224. // Set the cache directory path
  225. Kohana::$cache_dir = realpath($settings['cache_dir']);
  226. }
  227. else
  228. {
  229. // Use the default cache directory
  230. Kohana::$cache_dir = APPPATH.'cache';
  231. }
  232. if ( ! is_writable(Kohana::$cache_dir))
  233. {
  234. throw new Kohana_Exception('Directory :dir must be writable',
  235. array(':dir' => Debug::path(Kohana::$cache_dir)));
  236. }
  237. if (isset($settings['cache_life']))
  238. {
  239. // Set the default cache lifetime
  240. Kohana::$cache_life = (int) $settings['cache_life'];
  241. }
  242. if (isset($settings['caching']))
  243. {
  244. // Enable or disable internal caching
  245. Kohana::$caching = (bool) $settings['caching'];
  246. }
  247. if (Kohana::$caching === TRUE)
  248. {
  249. // Load the file path cache
  250. Kohana::$_files = Kohana::cache('Kohana::find_file()');
  251. }
  252. if (isset($settings['charset']))
  253. {
  254. // Set the system character set
  255. Kohana::$charset = strtolower($settings['charset']);
  256. }
  257. if (function_exists('mb_internal_encoding'))
  258. {
  259. // Set the MB extension encoding to the same character set
  260. mb_internal_encoding(Kohana::$charset);
  261. }
  262. if (isset($settings['base_url']))
  263. {
  264. // Set the base URL
  265. Kohana::$base_url = rtrim($settings['base_url'], '/').'/';
  266. }
  267. if (isset($settings['index_file']))
  268. {
  269. // Set the index file
  270. Kohana::$index_file = trim($settings['index_file'], '/');
  271. }
  272. // Determine if the extremely evil magic quotes are enabled
  273. Kohana::$magic_quotes = (bool) get_magic_quotes_gpc();
  274. // Sanitize all request variables
  275. $_GET = Kohana::sanitize($_GET);
  276. $_POST = Kohana::sanitize($_POST);
  277. $_COOKIE = Kohana::sanitize($_COOKIE);
  278. // Load the logger
  279. Kohana::$log = Log::instance();
  280. // Load the config
  281. Kohana::$config = Config::instance();
  282. }
  283. /**
  284. * Cleans up the environment:
  285. *
  286. * - Restore the previous error and exception handlers
  287. * - Destroy the Kohana::$log and Kohana::$config objects
  288. *
  289. * @return void
  290. */
  291. public static function deinit()
  292. {
  293. if (Kohana::$_init)
  294. {
  295. // Removed the autoloader
  296. spl_autoload_unregister(array('Kohana', 'auto_load'));
  297. if (Kohana::$errors)
  298. {
  299. // Go back to the previous error handler
  300. restore_error_handler();
  301. // Go back to the previous exception handler
  302. restore_exception_handler();
  303. }
  304. // Destroy objects created by init
  305. Kohana::$log = Kohana::$config = NULL;
  306. // Reset internal storage
  307. Kohana::$_modules = Kohana::$_files = array();
  308. Kohana::$_paths = array(APPPATH, SYSPATH);
  309. // Reset file cache status
  310. Kohana::$_files_changed = FALSE;
  311. // Kohana is no longer initialized
  312. Kohana::$_init = FALSE;
  313. }
  314. }
  315. /**
  316. * Reverts the effects of the `register_globals` PHP setting by unsetting
  317. * all global varibles except for the default super globals (GPCS, etc),
  318. * which is a [potential security hole.][ref-wikibooks]
  319. *
  320. * This is called automatically by [Kohana::init] if `register_globals` is
  321. * on.
  322. *
  323. *
  324. * [ref-wikibooks]: http://en.wikibooks.org/wiki/PHP_Programming/Register_Globals
  325. *
  326. * @return void
  327. */
  328. public static function globals()
  329. {
  330. if (isset($_REQUEST['GLOBALS']) OR isset($_FILES['GLOBALS']))
  331. {
  332. // Prevent malicious GLOBALS overload attack
  333. echo "Global variable overload attack detected! Request aborted.\n";
  334. // Exit with an error status
  335. exit(1);
  336. }
  337. // Get the variable names of all globals
  338. $global_variables = array_keys($GLOBALS);
  339. // Remove the standard global variables from the list
  340. $global_variables = array_diff($global_variables, array(
  341. '_COOKIE',
  342. '_ENV',
  343. '_GET',
  344. '_FILES',
  345. '_POST',
  346. '_REQUEST',
  347. '_SERVER',
  348. '_SESSION',
  349. 'GLOBALS',
  350. ));
  351. foreach ($global_variables as $name)
  352. {
  353. // Unset the global variable, effectively disabling register_globals
  354. unset($GLOBALS[$name]);
  355. }
  356. }
  357. /**
  358. * Recursively sanitizes an input variable:
  359. *
  360. * - Strips slashes if magic quotes are enabled
  361. * - Normalizes all newlines to LF
  362. *
  363. * @param mixed any variable
  364. * @return mixed sanitized variable
  365. */
  366. public static function sanitize($value)
  367. {
  368. if (is_array($value) OR is_object($value))
  369. {
  370. foreach ($value as $key => $val)
  371. {
  372. // Recursively clean each value
  373. $value[$key] = Kohana::sanitize($val);
  374. }
  375. }
  376. elseif (is_string($value))
  377. {
  378. if (Kohana::$magic_quotes === TRUE)
  379. {
  380. // Remove slashes added by magic quotes
  381. $value = stripslashes($value);
  382. }
  383. if (strpos($value, "\r") !== FALSE)
  384. {
  385. // Standardize newlines
  386. $value = str_replace(array("\r\n", "\r"), "\n", $value);
  387. }
  388. }
  389. return $value;
  390. }
  391. /**
  392. * Provides auto-loading support of classes that follow Kohana's [class
  393. * naming conventions](kohana/conventions#class-names-and-file-location).
  394. * See [Loading Classes](kohana/autoloading) for more information.
  395. *
  396. * Class names are converted to file names by making the class name
  397. * lowercase and converting underscores to slashes:
  398. *
  399. * // Loads classes/my/class/name.php
  400. * Kohana::auto_load('My_Class_Name');
  401. *
  402. * You should never have to call this function, as simply calling a class
  403. * will cause it to be called.
  404. *
  405. * This function must be enabled as an autoloader in the bootstrap:
  406. *
  407. * spl_autoload_register(array('Kohana', 'auto_load'));
  408. *
  409. * @param string class name
  410. * @return boolean
  411. */
  412. public static function auto_load($class)
  413. {
  414. try
  415. {
  416. // Transform the class name into a path
  417. $file = str_replace('_', '/', strtolower($class));
  418. if ($path = Kohana::find_file('classes', $file))
  419. {
  420. // Load the class file
  421. require $path;
  422. // Class has been found
  423. return TRUE;
  424. }
  425. // Class is not in the filesystem
  426. return FALSE;
  427. }
  428. catch (Exception $e)
  429. {
  430. Kohana_Exception::handler($e);
  431. die;
  432. }
  433. }
  434. /**
  435. * Changes the currently enabled modules. Module paths may be relative
  436. * or absolute, but must point to a directory:
  437. *
  438. * Kohana::modules(array('modules/foo', MODPATH.'bar'));
  439. *
  440. * @param array list of module paths
  441. * @return array enabled modules
  442. */
  443. public static function modules(array $modules = NULL)
  444. {
  445. if ($modules === NULL)
  446. {
  447. // Not changing modules, just return the current set
  448. return Kohana::$_modules;
  449. }
  450. // Start a new list of include paths, APPPATH first
  451. $paths = array(APPPATH);
  452. foreach ($modules as $name => $path)
  453. {
  454. if (is_dir($path))
  455. {
  456. // Add the module to include paths
  457. $paths[] = $modules[$name] = realpath($path).DIRECTORY_SEPARATOR;
  458. }
  459. else
  460. {
  461. // This module is invalid, remove it
  462. unset($modules[$name]);
  463. }
  464. }
  465. // Finish the include paths by adding SYSPATH
  466. $paths[] = SYSPATH;
  467. // Set the new include paths
  468. Kohana::$_paths = $paths;
  469. // Set the current module list
  470. Kohana::$_modules = $modules;
  471. foreach (Kohana::$_modules as $path)
  472. {
  473. $init = $path.'init'.EXT;
  474. if (is_file($init))
  475. {
  476. // Include the module initialization file once
  477. require_once $init;
  478. }
  479. }
  480. return Kohana::$_modules;
  481. }
  482. /**
  483. * Returns the the currently active include paths, including the
  484. * application, system, and each module's path.
  485. *
  486. * @return array
  487. */
  488. public static function include_paths()
  489. {
  490. return Kohana::$_paths;
  491. }
  492. /**
  493. * Searches for a file in the [Cascading Filesystem](kohana/files), and
  494. * returns the path to the file that has the highest precedence, so that it
  495. * can be included.
  496. *
  497. * When searching the "config", "messages", or "i18n" directories, or when
  498. * the `$array` flag is set to true, an array of all the files that match
  499. * that path in the [Cascading Filesystem](kohana/files) will be returned.
  500. * These files will return arrays which must be merged together.
  501. *
  502. * If no extension is given, the default extension (`EXT` set in
  503. * `index.php`) will be used.
  504. *
  505. * // Returns an absolute path to views/template.php
  506. * Kohana::find_file('views', 'template');
  507. *
  508. * // Returns an absolute path to media/css/style.css
  509. * Kohana::find_file('media', 'css/style', 'css');
  510. *
  511. * // Returns an array of all the "mimes" configuration files
  512. * Kohana::find_file('config', 'mimes');
  513. *
  514. * @param string directory name (views, i18n, classes, extensions, etc.)
  515. * @param string filename with subdirectory
  516. * @param string extension to search for
  517. * @param boolean return an array of files?
  518. * @return array a list of files when $array is TRUE
  519. * @return string single file path
  520. */
  521. public static function find_file($dir, $file, $ext = NULL, $array = FALSE)
  522. {
  523. if ($ext === NULL)
  524. {
  525. // Use the default extension
  526. $ext = EXT;
  527. }
  528. elseif ($ext)
  529. {
  530. // Prefix the extension with a period
  531. $ext = ".{$ext}";
  532. }
  533. else
  534. {
  535. // Use no extension
  536. $ext = '';
  537. }
  538. // Create a partial path of the filename
  539. $path = $dir.DIRECTORY_SEPARATOR.$file.$ext;
  540. if (Kohana::$caching === TRUE AND isset(Kohana::$_files[$path.($array ? '_array' : '_path')]))
  541. {
  542. // This path has been cached
  543. return Kohana::$_files[$path.($array ? '_array' : '_path')];
  544. }
  545. if (Kohana::$profiling === TRUE AND class_exists('Profiler', FALSE))
  546. {
  547. // Start a new benchmark
  548. $benchmark = Profiler::start('Kohana', __FUNCTION__);
  549. }
  550. if ($array OR $dir === 'config' OR $dir === 'i18n' OR $dir === 'messages')
  551. {
  552. // Include paths must be searched in reverse
  553. $paths = array_reverse(Kohana::$_paths);
  554. // Array of files that have been found
  555. $found = array();
  556. foreach ($paths as $dir)
  557. {
  558. if (is_file($dir.$path))
  559. {
  560. // This path has a file, add it to the list
  561. $found[] = $dir.$path;
  562. }
  563. }
  564. }
  565. else
  566. {
  567. // The file has not been found yet
  568. $found = FALSE;
  569. foreach (Kohana::$_paths as $dir)
  570. {
  571. if (is_file($dir.$path))
  572. {
  573. // A path has been found
  574. $found = $dir.$path;
  575. // Stop searching
  576. break;
  577. }
  578. }
  579. }
  580. if (Kohana::$caching === TRUE)
  581. {
  582. // Add the path to the cache
  583. Kohana::$_files[$path.($array ? '_array' : '_path')] = $found;
  584. // Files have been changed
  585. Kohana::$_files_changed = TRUE;
  586. }
  587. if (isset($benchmark))
  588. {
  589. // Stop the benchmark
  590. Profiler::stop($benchmark);
  591. }
  592. return $found;
  593. }
  594. /**
  595. * Recursively finds all of the files in the specified directory at any
  596. * location in the [Cascading Filesystem](kohana/files), and returns an
  597. * array of all the files found, sorted alphabetically.
  598. *
  599. * // Find all view files.
  600. * $views = Kohana::list_files('views');
  601. *
  602. * @param string directory name
  603. * @param array list of paths to search
  604. * @return array
  605. */
  606. public static function list_files($directory = NULL, array $paths = NULL)
  607. {
  608. if ($directory !== NULL)
  609. {
  610. // Add the directory separator
  611. $directory .= DIRECTORY_SEPARATOR;
  612. }
  613. if ($paths === NULL)
  614. {
  615. // Use the default paths
  616. $paths = Kohana::$_paths;
  617. }
  618. // Create an array for the files
  619. $found = array();
  620. foreach ($paths as $path)
  621. {
  622. if (is_dir($path.$directory))
  623. {
  624. // Create a new directory iterator
  625. $dir = new DirectoryIterator($path.$directory);
  626. foreach ($dir as $file)
  627. {
  628. // Get the file name
  629. $filename = $file->getFilename();
  630. if ($filename[0] === '.' OR $filename[strlen($filename)-1] === '~')
  631. {
  632. // Skip all hidden files and UNIX backup files
  633. continue;
  634. }
  635. // Relative filename is the array key
  636. $key = $directory.$filename;
  637. if ($file->isDir())
  638. {
  639. if ($sub_dir = Kohana::list_files($key, $paths))
  640. {
  641. if (isset($found[$key]))
  642. {
  643. // Append the sub-directory list
  644. $found[$key] += $sub_dir;
  645. }
  646. else
  647. {
  648. // Create a new sub-directory list
  649. $found[$key] = $sub_dir;
  650. }
  651. }
  652. }
  653. else
  654. {
  655. if ( ! isset($found[$key]))
  656. {
  657. // Add new files to the list
  658. $found[$key] = realpath($file->getPathName());
  659. }
  660. }
  661. }
  662. }
  663. }
  664. // Sort the results alphabetically
  665. ksort($found);
  666. return $found;
  667. }
  668. /**
  669. * Loads a file within a totally empty scope and returns the output:
  670. *
  671. * $foo = Kohana::load('foo.php');
  672. *
  673. * @param string
  674. * @return mixed
  675. */
  676. public static function load($file)
  677. {
  678. return include $file;
  679. }
  680. /**
  681. * Returns the configuration array for the requested group. See
  682. * [configuration files](kohana/files/config) for more information.
  683. *
  684. * // Get all the configuration in config/database.php
  685. * $config = Kohana::config('database');
  686. *
  687. * // Get only the default connection configuration
  688. * $default = Kohana::config('database.default')
  689. *
  690. * // Get only the hostname of the default connection
  691. * $host = Kohana::config('database.default.connection.hostname')
  692. *
  693. * @param string group name
  694. * @return Config
  695. */
  696. public static function config($group)
  697. {
  698. static $config;
  699. if (strpos($group, '.') !== FALSE)
  700. {
  701. // Split the config group and path
  702. list ($group, $path) = explode('.', $group, 2);
  703. }
  704. if ( ! isset($config[$group]))
  705. {
  706. // Load the config group into the cache
  707. $config[$group] = Kohana::$config->load($group);
  708. }
  709. if (isset($path))
  710. {
  711. return Arr::path($config[$group], $path, NULL, '.');
  712. }
  713. else
  714. {
  715. return $config[$group];
  716. }
  717. }
  718. /**
  719. * Provides simple file-based caching for strings and arrays:
  720. *
  721. * // Set the "foo" cache
  722. * Kohana::cache('foo', 'hello, world');
  723. *
  724. * // Get the "foo" cache
  725. * $foo = Kohana::cache('foo');
  726. *
  727. * All caches are stored as PHP code, generated with [var_export][ref-var].
  728. * Caching objects may not work as expected. Storing references or an
  729. * object or array that has recursion will cause an E_FATAL.
  730. *
  731. * The cache directory and default cache lifetime is set by [Kohana::init]
  732. *
  733. * [ref-var]: http://php.net/var_export
  734. *
  735. * @throws Kohana_Exception
  736. * @param string name of the cache
  737. * @param mixed data to cache
  738. * @param integer number of seconds the cache is valid for
  739. * @return mixed for getting
  740. * @return boolean for setting
  741. */
  742. public static function cache($name, $data = NULL, $lifetime = NULL)
  743. {
  744. // Cache file is a hash of the name
  745. $file = sha1($name).'.txt';
  746. // Cache directories are split by keys to prevent filesystem overload
  747. $dir = Kohana::$cache_dir.DIRECTORY_SEPARATOR.$file[0].$file[1].DIRECTORY_SEPARATOR;
  748. if ($lifetime === NULL)
  749. {
  750. // Use the default lifetime
  751. $lifetime = Kohana::$cache_life;
  752. }
  753. if ($data === NULL)
  754. {
  755. if (is_file($dir.$file))
  756. {
  757. if ((time() - filemtime($dir.$file)) < $lifetime)
  758. {
  759. // Return the cache
  760. try
  761. {
  762. return unserialize(file_get_contents($dir.$file));
  763. }
  764. catch (Exception $e)
  765. {
  766. // Cache is corrupt, let return happen normally.
  767. }
  768. }
  769. else
  770. {
  771. try
  772. {
  773. // Cache has expired
  774. unlink($dir.$file);
  775. }
  776. catch (Exception $e)
  777. {
  778. // Cache has mostly likely already been deleted,
  779. // let return happen normally.
  780. }
  781. }
  782. }
  783. // Cache not found
  784. return NULL;
  785. }
  786. if ( ! is_dir($dir))
  787. {
  788. // Create the cache directory
  789. mkdir($dir, 0777, TRUE);
  790. // Set permissions (must be manually set to fix umask issues)
  791. chmod($dir, 0777);
  792. }
  793. // Force the data to be a string
  794. $data = serialize($data);
  795. try
  796. {
  797. // Write the cache
  798. return (bool) file_put_contents($dir.$file, $data, LOCK_EX);
  799. }
  800. catch (Exception $e)
  801. {
  802. // Failed to write cache
  803. return FALSE;
  804. }
  805. }
  806. /**
  807. * Get a message from a file. Messages are arbitary strings that are stored
  808. * in the `messages/` directory and reference by a key. Translation is not
  809. * performed on the returned values. See [message files](kohana/files/messages)
  810. * for more information.
  811. *
  812. * // Get "username" from messages/text.php
  813. * $username = Kohana::message('text', 'username');
  814. *
  815. * @param string file name
  816. * @param string key path to get
  817. * @param mixed default value if the path does not exist
  818. * @return string message string for the given path
  819. * @return array complete message list, when no path is specified
  820. * @uses Arr::merge
  821. * @uses Arr::path
  822. */
  823. public static function message($file, $path = NULL, $default = NULL)
  824. {
  825. static $messages;
  826. if ( ! isset($messages[$file]))
  827. {
  828. // Create a new message list
  829. $messages[$file] = array();
  830. if ($files = Kohana::find_file('messages', $file))
  831. {
  832. foreach ($files as $f)
  833. {
  834. // Combine all the messages recursively
  835. $messages[$file] = Arr::merge($messages[$file], Kohana::load($f));
  836. }
  837. }
  838. }
  839. if ($path === NULL)
  840. {
  841. // Return all of the messages
  842. return $messages[$file];
  843. }
  844. else
  845. {
  846. // Get a message using the path
  847. return Arr::path($messages[$file], $path, $default);
  848. }
  849. }
  850. /**
  851. * PHP error handler, converts all errors into ErrorExceptions. This handler
  852. * respects error_reporting settings.
  853. *
  854. * @throws ErrorException
  855. * @return TRUE
  856. */
  857. public static function error_handler($code, $error, $file = NULL, $line = NULL)
  858. {
  859. if (error_reporting() & $code)
  860. {
  861. // This error is not suppressed by current error reporting settings
  862. // Convert the error into an ErrorException
  863. throw new ErrorException($error, $code, 0, $file, $line);
  864. }
  865. // Do not execute the PHP error handler
  866. return TRUE;
  867. }
  868. /**
  869. * Catches errors that are not caught by the error handler, such as E_PARSE.
  870. *
  871. * @uses Kohana_Exception::handler
  872. * @return void
  873. */
  874. public static function shutdown_handler()
  875. {
  876. if ( ! Kohana::$_init)
  877. {
  878. // Do not execute when not active
  879. return;
  880. }
  881. try
  882. {
  883. if (Kohana::$caching === TRUE AND Kohana::$_files_changed === TRUE)
  884. {
  885. // Write the file path cache
  886. Kohana::cache('Kohana::find_file()', Kohana::$_files);
  887. }
  888. }
  889. catch (Exception $e)
  890. {
  891. // Pass the exception to the handler
  892. Kohana_Exception::handler($e);
  893. }
  894. if (Kohana::$errors AND $error = error_get_last() AND in_array($error['type'], Kohana::$shutdown_errors))
  895. {
  896. // Clean the output buffer
  897. ob_get_level() and ob_clean();
  898. // Fake an exception for nice debugging
  899. Kohana_Exception::handler(new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
  900. // Shutdown now to avoid a "death loop"
  901. exit(1);
  902. }
  903. }
  904. } // End Kohana