2009-02-24 09:15:11 +02:00
|
|
|
<?php defined('SYSPATH') or die('No direct script access.');
|
2008-12-05 03:37:18 +02:00
|
|
|
/**
|
|
|
|
* Contains the most low-level helpers methods in Kohana:
|
|
|
|
*
|
|
|
|
* - Environment initialization
|
|
|
|
* - Locating files within the cascading filesystem
|
|
|
|
* - Auto-loading and transparent extension of classes
|
|
|
|
* - Variable and path debugging
|
|
|
|
*
|
2009-03-21 00:01:47 +02:00
|
|
|
* @package Kohana
|
2008-12-05 03:37:18 +02:00
|
|
|
* @author Kohana Team
|
2009-02-28 13:40:13 +02:00
|
|
|
* @copyright (c) 2008-2009 Kohana Team
|
2008-12-05 03:37:18 +02:00
|
|
|
* @license http://kohanaphp.com/license.html
|
|
|
|
*/
|
|
|
|
final class Kohana {
|
|
|
|
|
2009-04-07 03:10:32 +03:00
|
|
|
// Release version and codename
|
2008-12-12 07:43:18 +02:00
|
|
|
const VERSION = '3.0';
|
|
|
|
const CODENAME = 'renaissance';
|
2008-12-10 07:07:41 +02:00
|
|
|
|
2009-04-05 07:06:18 +03:00
|
|
|
// Log message types
|
|
|
|
const ERROR = 'ERROR';
|
|
|
|
const DEBUG = 'DEBUG';
|
|
|
|
const INFO = 'INFO';
|
|
|
|
|
2009-02-24 09:15:11 +02:00
|
|
|
// Security check that is added to all generated PHP files
|
2009-03-02 02:02:22 +02:00
|
|
|
const PHP_HEADER = '<?php defined(\'SYSPATH\') or die(\'No direct script access.\');';
|
2008-12-10 07:07:41 +02:00
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
/**
|
|
|
|
* @var boolean command line environment?
|
|
|
|
*/
|
2009-02-28 13:40:13 +02:00
|
|
|
public static $is_cli = FALSE;
|
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
/**
|
|
|
|
* @var boolean Windows environment?
|
|
|
|
*/
|
2009-02-28 13:40:13 +02:00
|
|
|
public static $is_windows = FALSE;
|
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
/**
|
|
|
|
* @var boolean magic quotes enabled?
|
|
|
|
*/
|
|
|
|
public static $magic_quotes = FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var boolean display errors and exceptions in output?
|
|
|
|
*/
|
|
|
|
public static $display_errors = TRUE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var boolean log errors and exceptions?
|
|
|
|
*/
|
2009-03-02 02:02:22 +02:00
|
|
|
public static $log_errors = FALSE;
|
2009-03-01 15:43:44 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string character set of input and output
|
|
|
|
*/
|
2009-02-28 13:40:13 +02:00
|
|
|
public static $charset = 'utf-8';
|
|
|
|
|
2009-04-18 00:41:28 +03:00
|
|
|
/**
|
|
|
|
* @var string base URL to the application
|
|
|
|
*/
|
|
|
|
public static $base_url = '/';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var boolean cache the location of files across requests?
|
|
|
|
*/
|
|
|
|
public static $cache_paths = FALSE;
|
|
|
|
|
2009-04-05 07:06:18 +03:00
|
|
|
/**
|
|
|
|
* @var object logging object
|
|
|
|
*/
|
|
|
|
public static $log;
|
|
|
|
|
2009-02-24 09:15:11 +02:00
|
|
|
// Currently active modules
|
|
|
|
private static $_modules = array();
|
2008-12-15 00:16:00 +02:00
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
// Include paths that are used to find files
|
2009-02-24 09:15:11 +02:00
|
|
|
private static $_paths = array(APPPATH, SYSPATH);
|
2008-12-12 07:43:18 +02:00
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
/**
|
|
|
|
* Initializes the environment:
|
|
|
|
*
|
2009-03-01 15:43:44 +02:00
|
|
|
* - Disables register_globals and magic_quotes_gpc
|
|
|
|
* - Determines the current environment
|
|
|
|
* - Set global settings
|
|
|
|
* - Sanitizes GET, POST, and COOKIE variables
|
|
|
|
* - Converts GET, POST, and COOKIE variables to the global character set
|
|
|
|
*
|
|
|
|
* Any of the global settings can be set here:
|
|
|
|
*
|
|
|
|
* > boolean "display_errors" : display errors and exceptions
|
|
|
|
* > boolean "log_errors" : log errors and exceptions
|
|
|
|
* > boolean "cache_paths" : cache the location of files between requests
|
|
|
|
* > string "charset" : character set used for all input and output
|
2008-12-05 03:37:18 +02:00
|
|
|
*
|
2009-03-01 15:43:44 +02:00
|
|
|
* @param array global settings
|
2008-12-05 03:37:18 +02:00
|
|
|
* @return void
|
|
|
|
*/
|
2009-03-01 15:43:44 +02:00
|
|
|
public static function init(array $settings = NULL)
|
2008-12-05 03:37:18 +02:00
|
|
|
{
|
2009-02-24 09:15:11 +02:00
|
|
|
static $_init;
|
2008-12-12 07:43:18 +02:00
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
// This function can only be run once
|
|
|
|
if ($_init === TRUE) return;
|
2008-12-12 07:43:18 +02:00
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
// The system will now be initialized
|
2009-02-24 09:15:11 +02:00
|
|
|
$_init = TRUE;
|
2009-03-01 15:43:44 +02:00
|
|
|
|
2009-03-21 00:01:47 +02:00
|
|
|
// Start an output buffer
|
|
|
|
ob_start();
|
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
if (version_compare(PHP_VERSION, '6.0', '<='))
|
|
|
|
{
|
|
|
|
// Disable magic quotes at runtime
|
|
|
|
set_magic_quotes_runtime(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ini_get('register_globals'))
|
|
|
|
{
|
|
|
|
if (isset($_REQUEST['GLOBALS']))
|
|
|
|
{
|
|
|
|
// Prevent malicious GLOBALS overload attack
|
|
|
|
echo "Global variable overload attack detected! Request aborted.\n";
|
|
|
|
|
|
|
|
// Exit with an error status
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the variable names of all globals
|
|
|
|
$global_variables = array_keys($GLOBALS);
|
|
|
|
|
|
|
|
// Remove the standard global variables from the list
|
|
|
|
$global_variables = array_diff($global_vars,
|
|
|
|
array('GLOBALS', '_REQUEST', '_GET', '_POST', '_FILES', '_COOKIE', '_SERVER', '_ENV', '_SESSION'));
|
|
|
|
|
|
|
|
foreach ($global_variables as $name)
|
|
|
|
{
|
|
|
|
// Retrieve the global variable and make it null
|
|
|
|
global $$name;
|
|
|
|
$$name = NULL;
|
|
|
|
|
|
|
|
// Unset the global variable, effectively disabling register_globals
|
|
|
|
unset($GLOBALS[$name], $$name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if we are running in a command line environment
|
|
|
|
self::$is_cli = (PHP_SAPI === 'cli');
|
|
|
|
|
|
|
|
// Determine if we are running in a Windows environment
|
|
|
|
self::$is_windows = (DIRECTORY_SEPARATOR === '\\');
|
|
|
|
|
|
|
|
if (isset($settings['display_errors']))
|
|
|
|
{
|
|
|
|
// Enable or disable the display of errors
|
|
|
|
self::$display_errors = (bool) $settings['display_errors'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($settings['cache_paths']))
|
|
|
|
{
|
|
|
|
// Enable or disable the caching of paths
|
|
|
|
self::$cache_paths = (bool) $settings['cache_paths'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($settings['charset']))
|
|
|
|
{
|
|
|
|
// Set the system character set
|
|
|
|
self::$charset = strtolower($settings['charset']);
|
|
|
|
}
|
|
|
|
|
2009-04-18 00:41:28 +03:00
|
|
|
if (isset($settings['base_url']))
|
|
|
|
{
|
|
|
|
// Set the base URL
|
|
|
|
self::$base_url = rtrim($settings['base_url'], '/').'/';
|
|
|
|
}
|
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
// Determine if the extremely evil magic quotes are enabled
|
|
|
|
self::$magic_quotes = (bool) get_magic_quotes_gpc();
|
|
|
|
|
|
|
|
// Sanitize all request variables
|
|
|
|
$_GET = self::sanitize($_GET);
|
|
|
|
$_POST = self::sanitize($_POST);
|
|
|
|
$_COOKIE = self::sanitize($_COOKIE);
|
|
|
|
|
2009-04-05 07:06:18 +03:00
|
|
|
// Load the logger
|
|
|
|
self::$log = Kohana_Log::instance();
|
|
|
|
|
2009-03-21 00:01:47 +02:00
|
|
|
// Determine if this server supports UTF-8 natively
|
|
|
|
utf8::$server_utf8 = extension_loaded('mbstring');
|
|
|
|
|
2009-03-01 15:43:44 +02:00
|
|
|
// Normalize all request variables to the current charset
|
|
|
|
$_GET = utf8::clean($_GET, self::$charset);
|
|
|
|
$_POST = utf8::clean($_POST, self::$charset);
|
|
|
|
$_COOKIE = utf8::clean($_COOKIE, self::$charset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively sanitizes an input variable:
|
|
|
|
*
|
|
|
|
* - Removes slashes if magic quotes are enabled
|
|
|
|
* - Normalizes all newlines to LF
|
|
|
|
*
|
|
|
|
* @param mixed any variable
|
|
|
|
* @return mixed sanitized variable
|
|
|
|
*/
|
|
|
|
public static function sanitize($value)
|
|
|
|
{
|
|
|
|
if (is_array($value) OR is_object($value))
|
|
|
|
{
|
|
|
|
foreach ($value as $key => $val)
|
|
|
|
{
|
|
|
|
// Recursively clean each value
|
|
|
|
$value[$key] = self::sanitize($val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (is_string($value))
|
|
|
|
{
|
|
|
|
if (self::$magic_quotes === TRUE)
|
|
|
|
{
|
|
|
|
// Remove slashes added by magic quotes
|
|
|
|
$value = stripslashes($value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strpos($value, "\r") !== FALSE)
|
|
|
|
{
|
|
|
|
// Standardize newlines
|
|
|
|
$value = str_replace(array("\r\n", "\r"), "\n", $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $value;
|
2008-12-10 07:07:41 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 07:43:18 +02:00
|
|
|
/**
|
|
|
|
* Provides auto-loading support of Kohana classes, as well as transparent
|
|
|
|
* extension of classes that have a _Core suffix.
|
|
|
|
*
|
|
|
|
* Class names are converted to file names by making the class name
|
|
|
|
* lowercase and converting underscores to slashes:
|
|
|
|
*
|
|
|
|
* // Loads classes/my/class/name.php
|
|
|
|
* Kohana::auto_load('My_Class_Name');
|
|
|
|
*
|
|
|
|
* @param string class name
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public static function auto_load($class)
|
|
|
|
{
|
|
|
|
// Transform the class name into a path
|
|
|
|
$file = str_replace('_', '/', strtolower($class));
|
|
|
|
|
|
|
|
if ($path = self::find_file('classes', $file))
|
|
|
|
{
|
|
|
|
// Load the class file
|
|
|
|
require $path;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-21 00:01:47 +02:00
|
|
|
// Class is not in the filesystem
|
2008-12-12 07:43:18 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($path = self::find_file('extensions', $file))
|
|
|
|
{
|
|
|
|
// Load the extension file
|
|
|
|
require $path;
|
|
|
|
}
|
|
|
|
elseif (class_exists($class.'_Core', FALSE))
|
|
|
|
{
|
|
|
|
if (($extension = Kohana::cache('kohana_auto_extension '.$class)) === NULL)
|
|
|
|
{
|
|
|
|
// Class extension to be evaluated
|
|
|
|
$extension = 'class '.$class.' extends '.$class.'_Core { }';
|
|
|
|
|
|
|
|
// Use reflection to find out of the class is abstract
|
|
|
|
$class = new ReflectionClass($class.'_Core');
|
|
|
|
|
|
|
|
if ($class->isAbstract())
|
|
|
|
{
|
|
|
|
// Make the extension abstract, too
|
|
|
|
$extension = 'abstract '.$extension;
|
|
|
|
}
|
|
|
|
|
2009-03-08 17:39:32 +02:00
|
|
|
// Cache the extension string so that Reflection will be avoided
|
2008-12-12 07:43:18 +02:00
|
|
|
Kohana::cache('kohana_auto_extension '.$class, $extension);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transparent class extensions are possible using eval. Not very
|
|
|
|
// clean, but it can be avoided by creating empty extension files.
|
|
|
|
eval($extension);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-12-10 07:07:41 +02:00
|
|
|
/**
|
|
|
|
* Changes the currently enabled modules. Module paths may be relative
|
|
|
|
* or absolute, but must point to a directory:
|
2009-03-01 15:46:10 +02:00
|
|
|
*
|
2008-12-10 07:07:41 +02:00
|
|
|
* Kohana::modules(array('modules/foo', MODPATH.'bar'));
|
2009-03-01 15:46:10 +02:00
|
|
|
*
|
2009-03-21 00:01:47 +02:00
|
|
|
* @param array list of module paths
|
|
|
|
* @return array enabled modules
|
2008-12-10 07:07:41 +02:00
|
|
|
*/
|
2009-02-24 09:15:11 +02:00
|
|
|
public static function modules(array $modules = NULL)
|
2008-12-10 07:07:41 +02:00
|
|
|
{
|
2008-12-15 00:16:00 +02:00
|
|
|
if ($modules === NULL)
|
2009-02-24 09:15:11 +02:00
|
|
|
return self::$_modules;
|
2008-12-15 00:16:00 +02:00
|
|
|
|
2008-12-15 00:45:14 +02:00
|
|
|
// Start a new list of include paths, APPPATH first
|
2009-02-24 09:15:11 +02:00
|
|
|
$paths = array(APPPATH);
|
2008-12-10 07:07:41 +02:00
|
|
|
|
2008-12-15 00:16:00 +02:00
|
|
|
foreach ($modules as $name => $path)
|
2008-12-10 07:07:41 +02:00
|
|
|
{
|
2008-12-15 00:16:00 +02:00
|
|
|
if (is_dir($path))
|
2008-12-10 07:07:41 +02:00
|
|
|
{
|
|
|
|
// Add the module to include paths
|
2009-02-24 09:15:11 +02:00
|
|
|
$paths[] = realpath($path).DIRECTORY_SEPARATOR;
|
2008-12-15 00:16:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-12-15 00:45:14 +02:00
|
|
|
// This module is invalid, remove it
|
2008-12-15 00:16:00 +02:00
|
|
|
unset($modules[$name]);
|
2008-12-10 07:07:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finish the include paths by adding SYSPATH
|
2009-02-24 09:15:11 +02:00
|
|
|
$paths[] = SYSPATH;
|
2008-12-10 07:07:41 +02:00
|
|
|
|
|
|
|
// Set the new include paths
|
2009-02-24 09:15:11 +02:00
|
|
|
self::$_paths = $paths;
|
2008-12-15 00:45:14 +02:00
|
|
|
|
|
|
|
// Set the current module list
|
2009-02-24 09:15:11 +02:00
|
|
|
return self::$_modules = $modules;
|
2008-12-09 19:03:20 +02:00
|
|
|
}
|
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
/**
|
|
|
|
* Finds the path of a file by directory, filename, and extension.
|
2009-03-08 17:39:32 +02:00
|
|
|
* If no extension is given, the default EXT extension will be used.
|
2008-12-05 03:37:18 +02:00
|
|
|
*
|
2009-03-21 00:01:47 +02:00
|
|
|
* When searching the "config" or "i18n" directory, an array of files
|
|
|
|
* will be returned. These files will return arrays which must be
|
|
|
|
* merged together.
|
|
|
|
*
|
2008-12-05 03:37:18 +02:00
|
|
|
* // Returns an absolute path to views/template.php
|
2009-03-21 00:01:47 +02:00
|
|
|
* Kohana::find_file('views', 'template');
|
2008-12-05 03:37:18 +02:00
|
|
|
*
|
|
|
|
* // Returns an absolute path to media/css/style.css
|
2009-03-21 00:01:47 +02:00
|
|
|
* Kohana::find_file('media', 'css/style', 'css');
|
2009-04-10 00:58:49 +03:00
|
|
|
*
|
2009-03-21 00:01:47 +02:00
|
|
|
* // Returns an array of all the "mimes" configuration file
|
|
|
|
* Kohana::find_file('config', 'mimes');
|
2008-12-05 03:37:18 +02:00
|
|
|
*
|
2009-03-21 00:01:47 +02:00
|
|
|
* @param string directory name (views, i18n, classes, extensions, etc.)
|
2008-12-05 03:37:18 +02:00
|
|
|
* @param string filename with subdirectory
|
|
|
|
* @param string extension to search for
|
2009-03-21 00:01:47 +02:00
|
|
|
* @return string single file found
|
|
|
|
* @return FALSE single file NOT found
|
|
|
|
* @return array multiple files from the "config" or "i18n" directories
|
2008-12-05 03:37:18 +02:00
|
|
|
*/
|
|
|
|
public static function find_file($dir, $file, $ext = NULL)
|
|
|
|
{
|
|
|
|
// Use the defined extension by default
|
|
|
|
$ext = ($ext === NULL) ? EXT : '.'.$ext;
|
|
|
|
|
2008-12-09 08:17:28 +02:00
|
|
|
// Create a partial path of the filename
|
2008-12-10 07:07:41 +02:00
|
|
|
$path = $dir.'/'.$file.$ext;
|
2008-12-05 03:37:18 +02:00
|
|
|
|
2009-03-01 02:32:34 +02:00
|
|
|
if ($dir === 'config' OR $dir === 'i18n')
|
2008-12-12 07:43:18 +02:00
|
|
|
{
|
|
|
|
// Include paths must be searched in reverse
|
2009-03-01 02:32:34 +02:00
|
|
|
$paths = array_reverse(self::$_paths);
|
2008-12-12 07:43:18 +02:00
|
|
|
|
|
|
|
// Array of files that have been found
|
|
|
|
$found = array();
|
|
|
|
|
|
|
|
foreach ($paths as $dir)
|
|
|
|
{
|
2009-03-01 02:32:34 +02:00
|
|
|
if (is_file($dir.$path))
|
2008-12-12 07:43:18 +02:00
|
|
|
{
|
|
|
|
// This path has a file, add it to the list
|
|
|
|
$found[] = $dir.$path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2008-12-05 03:37:18 +02:00
|
|
|
{
|
2008-12-12 07:43:18 +02:00
|
|
|
// The file has not been found yet
|
|
|
|
$found = FALSE;
|
|
|
|
|
2009-02-24 09:15:11 +02:00
|
|
|
foreach (self::$_paths as $dir)
|
2008-12-05 03:37:18 +02:00
|
|
|
{
|
2009-02-24 09:15:11 +02:00
|
|
|
if (is_file($dir.$path))
|
2008-12-12 07:43:18 +02:00
|
|
|
{
|
|
|
|
// A path has been found
|
|
|
|
$found = $dir.$path;
|
2008-12-10 07:34:22 +02:00
|
|
|
|
2008-12-12 07:43:18 +02:00
|
|
|
// Stop searching
|
|
|
|
break;
|
|
|
|
}
|
2008-12-05 03:37:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 07:43:18 +02:00
|
|
|
return $found;
|
2008-12-05 03:37:18 +02:00
|
|
|
}
|
|
|
|
|
2008-12-09 08:17:28 +02:00
|
|
|
/**
|
|
|
|
* Loads a file within a totally empty scope and returns the output:
|
2008-12-09 19:03:20 +02:00
|
|
|
*
|
2009-02-24 09:15:11 +02:00
|
|
|
* $foo = Kohana::load('foo.php');
|
2008-12-09 19:03:20 +02:00
|
|
|
*
|
2008-12-09 08:17:28 +02:00
|
|
|
* @param string
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2009-03-12 12:15:38 +02:00
|
|
|
public static function load($file)
|
2008-12-09 08:17:28 +02:00
|
|
|
{
|
|
|
|
return include $file;
|
|
|
|
}
|
|
|
|
|
2009-03-09 11:54:56 +02:00
|
|
|
/**
|
|
|
|
* Creates a new configuration object for the requested group.
|
2009-03-21 00:01:47 +02:00
|
|
|
*
|
2009-03-09 11:54:56 +02:00
|
|
|
* @param string group name
|
|
|
|
* @param boolean enable caching
|
|
|
|
*/
|
2009-04-07 03:10:32 +03:00
|
|
|
public static function config($group, $cache = TRUE)
|
2009-03-09 11:54:56 +02:00
|
|
|
{
|
|
|
|
return new Kohana_Config($group, $cache);
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
/**
|
2009-03-01 15:46:10 +02:00
|
|
|
* Provides simple file-based caching for strings and arrays:
|
2008-12-09 19:03:20 +02:00
|
|
|
*
|
|
|
|
* // Set the "foo" cache
|
|
|
|
* Kohana::cache('foo', 'hello, world');
|
|
|
|
*
|
|
|
|
* // Get the "foo" cache
|
|
|
|
* $foo = Kohana::cache('foo');
|
|
|
|
*
|
2008-12-12 07:43:18 +02:00
|
|
|
* All caches are stored as PHP code, generated with [var_export][ref-var].
|
|
|
|
* Caching objects may not work as expected. Storing references or an
|
|
|
|
* object or array that has recursion will cause an E_FATAL.
|
2009-03-01 15:46:10 +02:00
|
|
|
*
|
2008-12-12 07:43:18 +02:00
|
|
|
* [ref-var]: http://php.net/var_export
|
2009-03-01 15:46:10 +02:00
|
|
|
*
|
2008-12-09 19:03:20 +02:00
|
|
|
* @param string name of the cache
|
|
|
|
* @param mixed data to cache
|
|
|
|
* @param integer number of seconds the cache is valid for
|
|
|
|
* @return mixed for getting
|
|
|
|
* @return boolean for setting
|
|
|
|
*/
|
2009-04-07 03:10:32 +03:00
|
|
|
public static function cache($name, $data = NULL, $lifetime = 60)
|
2008-12-09 19:03:20 +02:00
|
|
|
{
|
|
|
|
// Cache file is a hash of the name
|
2008-12-12 07:43:18 +02:00
|
|
|
$file = sha1($name).EXT;
|
2008-12-09 19:03:20 +02:00
|
|
|
|
2009-03-01 02:21:53 +02:00
|
|
|
// Cache directories are split by keys to prevent filesystem overload
|
2009-03-21 00:01:47 +02:00
|
|
|
$dir = APPPATH."cache/{$file[0]}/";
|
2008-12-09 19:03:20 +02:00
|
|
|
|
|
|
|
if ($data === NULL)
|
|
|
|
{
|
|
|
|
if (is_file($dir.$file))
|
|
|
|
{
|
|
|
|
if ((time() - filemtime($dir.$file)) < $lifetime)
|
|
|
|
{
|
|
|
|
// Return the cache
|
2008-12-12 07:43:18 +02:00
|
|
|
return include $dir.$file;
|
2008-12-09 19:03:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Cache has expired
|
|
|
|
unlink($dir.$file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache not found
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! is_dir($dir))
|
|
|
|
{
|
|
|
|
// Create the cache directory
|
2009-03-01 02:21:53 +02:00
|
|
|
mkdir($dir, 0777, TRUE);
|
2009-04-10 00:58:49 +03:00
|
|
|
|
|
|
|
// Set permissions (must be manually set to fix umask issues)
|
|
|
|
chmod($dir, 0777);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! is_file($dir.$file))
|
|
|
|
{
|
|
|
|
// Create the file
|
|
|
|
touch($dir.$file);
|
|
|
|
|
|
|
|
// Make the file world writable
|
|
|
|
chmod($dir.$file, 0666);
|
2008-12-09 19:03:20 +02:00
|
|
|
}
|
|
|
|
|
2009-03-21 00:01:47 +02:00
|
|
|
// Convert the data to a string representation
|
|
|
|
$data = var_export($data, TRUE);
|
|
|
|
|
2009-04-10 00:58:49 +03:00
|
|
|
// Write the cache
|
2009-03-21 00:01:47 +02:00
|
|
|
return (bool) file_put_contents($dir.$file, self::PHP_HEADER."\n\nreturn {$data};");
|
2008-12-10 07:07:41 +02:00
|
|
|
}
|
|
|
|
|
2009-03-01 15:46:10 +02:00
|
|
|
/**
|
|
|
|
* PHP error handler, converts all errors into ErrorExceptions. This handler
|
|
|
|
* respects error_reporting settings.
|
|
|
|
*
|
|
|
|
* @throws ErrorException
|
|
|
|
* @return TRUE
|
|
|
|
*/
|
|
|
|
public static function error_handler($code, $error, $file = NULL, $line = NULL)
|
|
|
|
{
|
|
|
|
if ((error_reporting() & $code) !== 0)
|
|
|
|
{
|
|
|
|
// This error is not suppressed by current error reporting settings
|
2009-03-02 02:02:22 +02:00
|
|
|
throw new Kohana_Error($error, $code, 0, $file, $line);
|
2009-03-01 15:46:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Do not execute the PHP error handler
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inline exception handler, displays the error message, source of the
|
|
|
|
* exception, and the stack trace of the error.
|
|
|
|
*
|
|
|
|
* @param object exception object
|
2009-03-02 02:02:22 +02:00
|
|
|
* @return boolean
|
2009-03-01 15:46:10 +02:00
|
|
|
*/
|
|
|
|
public static function exception_handler(Exception $e)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Get the exception information
|
|
|
|
$type = get_class($e);
|
|
|
|
$code = $e->getCode();
|
|
|
|
$message = $e->getMessage();
|
|
|
|
$file = $e->getFile();
|
|
|
|
$line = $e->getLine();
|
|
|
|
|
2009-04-05 07:06:18 +03:00
|
|
|
// Set the text version of the exception
|
|
|
|
$text = "{$type} [ {$code} ]: {$message} ".self::debug_path($file)." [ {$line} ]";
|
|
|
|
|
|
|
|
// Add this exception to the log
|
|
|
|
self::$log->add(Kohana::ERROR, $text);
|
2009-03-02 02:02:22 +02:00
|
|
|
|
2009-03-01 15:46:10 +02:00
|
|
|
if (Kohana::$is_cli)
|
|
|
|
{
|
|
|
|
// Just display the text of the exception
|
2009-04-05 07:06:18 +03:00
|
|
|
echo "\n{$text}\n";
|
2009-03-01 15:46:10 +02:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the exception backtrace
|
|
|
|
$trace = $e->getTrace();
|
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
if ($e instanceof ErrorException AND version_compare(PHP_VERSION, '5.3', '<'))
|
|
|
|
{
|
|
|
|
// Work around for a bug in ErrorException::getTrace() that exists in
|
|
|
|
// all PHP 5.2 versions. @see http://bugs.php.net/bug.php?id=45895
|
|
|
|
for ($i = count($trace) - 1; $i > 0; --$i)
|
|
|
|
{
|
|
|
|
if (isset($trace[$i - 1]['args']))
|
|
|
|
{
|
|
|
|
// Re-position the args
|
|
|
|
$trace[$i]['args'] = $trace[$i - 1]['args'];
|
|
|
|
|
|
|
|
// Remove the args
|
|
|
|
unset($trace[$i - 1]['args']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-01 15:46:10 +02:00
|
|
|
// Get the source of the error
|
2009-03-02 02:02:22 +02:00
|
|
|
$source = self::debug_source($file, $line);
|
2009-03-01 15:46:10 +02:00
|
|
|
|
|
|
|
// Generate a new error id
|
|
|
|
$error_id = uniqid();
|
|
|
|
|
|
|
|
// Start an output buffer
|
|
|
|
ob_start();
|
|
|
|
|
|
|
|
// Include the exception HTML
|
2009-03-02 02:02:22 +02:00
|
|
|
include self::find_file('views', 'kohana/error');
|
2009-03-01 15:46:10 +02:00
|
|
|
|
|
|
|
// Display the contents of the output buffer
|
|
|
|
echo ob_get_clean();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
catch (Exception $e)
|
|
|
|
{
|
|
|
|
// Clean the output buffer if one exists
|
|
|
|
ob_get_level() and ob_clean();
|
|
|
|
|
|
|
|
// This can happen when the kohana error view has a PHP error
|
|
|
|
echo $e->getMessage(), ' [ ', Kohana::debug_path($e->getFile()), ', ', $e->getLine(), ' ]';
|
|
|
|
|
|
|
|
// Exit with an error status
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
/**
|
|
|
|
* Returns an HTML string of debugging information about any number of
|
|
|
|
* variables, each wrapped in a <pre> tag:
|
|
|
|
*
|
|
|
|
* // Displays the type and value of each variable
|
|
|
|
* echo Kohana::debug($foo, $bar, $baz);
|
|
|
|
*
|
|
|
|
* @param mixed variable to debug
|
|
|
|
* @param ...
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function debug()
|
|
|
|
{
|
|
|
|
if (func_num_args() === 0)
|
|
|
|
return;
|
|
|
|
|
2008-12-09 08:17:28 +02:00
|
|
|
// Get all passed variables
|
|
|
|
$variables = func_get_args();
|
2008-12-05 03:37:18 +02:00
|
|
|
|
2008-12-09 08:17:28 +02:00
|
|
|
$output = array();
|
|
|
|
foreach ($variables as $var)
|
2008-12-05 03:37:18 +02:00
|
|
|
{
|
2008-12-10 07:07:41 +02:00
|
|
|
$type = gettype($var);
|
|
|
|
|
|
|
|
switch ($type)
|
|
|
|
{
|
2009-03-01 15:46:10 +02:00
|
|
|
case 'null':
|
|
|
|
$var = 'NULL';
|
|
|
|
break;
|
2008-12-10 07:07:41 +02:00
|
|
|
case 'boolean':
|
|
|
|
$var = $var ? 'TRUE' : 'FALSE';
|
|
|
|
break;
|
|
|
|
default:
|
2009-02-28 13:40:13 +02:00
|
|
|
$var = htmlspecialchars(print_r($var, TRUE), NULL, self::$charset, TRUE);
|
2008-12-10 07:07:41 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$output[] = '<pre>('.$type.') '.$var.'</pre>';
|
2008-12-05 03:37:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return implode("\n", $output);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes application, system, modpath, or docroot from a filename,
|
|
|
|
* replacing them with the plain text equivalents. Useful for debugging
|
|
|
|
* when you want to display a shorter path.
|
|
|
|
*
|
|
|
|
* // Displays SYSPATH/classes/kohana.php
|
|
|
|
* echo Kohana::debug_path(Kohana::find_file('classes', 'kohana'));
|
|
|
|
*
|
|
|
|
* @param string path to debug
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function debug_path($file)
|
|
|
|
{
|
|
|
|
if (strpos($file, APPPATH) === 0)
|
|
|
|
{
|
|
|
|
$file = 'APPPATH/'.substr($file, strlen(APPPATH));
|
|
|
|
}
|
|
|
|
elseif (strpos($file, SYSPATH) === 0)
|
|
|
|
{
|
|
|
|
$file = 'SYSPATH/'.substr($file, strlen(SYSPATH));
|
|
|
|
}
|
|
|
|
elseif (strpos($file, MODPATH) === 0)
|
|
|
|
{
|
|
|
|
$file = 'MODPATH/'.substr($file, strlen(MODPATH));
|
|
|
|
}
|
|
|
|
elseif (strpos($file, DOCROOT) === 0)
|
|
|
|
{
|
|
|
|
$file = 'DOCROOT/'.substr($file, strlen(DOCROOT));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $file;
|
|
|
|
}
|
|
|
|
|
2009-02-28 13:40:13 +02:00
|
|
|
/**
|
|
|
|
* Returns an HTML string, highlighting a specific line of a file, with some
|
|
|
|
* number of lines padded above and below.
|
|
|
|
*
|
|
|
|
* // Highlights the current line of the current file
|
|
|
|
* echo Kohana::debug_source(__FILE__, __LINE__);
|
|
|
|
*
|
|
|
|
* @param string file to open
|
|
|
|
* @param integer line number to highlight
|
|
|
|
* @param integer number of padding lines
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function debug_source($file, $line_number, $padding = 3)
|
|
|
|
{
|
|
|
|
// Open the file and set the line position
|
|
|
|
$file = fopen($file, 'r');
|
|
|
|
$line = 0;
|
|
|
|
|
|
|
|
// Set the reading range
|
|
|
|
$range = array('start' => $line_number - $padding, 'end' => $line_number + $padding);
|
|
|
|
|
|
|
|
$source = array();
|
|
|
|
while (($row = fgets($file)) !== FALSE)
|
|
|
|
{
|
|
|
|
// Increment the line number
|
|
|
|
if (++$line > $range['end'])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ($line >= $range['start'])
|
|
|
|
{
|
|
|
|
// Trim whitespace and sanitize the row
|
|
|
|
$row = htmlspecialchars(rtrim($row));
|
|
|
|
|
|
|
|
if ($line === $line_number)
|
|
|
|
{
|
|
|
|
// Apply highlighting to the row
|
|
|
|
$row = '<span style="background:#f2df92">'.$row.'</span>';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add to the captured source
|
|
|
|
$source[] = $row;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the file
|
|
|
|
fclose($file);
|
|
|
|
|
|
|
|
return implode("\n", $source);
|
|
|
|
}
|
|
|
|
|
2009-03-01 15:46:10 +02:00
|
|
|
/**
|
|
|
|
* Returns a single line representation of a variable. Internally, this is
|
|
|
|
* used only for showing function arguments in stack traces.
|
2009-03-21 00:01:47 +02:00
|
|
|
*
|
2009-03-01 15:46:10 +02:00
|
|
|
* echo Kohana::debug_var($my_var);
|
|
|
|
*
|
|
|
|
* @param mixed variable to debug
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function debug_var($var)
|
|
|
|
{
|
|
|
|
switch (gettype($var))
|
|
|
|
{
|
|
|
|
case 'null':
|
|
|
|
return 'NULL';
|
|
|
|
break;
|
|
|
|
case 'boolean':
|
|
|
|
return $var ? 'TRUE' : 'FALSE';
|
|
|
|
break;
|
|
|
|
case 'string':
|
2009-03-26 04:41:37 +02:00
|
|
|
return var_export($var, TRUE);
|
2009-03-01 15:46:10 +02:00
|
|
|
break;
|
|
|
|
case 'object':
|
|
|
|
return 'object '.get_class($var);
|
|
|
|
break;
|
|
|
|
case 'array':
|
|
|
|
if (arr::is_assoc($var))
|
2009-03-02 02:02:22 +02:00
|
|
|
return print_r($var, TRUE);
|
2009-03-01 15:46:10 +02:00
|
|
|
|
|
|
|
return 'array('.implode(', ', array_map(array(__CLASS__, __FUNCTION__), $var)).')';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return var_export($var, TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-28 13:40:13 +02:00
|
|
|
/**
|
2009-03-08 17:39:32 +02:00
|
|
|
* Returns an array of HTML strings that represent each step in the backtrace.
|
2009-02-28 13:40:13 +02:00
|
|
|
*
|
|
|
|
* // Displays the entire current backtrace
|
|
|
|
* echo implode('<br/>', Kohana::trace());
|
|
|
|
*
|
|
|
|
* @param string path to debug
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function trace(array $trace = NULL)
|
|
|
|
{
|
|
|
|
if ($trace === NULL)
|
|
|
|
{
|
|
|
|
// Start a new trace
|
|
|
|
$trace = debug_backtrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Non-standard function calls
|
|
|
|
$statements = array('include', 'include_once', 'require', 'require_once');
|
|
|
|
|
|
|
|
$output = array();
|
2009-03-26 04:41:37 +02:00
|
|
|
foreach ($trace as $step)
|
2009-02-28 13:40:13 +02:00
|
|
|
{
|
2009-03-26 04:41:37 +02:00
|
|
|
if ( ! (isset($step['function']) AND isset($step['file'])))
|
2009-02-28 13:40:13 +02:00
|
|
|
{
|
|
|
|
// Ignore this line, it has unusable data
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
// Set the function name
|
|
|
|
$function = $step['function'];
|
2009-02-28 13:40:13 +02:00
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
// Set the file and line
|
|
|
|
$file = self::debug_path($step['file']);
|
|
|
|
$line = $step['line'];
|
2009-02-28 13:40:13 +02:00
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
if (isset($step['class']))
|
2009-02-28 13:40:13 +02:00
|
|
|
{
|
2009-03-26 04:41:37 +02:00
|
|
|
// Change the function to a method
|
|
|
|
$function = $step['class'].$step['type'].$function;
|
2009-02-28 13:40:13 +02:00
|
|
|
}
|
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
if (isset($step['args']))
|
|
|
|
{
|
|
|
|
if (in_array($function, $statements))
|
2009-02-28 13:40:13 +02:00
|
|
|
{
|
2009-03-26 04:41:37 +02:00
|
|
|
// Sanitize the path name
|
|
|
|
$function .= ' '.self::debug_path($step['args'][0]);
|
2009-02-28 13:40:13 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-26 04:41:37 +02:00
|
|
|
// Sanitize the function arguments
|
|
|
|
$function .= '('.implode(', ', $args = array_map('Kohana::debug_var', $step['args'])).')';
|
2009-02-28 13:40:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-26 04:41:37 +02:00
|
|
|
$output[] = array(
|
|
|
|
'function' => $function,
|
|
|
|
'file' => self::debug_path($step['file']),
|
|
|
|
'line' => $step['line']);
|
2009-02-28 13:40:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
2009-04-07 03:10:32 +03:00
|
|
|
private function __construct()
|
2009-02-28 13:40:13 +02:00
|
|
|
{
|
|
|
|
// This is a static class
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:37:18 +02:00
|
|
|
} // End Kohana
|