system\classes\Kohana\Core.php 核心文件

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