fix typo
[kohana-core.git] / classes / kohana / core.php
blob1dd28c7f3b02b825d647f3c85584808e83f96e67
1 <?php defined('SYSPATH') or die('No direct script access.');
2 /**
3 * Contains the most low-level helpers methods in Kohana:
5 * - Environment initialization
6 * - Locating files within the cascading filesystem
7 * - Auto-loading and transparent extension of classes
8 * - Variable and path debugging
10 * @package Kohana
11 * @category Base
12 * @author Kohana Team
13 * @copyright (c) 2008-2012 Kohana Team
14 * @license http://kohanaframework.org/license
16 class Kohana_Core {
18 // Release version and codename
19 const VERSION = '3.2.2';
20 const CODENAME = 'hypoleucos';
22 // Common environment type constants for consistency and convenience
23 const PRODUCTION = 10;
24 const STAGING = 20;
25 const TESTING = 30;
26 const DEVELOPMENT = 40;
28 // Security check that is added to all generated PHP files
29 const FILE_SECURITY = '<?php defined(\'SYSPATH\') OR die(\'No direct script access.\');';
31 // Format of cache files: header, cache name, and data
32 const FILE_CACHE = ":header \n\n// :name\n\n:data\n";
34 /**
35 * @var string Current environment name
37 public static $environment = Kohana::DEVELOPMENT;
39 /**
40 * @var boolean True if Kohana is running from the command line
42 public static $is_cli = FALSE;
44 /**
45 * @var boolean True if Kohana is running on windows
47 public static $is_windows = FALSE;
49 /**
50 * @var boolean True if [magic quotes](http://php.net/manual/en/security.magicquotes.php) is enabled.
52 public static $magic_quotes = FALSE;
54 /**
55 * @var boolean Should errors and exceptions be logged
57 public static $log_errors = FALSE;
59 /**
60 * @var boolean TRUE if PHP safe mode is on
62 public static $safe_mode = FALSE;
64 /**
65 * @var string
67 public static $content_type = 'text/html';
69 /**
70 * @var string character set of input and output
72 public static $charset = 'utf-8';
74 /**
75 * @var string the name of the server Kohana is hosted upon
77 public static $server_name = '';
79 /**
80 * @var array list of valid host names for this instance
82 public static $hostnames = array();
84 /**
85 * @var string base URL to the application
87 public static $base_url = '/';
89 /**
90 * @var string Application index file, added to links generated by Kohana. Set by [Kohana::init]
92 public static $index_file = 'index.php';
94 /**
95 * @var string Cache directory, used by [Kohana::cache]. Set by [Kohana::init]
97 public static $cache_dir;
99 /**
100 * @var integer Default lifetime for caching, in seconds, used by [Kohana::cache]. Set by [Kohana::init]
102 public static $cache_life = 60;
105 * @var boolean Whether to use internal caching for [Kohana::find_file], does not apply to [Kohana::cache]. Set by [Kohana::init]
107 public static $caching = FALSE;
110 * @var boolean Whether to enable [profiling](kohana/profiling). Set by [Kohana::init]
112 public static $profiling = TRUE;
115 * @var boolean Enable Kohana catching and displaying PHP errors and exceptions. Set by [Kohana::init]
117 public static $errors = TRUE;
120 * @var array Types of errors to display at shutdown
122 public static $shutdown_errors = array(E_PARSE, E_ERROR, E_USER_ERROR);
125 * @var boolean set the X-Powered-By header
127 public static $expose = FALSE;
130 * @var Log logging object
132 public static $log;
135 * @var Config config object
137 public static $config;
140 * @var boolean Has [Kohana::init] been called?
142 protected static $_init = FALSE;
145 * @var array Currently active modules
147 protected static $_modules = array();
150 * @var array Include paths that are used to find files
152 protected static $_paths = array(APPPATH, SYSPATH);
155 * @var array File path cache, used when caching is true in [Kohana::init]
157 protected static $_files = array();
160 * @var boolean Has the file path cache changed during this execution? Used internally when when caching is true in [Kohana::init]
162 protected static $_files_changed = FALSE;
165 * Initializes the environment:
167 * - Disables register_globals and magic_quotes_gpc
168 * - Determines the current environment
169 * - Set global settings
170 * - Sanitizes GET, POST, and COOKIE variables
171 * - Converts GET, POST, and COOKIE variables to the global character set
173 * The following settings can be set:
175 * Type | Setting | Description | Default Value
176 * ----------|------------|------------------------------------------------|---------------
177 * `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. | `"/"`
178 * `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"`
179 * `string` | charset | Character set used for all input and output | `"utf-8"`
180 * `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"`
181 * `integer` | cache_life | Lifetime, in seconds, of items cached by [Kohana::cache] | `60`
182 * `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`
183 * `boolean` | profile | Whether to enable the [Profiler](kohana/profiling). <br /> <br />Recommended setting: `TRUE` while developing, `FALSE` on production servers. | `TRUE`
184 * `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`
185 * `boolean` | expose | Set the X-Powered-By header
187 * @throws Kohana_Exception
188 * @param array $settings Array of settings. See above.
189 * @return void
190 * @uses Kohana::globals
191 * @uses Kohana::sanitize
192 * @uses Kohana::cache
193 * @uses Profiler
195 public static function init(array $settings = NULL)
197 if (Kohana::$_init)
199 // Do not allow execution twice
200 return;
203 // Kohana is now initialized
204 Kohana::$_init = TRUE;
206 if (isset($settings['profile']))
208 // Enable profiling
209 Kohana::$profiling = (bool) $settings['profile'];
212 // Start an output buffer
213 ob_start();
215 if (isset($settings['errors']))
217 // Enable error handling
218 Kohana::$errors = (bool) $settings['errors'];
221 if (Kohana::$errors === TRUE)
223 // Enable Kohana exception handling, adds stack traces and error source.
224 set_exception_handler(array('Kohana_Exception', 'handler'));
226 // Enable Kohana error handling, converts all PHP errors to exceptions.
227 set_error_handler(array('Kohana', 'error_handler'));
230 // Enable the Kohana shutdown handler, which catches E_FATAL errors.
231 register_shutdown_function(array('Kohana', 'shutdown_handler'));
233 if (ini_get('register_globals'))
235 // Reverse the effects of register_globals
236 Kohana::globals();
239 if (isset($settings['expose']))
241 Kohana::$expose = (bool) $settings['expose'];
244 // Determine if we are running in a command line environment
245 Kohana::$is_cli = (PHP_SAPI === 'cli');
247 // Determine if we are running in a Windows environment
248 Kohana::$is_windows = (DIRECTORY_SEPARATOR === '\\');
250 // Determine if we are running in safe mode
251 Kohana::$safe_mode = (bool) ini_get('safe_mode');
253 if (isset($settings['cache_dir']))
255 if ( ! is_dir($settings['cache_dir']))
259 // Create the cache directory
260 mkdir($settings['cache_dir'], 0755, TRUE);
262 // Set permissions (must be manually set to fix umask issues)
263 chmod($settings['cache_dir'], 0755);
265 catch (Exception $e)
267 throw new Kohana_Exception('Could not create cache directory :dir',
268 array(':dir' => Debug::path($settings['cache_dir'])));
272 // Set the cache directory path
273 Kohana::$cache_dir = realpath($settings['cache_dir']);
275 else
277 // Use the default cache directory
278 Kohana::$cache_dir = APPPATH.'cache';
281 if ( ! is_writable(Kohana::$cache_dir))
283 throw new Kohana_Exception('Directory :dir must be writable',
284 array(':dir' => Debug::path(Kohana::$cache_dir)));
287 if (isset($settings['cache_life']))
289 // Set the default cache lifetime
290 Kohana::$cache_life = (int) $settings['cache_life'];
293 if (isset($settings['caching']))
295 // Enable or disable internal caching
296 Kohana::$caching = (bool) $settings['caching'];
299 if (Kohana::$caching === TRUE)
301 // Load the file path cache
302 Kohana::$_files = Kohana::cache('Kohana::find_file()');
305 if (isset($settings['charset']))
307 // Set the system character set
308 Kohana::$charset = strtolower($settings['charset']);
311 if (function_exists('mb_internal_encoding'))
313 // Set the MB extension encoding to the same character set
314 mb_internal_encoding(Kohana::$charset);
317 if (isset($settings['base_url']))
319 // Set the base URL
320 Kohana::$base_url = rtrim($settings['base_url'], '/').'/';
323 if (isset($settings['index_file']))
325 // Set the index file
326 Kohana::$index_file = trim($settings['index_file'], '/');
329 // Determine if the extremely evil magic quotes are enabled
330 Kohana::$magic_quotes = (version_compare(PHP_VERSION, '5.4') < 0 AND get_magic_quotes_gpc());
332 // Sanitize all request variables
333 $_GET = Kohana::sanitize($_GET);
334 $_POST = Kohana::sanitize($_POST);
335 $_COOKIE = Kohana::sanitize($_COOKIE);
337 // Load the logger if one doesn't already exist
338 if ( ! Kohana::$log instanceof Log)
340 Kohana::$log = Log::instance();
343 // Load the config if one doesn't already exist
344 if ( ! Kohana::$config instanceof Config)
346 Kohana::$config = new Config;
351 * Cleans up the environment:
353 * - Restore the previous error and exception handlers
354 * - Destroy the Kohana::$log and Kohana::$config objects
356 * @return void
358 public static function deinit()
360 if (Kohana::$_init)
362 // Removed the autoloader
363 spl_autoload_unregister(array('Kohana', 'auto_load'));
365 if (Kohana::$errors)
367 // Go back to the previous error handler
368 restore_error_handler();
370 // Go back to the previous exception handler
371 restore_exception_handler();
374 // Destroy objects created by init
375 Kohana::$log = Kohana::$config = NULL;
377 // Reset internal storage
378 Kohana::$_modules = Kohana::$_files = array();
379 Kohana::$_paths = array(APPPATH, SYSPATH);
381 // Reset file cache status
382 Kohana::$_files_changed = FALSE;
384 // Kohana is no longer initialized
385 Kohana::$_init = FALSE;
390 * Reverts the effects of the `register_globals` PHP setting by unsetting
391 * all global variables except for the default super globals (GPCS, etc),
392 * which is a [potential security hole.][ref-wikibooks]
394 * This is called automatically by [Kohana::init] if `register_globals` is
395 * on.
398 * [ref-wikibooks]: http://en.wikibooks.org/wiki/PHP_Programming/Register_Globals
400 * @return void
402 public static function globals()
404 if (isset($_REQUEST['GLOBALS']) OR isset($_FILES['GLOBALS']))
406 // Prevent malicious GLOBALS overload attack
407 echo "Global variable overload attack detected! Request aborted.\n";
409 // Exit with an error status
410 exit(1);
413 // Get the variable names of all globals
414 $global_variables = array_keys($GLOBALS);
416 // Remove the standard global variables from the list
417 $global_variables = array_diff($global_variables, array(
418 '_COOKIE',
419 '_ENV',
420 '_GET',
421 '_FILES',
422 '_POST',
423 '_REQUEST',
424 '_SERVER',
425 '_SESSION',
426 'GLOBALS',
429 foreach ($global_variables as $name)
431 // Unset the global variable, effectively disabling register_globals
432 unset($GLOBALS[$name]);
437 * Recursively sanitizes an input variable:
439 * - Strips slashes if magic quotes are enabled
440 * - Normalizes all newlines to LF
442 * @param mixed $value any variable
443 * @return mixed sanitized variable
445 public static function sanitize($value)
447 if (is_array($value) OR is_object($value))
449 foreach ($value as $key => $val)
451 // Recursively clean each value
452 $value[$key] = Kohana::sanitize($val);
455 elseif (is_string($value))
457 if (Kohana::$magic_quotes === TRUE)
459 // Remove slashes added by magic quotes
460 $value = stripslashes($value);
463 if (strpos($value, "\r") !== FALSE)
465 // Standardize newlines
466 $value = str_replace(array("\r\n", "\r"), "\n", $value);
470 return $value;
474 * Provides auto-loading support of classes that follow Kohana's [class
475 * naming conventions](kohana/conventions#class-names-and-file-location).
476 * See [Loading Classes](kohana/autoloading) for more information.
478 * Class names are converted to file names by making the class name
479 * lowercase and converting underscores to slashes:
481 * // Loads classes/my/class/name.php
482 * Kohana::auto_load('My_Class_Name');
484 * You should never have to call this function, as simply calling a class
485 * will cause it to be called.
487 * This function must be enabled as an autoloader in the bootstrap:
489 * spl_autoload_register(array('Kohana', 'auto_load'));
491 * @param string $class class name
492 * @return boolean
494 public static function auto_load($class)
498 // Transform the class name into a path
499 $file = str_replace('_', '/', strtolower($class));
501 if ($path = Kohana::find_file('classes', $file))
503 // Load the class file
504 require $path;
506 // Class has been found
507 return TRUE;
510 // Class is not in the filesystem
511 return FALSE;
513 catch (Exception $e)
515 Kohana_Exception::handler($e);
516 die;
521 * Changes the currently enabled modules. Module paths may be relative
522 * or absolute, but must point to a directory:
524 * Kohana::modules(array('modules/foo', MODPATH.'bar'));
526 * @param array $modules list of module paths
527 * @return array enabled modules
529 public static function modules(array $modules = NULL)
531 if ($modules === NULL)
533 // Not changing modules, just return the current set
534 return Kohana::$_modules;
537 // Start a new list of include paths, APPPATH first
538 $paths = array(APPPATH);
540 foreach ($modules as $name => $path)
542 if (is_dir($path))
544 // Add the module to include paths
545 $paths[] = $modules[$name] = realpath($path).DIRECTORY_SEPARATOR;
547 else
549 // This module is invalid, remove it
550 throw new Kohana_Exception('Attempted to load an invalid or missing module \':module\' at \':path\'', array(
551 ':module' => $name,
552 ':path' => Debug::path($path),
557 // Finish the include paths by adding SYSPATH
558 $paths[] = SYSPATH;
560 // Set the new include paths
561 Kohana::$_paths = $paths;
563 // Set the current module list
564 Kohana::$_modules = $modules;
566 foreach (Kohana::$_modules as $path)
568 $init = $path.'init'.EXT;
570 if (is_file($init))
572 // Include the module initialization file once
573 require_once $init;
577 return Kohana::$_modules;
581 * Returns the the currently active include paths, including the
582 * application, system, and each module's path.
584 * @return array
586 public static function include_paths()
588 return Kohana::$_paths;
592 * Searches for a file in the [Cascading Filesystem](kohana/files), and
593 * returns the path to the file that has the highest precedence, so that it
594 * can be included.
596 * When searching the "config", "messages", or "i18n" directories, or when
597 * the `$array` flag is set to true, an array of all the files that match
598 * that path in the [Cascading Filesystem](kohana/files) will be returned.
599 * These files will return arrays which must be merged together.
601 * If no extension is given, the default extension (`EXT` set in
602 * `index.php`) will be used.
604 * // Returns an absolute path to views/template.php
605 * Kohana::find_file('views', 'template');
607 * // Returns an absolute path to media/css/style.css
608 * Kohana::find_file('media', 'css/style', 'css');
610 * // Returns an array of all the "mimes" configuration files
611 * Kohana::find_file('config', 'mimes');
613 * @param string $dir directory name (views, i18n, classes, extensions, etc.)
614 * @param string $file filename with subdirectory
615 * @param string $ext extension to search for
616 * @param boolean $array return an array of files?
617 * @return array a list of files when $array is TRUE
618 * @return string single file path
620 public static function find_file($dir, $file, $ext = NULL, $array = FALSE)
622 if ($ext === NULL)
624 // Use the default extension
625 $ext = EXT;
627 elseif ($ext)
629 // Prefix the extension with a period
630 $ext = ".{$ext}";
632 else
634 // Use no extension
635 $ext = '';
638 // Create a partial path of the filename
639 $path = $dir.DIRECTORY_SEPARATOR.$file.$ext;
641 if (Kohana::$caching === TRUE AND isset(Kohana::$_files[$path.($array ? '_array' : '_path')]))
643 // This path has been cached
644 return Kohana::$_files[$path.($array ? '_array' : '_path')];
647 if (Kohana::$profiling === TRUE AND class_exists('Profiler', FALSE))
649 // Start a new benchmark
650 $benchmark = Profiler::start('Kohana', __FUNCTION__);
653 if ($array OR $dir === 'config' OR $dir === 'i18n' OR $dir === 'messages')
655 // Include paths must be searched in reverse
656 $paths = array_reverse(Kohana::$_paths);
658 // Array of files that have been found
659 $found = array();
661 foreach ($paths as $dir)
663 if (is_file($dir.$path))
665 // This path has a file, add it to the list
666 $found[] = $dir.$path;
670 else
672 // The file has not been found yet
673 $found = FALSE;
675 foreach (Kohana::$_paths as $dir)
677 if (is_file($dir.$path))
679 // A path has been found
680 $found = $dir.$path;
682 // Stop searching
683 break;
688 if (Kohana::$caching === TRUE)
690 // Add the path to the cache
691 Kohana::$_files[$path.($array ? '_array' : '_path')] = $found;
693 // Files have been changed
694 Kohana::$_files_changed = TRUE;
697 if (isset($benchmark))
699 // Stop the benchmark
700 Profiler::stop($benchmark);
703 return $found;
707 * Recursively finds all of the files in the specified directory at any
708 * location in the [Cascading Filesystem](kohana/files), and returns an
709 * array of all the files found, sorted alphabetically.
711 * // Find all view files.
712 * $views = Kohana::list_files('views');
714 * @param string $directory directory name
715 * @param array $paths list of paths to search
716 * @return array
718 public static function list_files($directory = NULL, array $paths = NULL)
720 if ($directory !== NULL)
722 // Add the directory separator
723 $directory .= DIRECTORY_SEPARATOR;
726 if ($paths === NULL)
728 // Use the default paths
729 $paths = Kohana::$_paths;
732 // Create an array for the files
733 $found = array();
735 foreach ($paths as $path)
737 if (is_dir($path.$directory))
739 // Create a new directory iterator
740 $dir = new DirectoryIterator($path.$directory);
742 foreach ($dir as $file)
744 // Get the file name
745 $filename = $file->getFilename();
747 if ($filename[0] === '.' OR $filename[strlen($filename)-1] === '~')
749 // Skip all hidden files and UNIX backup files
750 continue;
753 // Relative filename is the array key
754 $key = $directory.$filename;
756 if ($file->isDir())
758 if ($sub_dir = Kohana::list_files($key, $paths))
760 if (isset($found[$key]))
762 // Append the sub-directory list
763 $found[$key] += $sub_dir;
765 else
767 // Create a new sub-directory list
768 $found[$key] = $sub_dir;
772 else
774 if ( ! isset($found[$key]))
776 // Add new files to the list
777 $found[$key] = realpath($file->getPathName());
784 // Sort the results alphabetically
785 ksort($found);
787 return $found;
791 * Loads a file within a totally empty scope and returns the output:
793 * $foo = Kohana::load('foo.php');
795 * @param string $file
796 * @return mixed
798 public static function load($file)
800 return include $file;
804 * Provides simple file-based caching for strings and arrays:
806 * // Set the "foo" cache
807 * Kohana::cache('foo', 'hello, world');
809 * // Get the "foo" cache
810 * $foo = Kohana::cache('foo');
812 * All caches are stored as PHP code, generated with [var_export][ref-var].
813 * Caching objects may not work as expected. Storing references or an
814 * object or array that has recursion will cause an E_FATAL.
816 * The cache directory and default cache lifetime is set by [Kohana::init]
818 * [ref-var]: http://php.net/var_export
820 * @throws Kohana_Exception
821 * @param string $name name of the cache
822 * @param mixed $data data to cache
823 * @param integer $lifetime number of seconds the cache is valid for
824 * @return mixed for getting
825 * @return boolean for setting
827 public static function cache($name, $data = NULL, $lifetime = NULL)
829 // Cache file is a hash of the name
830 $file = sha1($name).'.txt';
832 // Cache directories are split by keys to prevent filesystem overload
833 $dir = Kohana::$cache_dir.DIRECTORY_SEPARATOR.$file[0].$file[1].DIRECTORY_SEPARATOR;
835 if ($lifetime === NULL)
837 // Use the default lifetime
838 $lifetime = Kohana::$cache_life;
841 if ($data === NULL)
843 if (is_file($dir.$file))
845 if ((time() - filemtime($dir.$file)) < $lifetime)
847 // Return the cache
850 return unserialize(file_get_contents($dir.$file));
852 catch (Exception $e)
854 // Cache is corrupt, let return happen normally.
857 else
861 // Cache has expired
862 unlink($dir.$file);
864 catch (Exception $e)
866 // Cache has mostly likely already been deleted,
867 // let return happen normally.
872 // Cache not found
873 return NULL;
876 if ( ! is_dir($dir))
878 // Create the cache directory
879 mkdir($dir, 0777, TRUE);
881 // Set permissions (must be manually set to fix umask issues)
882 chmod($dir, 0777);
885 // Force the data to be a string
886 $data = serialize($data);
890 // Write the cache
891 return (bool) file_put_contents($dir.$file, $data, LOCK_EX);
893 catch (Exception $e)
895 // Failed to write cache
896 return FALSE;
901 * Get a message from a file. Messages are arbitrary strings that are stored
902 * in the `messages/` directory and reference by a key. Translation is not
903 * performed on the returned values. See [message files](kohana/files/messages)
904 * for more information.
906 * // Get "username" from messages/text.php
907 * $username = Kohana::message('text', 'username');
909 * @param string $file file name
910 * @param string $path key path to get
911 * @param mixed $default default value if the path does not exist
912 * @return string message string for the given path
913 * @return array complete message list, when no path is specified
914 * @uses Arr::merge
915 * @uses Arr::path
917 public static function message($file, $path = NULL, $default = NULL)
919 static $messages;
921 if ( ! isset($messages[$file]))
923 // Create a new message list
924 $messages[$file] = array();
926 if ($files = Kohana::find_file('messages', $file))
928 foreach ($files as $f)
930 // Combine all the messages recursively
931 $messages[$file] = Arr::merge($messages[$file], Kohana::load($f));
936 if ($path === NULL)
938 // Return all of the messages
939 return $messages[$file];
941 else
943 // Get a message using the path
944 return Arr::path($messages[$file], $path, $default);
949 * PHP error handler, converts all errors into ErrorExceptions. This handler
950 * respects error_reporting settings.
952 * @throws ErrorException
953 * @return TRUE
955 public static function error_handler($code, $error, $file = NULL, $line = NULL)
957 if (error_reporting() & $code)
959 // This error is not suppressed by current error reporting settings
960 // Convert the error into an ErrorException
961 throw new ErrorException($error, $code, 0, $file, $line);
964 // Do not execute the PHP error handler
965 return TRUE;
969 * Catches errors that are not caught by the error handler, such as E_PARSE.
971 * @return void
973 public static function shutdown_handler()
976 * $shutdown_handler_visited is a static function variable
977 * that will test if this function is already passed
978 * through by PHP runtime.
980 * If it is passed through already, we should exit with
981 * an error status.
983 * The second registration occurs inside Kohana's default
984 * exception handler.
986 * @see issue #3931
988 static $shutdown_handler_visited = FALSE;
989 if ($shutdown_handler_visited) {
990 exit(1);
992 $shutdown_handler_visited = TRUE;
994 if ( ! Kohana::$_init)
996 // Do not execute when not active
997 return;
1000 // Retrieve the current exception handler
1001 $handler = set_exception_handler(array('Kohana_Exception', 'handler'));
1003 // Restore it back to it's previous state
1004 restore_exception_handler();
1008 if (Kohana::$caching === TRUE AND Kohana::$_files_changed === TRUE)
1010 // Write the file path cache
1011 Kohana::cache('Kohana::find_file()', Kohana::$_files);
1014 catch (Exception $e)
1016 // Pass the exception to the handler
1017 call_user_func($handler, $e);
1020 if (Kohana::$errors AND $error = error_get_last() AND in_array($error['type'], Kohana::$shutdown_errors))
1022 // Clean the output buffer
1023 ob_get_level() and ob_clean();
1025 // Fake an exception for nice debugging
1026 call_user_func($handler, new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
1028 // Shutdown now to avoid a "death loop"
1029 exit(1);
1033 } // End Kohana