diff options
author | Bharat Mediratta <bharat@menalto.com> | 2009-03-17 18:56:01 +0000 |
---|---|---|
committer | Bharat Mediratta <bharat@menalto.com> | 2009-03-17 18:56:01 +0000 |
commit | 208fc9db683c51e3bcf1f24d1e5e0200e0f32d96 (patch) | |
tree | 68ef623d8c6e13cc15fc2fe6dbe13a32585b9fa6 | |
parent | 3f87c16223d7aca44f432efe99b35ab7afb0dbe4 (diff) |
Update Kohana to r4081.
This resolves ticket http://dev.kohanaphp.com/ticket/1156
1156: "Table prefix gets append to column name"
All tests pass.
-rw-r--r-- | kohana/config/cache_sqlite.php | 9 | ||||
-rw-r--r-- | kohana/helpers/inflector.php | 38 | ||||
-rw-r--r-- | kohana/helpers/request.php | 28 | ||||
-rw-r--r-- | kohana/libraries/Cache.php | 90 | ||||
-rw-r--r-- | kohana/libraries/Database.php | 70 | ||||
-rw-r--r-- | kohana/libraries/Database_Expression.php | 26 | ||||
-rw-r--r-- | kohana/libraries/Encrypt.php | 14 | ||||
-rw-r--r-- | kohana/libraries/Image.php | 2 | ||||
-rw-r--r-- | kohana/libraries/Input.php | 8 | ||||
-rw-r--r-- | kohana/libraries/ORM.php | 32 | ||||
-rw-r--r-- | kohana/libraries/Router.php | 92 | ||||
-rw-r--r-- | kohana/libraries/Session.php | 92 | ||||
-rw-r--r-- | kohana/libraries/URI.php | 38 | ||||
-rw-r--r-- | kohana/libraries/View.php | 14 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache.php | 2 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/Apc.php | 27 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/Eaccelerator.php | 29 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/File.php | 94 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/Memcache.php | 142 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/Sqlite.php | 101 | ||||
-rw-r--r-- | kohana/libraries/drivers/Cache/Xcache.php | 7 |
21 files changed, 587 insertions, 368 deletions
diff --git a/kohana/config/cache_sqlite.php b/kohana/config/cache_sqlite.php index 918224ce..818b8932 100644 --- a/kohana/config/cache_sqlite.php +++ b/kohana/config/cache_sqlite.php @@ -4,8 +4,7 @@ */ $config['schema'] = 'CREATE TABLE caches( - id varchar(127) PRIMARY KEY, - hash char(40) NOT NULL, - tags varchar(255), - expiration int, - cache blob);';
\ No newline at end of file + id VARCHAR(127) PRIMARY KEY, + tags VARCHAR(255), + expiration INTEGER, + cache TEXT);';
\ No newline at end of file diff --git a/kohana/helpers/inflector.php b/kohana/helpers/inflector.php index b619eddb..94e62d36 100644 --- a/kohana/helpers/inflector.php +++ b/kohana/helpers/inflector.php @@ -26,16 +26,16 @@ class inflector_Core { */ public static function uncountable($str) { - if (self::$uncountable === NULL) + if (inflector::$uncountable === NULL) { // Cache uncountables - self::$uncountable = Kohana::config('inflector.uncountable'); + inflector::$uncountable = Kohana::config('inflector.uncountable'); // Make uncountables mirroed - self::$uncountable = array_combine(self::$uncountable, self::$uncountable); + inflector::$uncountable = array_combine(inflector::$uncountable, inflector::$uncountable); } - return isset(self::$uncountable[strtolower($str)]); + return isset(inflector::$uncountable[strtolower($str)]); } /** @@ -63,19 +63,19 @@ class inflector_Core { // Cache key name $key = 'singular_'.$str.$count; - if (isset(self::$cache[$key])) - return self::$cache[$key]; + if (isset(inflector::$cache[$key])) + return inflector::$cache[$key]; if (inflector::uncountable($str)) - return self::$cache[$key] = $str; + return inflector::$cache[$key] = $str; - if (empty(self::$irregular)) + if (empty(inflector::$irregular)) { // Cache irregular words - self::$irregular = Kohana::config('inflector.irregular'); + inflector::$irregular = Kohana::config('inflector.irregular'); } - if ($irregular = array_search($str, self::$irregular)) + if ($irregular = array_search($str, inflector::$irregular)) { $str = $irregular; } @@ -93,7 +93,7 @@ class inflector_Core { $str = substr($str, 0, -1); } - return self::$cache[$key] = $str; + return inflector::$cache[$key] = $str; } /** @@ -120,21 +120,21 @@ class inflector_Core { // Cache key name $key = 'plural_'.$str.$count; - if (isset(self::$cache[$key])) - return self::$cache[$key]; + if (isset(inflector::$cache[$key])) + return inflector::$cache[$key]; if (inflector::uncountable($str)) - return self::$cache[$key] = $str; + return inflector::$cache[$key] = $str; - if (empty(self::$irregular)) + if (empty(inflector::$irregular)) { // Cache irregular words - self::$irregular = Kohana::config('inflector.irregular'); + inflector::$irregular = Kohana::config('inflector.irregular'); } - if (isset(self::$irregular[$str])) + if (isset(inflector::$irregular[$str])) { - $str = self::$irregular[$str]; + $str = inflector::$irregular[$str]; } elseif (preg_match('/[sxz]$/', $str) OR preg_match('/[^aeioudgkprt]h$/', $str)) { @@ -151,7 +151,7 @@ class inflector_Core { } // Set the cache and return - return self::$cache[$key] = $str; + return inflector::$cache[$key] = $str; } /** diff --git a/kohana/helpers/request.php b/kohana/helpers/request.php index ba6f68ac..625f9226 100644 --- a/kohana/helpers/request.php +++ b/kohana/helpers/request.php @@ -83,7 +83,7 @@ class request_Core { { $method = strtolower($_SERVER['REQUEST_METHOD']); - if ( ! in_array($method, self::$http_methods)) + if ( ! in_array($method, request::$http_methods)) throw new Kohana_Exception('request.unknown_method', $method); return $method; @@ -101,7 +101,7 @@ class request_Core { request::parse_accept_header(); if ($type === NULL) - return self::$accept_types; + return request::$accept_types; return (request::accepts_at_quality($type, $explicit_check) > 0); } @@ -175,16 +175,16 @@ class request_Core { $type = explode('/', $type, 2); // Exact match - if (isset(self::$accept_types[$type[0]][$type[1]])) - return self::$accept_types[$type[0]][$type[1]]; - + if (isset(request::$accept_types[$type[0]][$type[1]])) + return request::$accept_types[$type[0]][$type[1]]; + // Wildcard match (if not checking explicitly) - if ($explicit_check === FALSE AND isset(self::$accept_types[$type[0]]['*'])) - return self::$accept_types[$type[0]]['*']; + if ($explicit_check === FALSE AND isset(request::$accept_types[$type[0]]['*'])) + return request::$accept_types[$type[0]]['*']; // Catch-all wildcard match (if not checking explicitly) - if ($explicit_check === FALSE AND isset(self::$accept_types['*']['*'])) - return self::$accept_types['*']['*']; + if ($explicit_check === FALSE AND isset(request::$accept_types['*']['*'])) + return request::$accept_types['*']['*']; // Content type not accepted return 0; @@ -198,17 +198,17 @@ class request_Core { protected static function parse_accept_header() { // Run this function just once - if (self::$accept_types !== NULL) + if (request::$accept_types !== NULL) return; // Initialize accept_types array - self::$accept_types = array(); + request::$accept_types = array(); // No HTTP Accept header found if (empty($_SERVER['HTTP_ACCEPT'])) { // Accept everything - self::$accept_types['*']['*'] = 1; + request::$accept_types['*']['*'] = 1; return; } @@ -229,9 +229,9 @@ class request_Core { $q = (isset($accept_entry[1]) AND preg_match('~\bq\s*+=\s*+([.0-9]+)~', $accept_entry[1], $match)) ? (float) $match[1] : 1; // Populate accept_types array - if ( ! isset(self::$accept_types[$type[0]][$type[1]]) OR $q > self::$accept_types[$type[0]][$type[1]]) + if ( ! isset(request::$accept_types[$type[0]][$type[1]]) OR $q > request::$accept_types[$type[0]][$type[1]]) { - self::$accept_types[$type[0]][$type[1]] = $q; + request::$accept_types[$type[0]][$type[1]] = $q; } } } diff --git a/kohana/libraries/Cache.php b/kohana/libraries/Cache.php index 73b80252..3fb5a31c 100644 --- a/kohana/libraries/Cache.php +++ b/kohana/libraries/Cache.php @@ -13,6 +13,8 @@ */ class Cache_Core { + protected static $instances = array(); + // For garbage collection protected static $loaded; @@ -25,17 +27,18 @@ class Cache_Core { /** * Returns a singleton instance of Cache. * - * @param array configuration + * @param string configuration * @return Cache_Core */ - public static function instance($config = array()) + public static function & instance($config = FALSE) { - static $obj; - - // Create the Cache instance - ($obj === NULL) and $obj = new Cache($config); + if ( ! isset(Cache::$instances[$config])) + { + // Create a new instance + Cache::$instances[$config] = new Cache($config); + } - return $obj; + return Cache::$instances[$config]; } /** @@ -85,7 +88,7 @@ class Cache_Core { Kohana::log('debug', 'Cache Library initialized'); - if (self::$loaded !== TRUE) + if (Cache::$loaded !== TRUE) { $this->config['requests'] = (int) $this->config['requests']; @@ -98,33 +101,22 @@ class Cache_Core { } // Cache has been loaded once - self::$loaded = TRUE; + Cache::$loaded = TRUE; } } /** - * Fetches a cache by id. Non-string cache items are automatically - * unserialized before the cache is returned. NULL is returned when - * a cache item is not found. + * Fetches a cache by id. NULL is returned when a cache item is not found. * * @param string cache id * @return mixed cached data or NULL */ public function get($id) { - // Change slashes to colons - $id = str_replace(array('/', '\\'), '=', $id); + // Sanitize the ID + $id = $this->sanitize_id($id); - if ($data = $this->driver->get($id)) - { - if (substr($data, 0, 14) === '<{serialized}>') - { - // Data has been serialized, unserialize now - $data = unserialize(substr($data, 14)); - } - } - - return $data; + return $this->driver->get($id); } /** @@ -136,22 +128,7 @@ class Cache_Core { */ public function find($tag) { - if ($ids = $this->driver->find($tag)) - { - $data = array(); - foreach ($ids as $id) - { - // Load each cache item and add it to the array - if (($cache = $this->get($id)) !== NULL) - { - $data[$id] = $cache; - } - } - - return $data; - } - - return array(); + return $this->driver->find($tag); } /** @@ -164,22 +141,13 @@ class Cache_Core { * @param integer number of seconds until the cache expires * @return boolean */ - function set($id, $data, $tags = NULL, $lifetime = NULL) + function set($id, $data, array $tags = NULL, $lifetime = NULL) { if (is_resource($data)) throw new Kohana_Exception('cache.resources'); - // Change slashes to colons - $id = str_replace(array('/', '\\'), '=', $id); - - if ( ! is_string($data)) - { - // Serialize all non-string data, so that types can be preserved - $data = '<{serialized}>'.serialize($data); - } - - // Make sure that tags is an array - $tags = empty($tags) ? array() : (array) $tags; + // Sanitize the ID + $id = $this->sanitize_id($id); if ($lifetime === NULL) { @@ -198,8 +166,8 @@ class Cache_Core { */ public function delete($id) { - // Change slashes to colons - $id = str_replace(array('/', '\\'), '=', $id); + // Sanitize the ID + $id = $this->sanitize_id($id); return $this->driver->delete($id); } @@ -212,7 +180,7 @@ class Cache_Core { */ public function delete_tag($tag) { - return $this->driver->delete(FALSE, $tag); + return $this->driver->delete($tag, TRUE); } /** @@ -225,4 +193,16 @@ class Cache_Core { return $this->driver->delete(TRUE); } + /** + * Replaces troublesome characters with underscores. + * + * @param string cache id + * @return string + */ + protected function sanitize_id($id) + { + // Change slashes and spaces to underscores + return str_replace(array('/', '\\', ' '), '_', $id); + } + } // End Cache diff --git a/kohana/libraries/Database.php b/kohana/libraries/Database.php index c1ff0764..c98faffb 100644 --- a/kohana/libraries/Database.php +++ b/kohana/libraries/Database.php @@ -264,7 +264,7 @@ class Database_Core { if ($this->config['benchmark'] == TRUE) { // Benchmark the query - self::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result)); + Database::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result)); } return $result; @@ -299,9 +299,9 @@ class Database_Core { { if (preg_match('/^DISTINCT\s++(.+)$/i', $val, $matches)) { - /* ****** Begin Gallery 3 Local Change *********** */ - $val = (strpos($matches[1], '.') !== FALSE) ? $this->config['table_prefix'].$matches[1] : $matches[1]; - /* ****** End Gallery 3 Local Change *********** */ + // Only prepend with table prefix if table name is specified + $val = (strpos($matches[1], '.') !== FALSE) ? $this->config['table_prefix'].$matches[1] : $matches[1]; + $this->distinct = TRUE; } else @@ -336,27 +336,32 @@ class Database_Core { } else { - $sql = (array) $sql; + $sql = array($sql); } foreach ($sql as $val) { if (($val = trim($val)) === '') continue; - // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice) - if (stripos($val, ' AS ') !== FALSE) + if (is_string($val)) { - $val = str_ireplace(' AS ', ' AS ', $val); + // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice) + if (stripos($val, ' AS ') !== FALSE) + { + $val = str_ireplace(' AS ', ' AS ', $val); - list($table, $alias) = explode(' AS ', $val); + list($table, $alias) = explode(' AS ', $val); - // Attach prefix to both sides of the AS - $this->from[] = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias; - } - else - { - $this->from[] = $this->config['table_prefix'].$val; + // Attach prefix to both sides of the AS + $val = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias; + } + else + { + $val = $this->config['table_prefix'].$val; + } } + + $this->from[] = $val; } return $this; @@ -404,23 +409,34 @@ class Database_Core { $cond[] = $this->driver->where($key, $value, 'AND ', count($cond), FALSE); } - if( ! is_array($this->join)) { $this->join = array(); } + if ( ! is_array($this->join)) + { + $this->join = array(); + } + + if ( ! is_array($table)) + { + $table = array($table); + } - foreach ((array) $table as $t) + foreach ($table as $t) { - // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice) - if (stripos($t, ' AS ') !== FALSE) + if (is_string($t)) { - $t = str_ireplace(' AS ', ' AS ', $t); + // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice) + if (stripos($t, ' AS ') !== FALSE) + { + $t = str_ireplace(' AS ', ' AS ', $t); - list($table, $alias) = explode(' AS ', $t); + list($table, $alias) = explode(' AS ', $t); - // Attach prefix to both sides of the AS - $t = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias; - } - else - { - $t = $this->config['table_prefix'].$t; + // Attach prefix to both sides of the AS + $t = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias; + } + else + { + $t = $this->config['table_prefix'].$t; + } } $join['tables'][] = $this->driver->escape_column($t); diff --git a/kohana/libraries/Database_Expression.php b/kohana/libraries/Database_Expression.php new file mode 100644 index 00000000..3a8427ca --- /dev/null +++ b/kohana/libraries/Database_Expression.php @@ -0,0 +1,26 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); +/** + * Database expression class to allow for explicit joins and where expressions. + * + * $Id$ + * + * @package Core + * @author Kohana Team + * @copyright (c) 2007-2009 Kohana Team + * @license http://kohanaphp.com/license.html + */ +class Database_Expression_Core { + + protected $expression; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function __toString() + { + return (string) $this->expression; + } + +} // End Database Expr Class
\ No newline at end of file diff --git a/kohana/libraries/Encrypt.php b/kohana/libraries/Encrypt.php index bfa4c625..31e72438 100644 --- a/kohana/libraries/Encrypt.php +++ b/kohana/libraries/Encrypt.php @@ -96,34 +96,34 @@ class Encrypt_Core { public function encode($data) { // Set the rand type if it has not already been set - if (self::$rand === NULL) + if (Encrypt::$rand === NULL) { if (KOHANA_IS_WIN) { // Windows only supports the system random number generator - self::$rand = MCRYPT_RAND; + Encrypt::$rand = MCRYPT_RAND; } else { if (defined('MCRYPT_DEV_URANDOM')) { // Use /dev/urandom - self::$rand = MCRYPT_DEV_URANDOM; + Encrypt::$rand = MCRYPT_DEV_URANDOM; } elseif (defined('MCRYPT_DEV_RANDOM')) { // Use /dev/random - self::$rand = MCRYPT_DEV_RANDOM; + Encrypt::$rand = MCRYPT_DEV_RANDOM; } else { // Use the system random number generator - self::$rand = MCRYPT_RAND; + Encrypt::$rand = MCRYPT_RAND; } } } - if (self::$rand === MCRYPT_RAND) + if (Encrypt::$rand === MCRYPT_RAND) { // The system random number generator must always be seeded each // time it is used, or it will not produce true random results @@ -131,7 +131,7 @@ class Encrypt_Core { } // Create a random initialization vector of the proper size for the current cipher - $iv = mcrypt_create_iv($this->config['iv_size'], self::$rand); + $iv = mcrypt_create_iv($this->config['iv_size'], Encrypt::$rand); // Encrypt the data using the configured options and generated iv $data = mcrypt_encrypt($this->config['cipher'], $this->config['key'], $data, $this->config['mode'], $iv); diff --git a/kohana/libraries/Image.php b/kohana/libraries/Image.php index c9e82a1c..d740272d 100644 --- a/kohana/libraries/Image.php +++ b/kohana/libraries/Image.php @@ -292,7 +292,7 @@ class Image_Core { */ public function flip($direction) { - if ($direction !== self::HORIZONTAL AND $direction !== self::VERTICAL) + if ($direction !== Image::HORIZONTAL AND $direction !== Image::VERTICAL) throw new Kohana_Exception('image.invalid_flip'); $this->actions['flip'] = $direction; diff --git a/kohana/libraries/Input.php b/kohana/libraries/Input.php index 3cdef0b8..04e8ee4d 100644 --- a/kohana/libraries/Input.php +++ b/kohana/libraries/Input.php @@ -31,13 +31,13 @@ class Input_Core { */ public static function instance() { - if (self::$instance === NULL) + if (Input::$instance === NULL) { // Create a new instance return new Input; } - return self::$instance; + return Input::$instance; } /** @@ -51,7 +51,7 @@ class Input_Core { // Use XSS clean? $this->use_xss_clean = (bool) Kohana::config('core.global_xss_filtering'); - if (self::$instance === NULL) + if (Input::$instance === NULL) { // magic_quotes_runtime is enabled if (get_magic_quotes_runtime()) @@ -140,7 +140,7 @@ class Input_Core { } // Create a singleton - self::$instance = $this; + Input::$instance = $this; Kohana::log('debug', 'Global GET, POST and COOKIE data sanitized'); } diff --git a/kohana/libraries/ORM.php b/kohana/libraries/ORM.php index 64229ee2..fbbe9b92 100644 --- a/kohana/libraries/ORM.php +++ b/kohana/libraries/ORM.php @@ -258,11 +258,7 @@ class ORM_Core { */ public function __get($column) { - if (isset($this->ignored_columns[$column])) - { - return NULL; - } - elseif (array_key_exists($column, $this->object)) + if (array_key_exists($column, $this->object)) { return $this->object[$column]; } @@ -278,7 +274,7 @@ class ORM_Core { { // This handles the has_one and belongs_to relationships - if (in_array($model->object_name, $this->belongs_to) OR ! isset($model->object[$this->foreign_key($column)])) + if (in_array($model->object_name, $this->belongs_to) OR ! array_key_exists($this->foreign_key($column), $model->object)) { // Foreign key lies in this table (this model belongs_to target model) OR an invalid has_one relationship $where = array($model->table_name.'.'.$model->primary_key => $this->object[$this->foreign_key($column)]); @@ -339,6 +335,10 @@ class ORM_Core { ->find_all(); } } + elseif (isset($this->ignored_columns[$column])) + { + return NULL; + } elseif (in_array($column, array ( 'object_name', 'object_plural', // Object @@ -513,7 +513,7 @@ class ORM_Core { $this->with_applied[$target_path] = TRUE; // Use the keys of the empty object to determine the columns - $select = array_keys($target->as_array()); + $select = array_keys($target->object); foreach ($select as $i => $column) { // Add the prefix so that load_result can determine the relationship @@ -523,7 +523,7 @@ class ORM_Core { // Select all of the prefixed keys in the object $this->db->select($select); - + if (in_array($target->object_name, $parent->belongs_to) OR ! isset($target->object[$parent->foreign_key($target_name)])) { // Parent belongs_to target, use target's primary key as join column @@ -537,8 +537,11 @@ class ORM_Core { $join_col1 = $parent->foreign_key($target_name, $target_path); } + // This allows for models to use different table prefixes (sharing the same database) + $join_table = new Database_Expression($target->db->table_prefix().$target->table_name.' AS '.$this->db->table_prefix().$target_path); + // Join the related object into the result - $this->db->join($target->table_name.' AS '.$this->db->table_prefix().$target_path, $join_col1, $join_col2, 'LEFT'); + $this->db->join($join_table, $join_col1, $join_col2, 'LEFT'); return $this; } @@ -883,15 +886,15 @@ class ORM_Core { { if ($force === TRUE OR empty($this->table_columns)) { - if (isset(self::$column_cache[$this->object_name])) + if (isset(ORM::$column_cache[$this->object_name])) { // Use cached column information - $this->table_columns = self::$column_cache[$this->object_name]; + $this->table_columns = ORM::$column_cache[$this->object_name]; } else { // Load table columns - self::$column_cache[$this->object_name] = $this->table_columns = $this->db->list_fields($this->table_name, TRUE); + ORM::$column_cache[$this->object_name] = $this->table_columns = $this->db->list_fields($this->table_name, TRUE); } } @@ -907,7 +910,8 @@ class ORM_Core { */ public function has(ORM $model, $any = FALSE) { - $related = $model->object_plural; + // Determine plural or singular relation name + $related = ($model->table_names_plural === TRUE) ? $model->object_plural : $model->object_name; if (($join_table = array_search($related, $this->has_and_belongs_to_many)) === FALSE) return FALSE; @@ -1141,7 +1145,7 @@ class ORM_Core { } else { - if ( ! is_string($table) OR ! isset($this->object[$table.'_'.$this->primary_key])) + if ( ! is_string($table) OR ! array_key_exists($table.'_'.$this->primary_key, $this->object)) { // Use this table $table = $this->table_name; diff --git a/kohana/libraries/Router.php b/kohana/libraries/Router.php index 49ed1246..172c5f92 100644 --- a/kohana/libraries/Router.php +++ b/kohana/libraries/Router.php @@ -38,57 +38,57 @@ class Router_Core { if ( ! empty($_SERVER['QUERY_STRING'])) { // Set the query string to the current query string - self::$query_string = '?'.trim($_SERVER['QUERY_STRING'], '&/'); + Router::$query_string = '?'.trim($_SERVER['QUERY_STRING'], '&/'); } - if (self::$routes === NULL) + if (Router::$routes === NULL) { // Load routes - self::$routes = Kohana::config('routes'); + Router::$routes = Kohana::config('routes'); } // Default route status $default_route = FALSE; - if (self::$current_uri === '') + if (Router::$current_uri === '') { // Make sure the default route is set - if ( ! isset(self::$routes['_default'])) + if ( ! isset(Router::$routes['_default'])) throw new Kohana_Exception('core.no_default_route'); // Use the default route when no segments exist - self::$current_uri = self::$routes['_default']; + Router::$current_uri = Router::$routes['_default']; // Default route is in use $default_route = TRUE; } // Make sure the URL is not tainted with HTML characters - self::$current_uri = html::specialchars(self::$current_uri, FALSE); + Router::$current_uri = html::specialchars(Router::$current_uri, FALSE); // Remove all dot-paths from the URI, they are not valid - self::$current_uri = preg_replace('#\.[\s./]*/#', '', self::$current_uri); + Router::$current_uri = preg_replace('#\.[\s./]*/#', '', Router::$current_uri); // At this point segments, rsegments, and current URI are all the same - self::$segments = self::$rsegments = self::$current_uri = trim(self::$current_uri, '/'); + Router::$segments = Router::$rsegments = Router::$current_uri = trim(Router::$current_uri, '/'); // Set the complete URI - self::$complete_uri = self::$current_uri.self::$query_string; + Router::$complete_uri = Router::$current_uri.Router::$query_string; // Explode the segments by slashes - self::$segments = ($default_route === TRUE OR self::$segments === '') ? array() : explode('/', self::$segments); + Router::$segments = ($default_route === TRUE OR Router::$segments === '') ? array() : explode('/', Router::$segments); - if ($default_route === FALSE AND count(self::$routes) > 1) + if ($default_route === FALSE AND count(Router::$routes) > 1) { // Custom routing - self::$rsegments = self::routed_uri(self::$current_uri); + Router::$rsegments = Router::routed_uri(Router::$current_uri); } // The routed URI is now complete - self::$routed_uri = self::$rsegments; + Router::$routed_uri = Router::$rsegments; // Routed segments will never be empty - self::$rsegments = explode('/', self::$rsegments); + Router::$rsegments = explode('/', Router::$rsegments); // Prepare to find the controller $controller_path = ''; @@ -97,7 +97,7 @@ class Router_Core { // Paths to search $paths = Kohana::include_paths(); - foreach (self::$rsegments as $key => $segment) + foreach (Router::$rsegments as $key => $segment) { // Add the segment to the search path $controller_path .= $segment; @@ -114,14 +114,14 @@ class Router_Core { $found = TRUE; // The controller must be a file that exists with the search path - if ($c = str_replace('\\', '/', realpath($dir.$controller_path.EXT)) + if ($c = str_replace('\\', '/', realpath($dir.$controller_path.EXT)) AND is_file($c) AND strpos($c, $dir) === 0) { // Set controller name - self::$controller = $segment; + Router::$controller = $segment; // Change controller path - self::$controller_path = $c; + Router::$controller_path = $c; // Set the method segment $method_segment = $key + 1; @@ -142,22 +142,22 @@ class Router_Core { $controller_path .= '/'; } - if ($method_segment !== NULL AND isset(self::$rsegments[$method_segment])) + if ($method_segment !== NULL AND isset(Router::$rsegments[$method_segment])) { // Set method - self::$method = self::$rsegments[$method_segment]; + Router::$method = Router::$rsegments[$method_segment]; - if (isset(self::$rsegments[$method_segment + 1])) + if (isset(Router::$rsegments[$method_segment + 1])) { // Set arguments - self::$arguments = array_slice(self::$rsegments, $method_segment + 1); + Router::$arguments = array_slice(Router::$rsegments, $method_segment + 1); } } // Last chance to set routing before a 404 is triggered Event::run('system.post_routing'); - if (self::$controller === NULL) + if (Router::$controller === NULL) { // No controller was found, so no page can be rendered Event::run('system.404'); @@ -176,12 +176,12 @@ class Router_Core { // Command line requires a bit of hacking if (isset($_SERVER['argv'][1])) { - self::$current_uri = $_SERVER['argv'][1]; + Router::$current_uri = $_SERVER['argv'][1]; // Remove GET string from segments - if (($query = strpos(self::$current_uri, '?')) !== FALSE) + if (($query = strpos(Router::$current_uri, '?')) !== FALSE) { - list (self::$current_uri, $query) = explode('?', self::$current_uri, 2); + list (Router::$current_uri, $query) = explode('?', Router::$current_uri, 2); // Parse the query string into $_GET parse_str($query, $_GET); @@ -194,7 +194,7 @@ class Router_Core { elseif (isset($_GET['kohana_uri'])) { // Use the URI defined in the query string - self::$current_uri = $_GET['kohana_uri']; + Router::$current_uri = $_GET['kohana_uri']; // Remove the URI from $_GET unset($_GET['kohana_uri']); @@ -204,42 +204,42 @@ class Router_Core { } elseif (isset($_SERVER['PATH_INFO']) AND $_SERVER['PATH_INFO']) { - self::$current_uri = $_SERVER['PATH_INFO']; + Router::$current_uri = $_SERVER['PATH_INFO']; } elseif (isset($_SERVER['ORIG_PATH_INFO']) AND $_SERVER['ORIG_PATH_INFO']) { - self::$current_uri = $_SERVER['ORIG_PATH_INFO']; + Router::$current_uri = $_SERVER['ORIG_PATH_INFO']; } elseif (isset($_SERVER['PHP_SELF']) AND $_SERVER['PHP_SELF']) { - self::$current_uri = $_SERVER['PHP_SELF']; + Router::$current_uri = $_SERVER['PHP_SELF']; } // The front controller directory and filename $fc = substr(realpath($_SERVER['SCRIPT_FILENAME']), strlen(DOCROOT)); - if (($strpos_fc = strpos(self::$current_uri, $fc)) !== FALSE) + if (($strpos_fc = strpos(Router::$current_uri, $fc)) !== FALSE) { // Remove the front controller from the current uri - self::$current_uri = substr(self::$current_uri, $strpos_fc + strlen($fc)); + Router::$current_uri = substr(Router::$current_uri, $strpos_fc + strlen($fc)); } // Remove slashes from the start and end of the URI - self::$current_uri = trim(self::$current_uri, '/'); + Router::$current_uri = trim(Router::$current_uri, '/'); - if (self::$current_uri !== '') + if (Router::$current_uri !== '') { - if ($suffix = Kohana::config('core.url_suffix') AND strpos(self::$current_uri, $suffix) !== FALSE) + if ($suffix = Kohana::config('core.url_suffix') AND strpos(Router::$current_uri, $suffix) !== FALSE) { // Remove the URL suffix - self::$current_uri = preg_replace('#'.preg_quote($suffix).'$#u', '', self::$current_uri); + Router::$current_uri = preg_replace('#'.preg_quote($suffix).'$#u', '', Router::$current_uri); // Set the URL suffix - self::$url_suffix = $suffix; + Router::$url_suffix = $suffix; } // Reduce multiple slashes into single slashes - self::$current_uri = preg_replace('#//+#', '/', self::$current_uri); + Router::$current_uri = preg_replace('#//+#', '/', Router::$current_uri); } } @@ -251,24 +251,24 @@ class Router_Core { */ public static function routed_uri($uri) { - if (self::$routes === NULL) + if (Router::$routes === NULL) { // Load routes - self::$routes = Kohana::config('routes'); + Router::$routes = Kohana::config('routes'); } // Prepare variables $routed_uri = $uri = trim($uri, '/'); - if (isset(self::$routes[$uri])) + if (isset(Router::$routes[$uri])) { // Literal match, no need for regex - $routed_uri = self::$routes[$uri]; + $routed_uri = Router::$routes[$uri]; } else { // Loop through the routes and see if anything matches - foreach (self::$routes as $key => $val) + foreach (Router::$routes as $key => $val) { if ($key === '_default') continue; @@ -295,10 +295,10 @@ class Router_Core { } } - if (isset(self::$routes[$routed_uri])) + if (isset(Router::$routes[$routed_uri])) { // Check for double routing (without regex) - $routed_uri = self::$routes[$routed_uri]; + $routed_uri = Router::$routes[$routed_uri]; } return trim($routed_uri, '/'); diff --git a/kohana/libraries/Session.php b/kohana/libraries/Session.php index 4b5feed3..900e5405 100644 --- a/kohana/libraries/Session.php +++ b/kohana/libraries/Session.php @@ -12,7 +12,7 @@ class Session_Core { // Session singleton - private static $instance; + protected static $instance; // Protected key names (cannot be set by the user) protected static $protect = array('session_id', 'user_agent', 'last_activity', 'ip_address', 'total_hits', '_kf_flash_'); @@ -32,13 +32,13 @@ class Session_Core { */ public static function instance() { - if (self::$instance == NULL) + if (Session::$instance == NULL) { // Create a new instance new Session; } - return self::$instance; + return Session::$instance; } /** @@ -49,23 +49,23 @@ class Session_Core { $this->input = Input::instance(); // This part only needs to be run once - if (self::$instance === NULL) + if (Session::$instance === NULL) { // Load config - self::$config = Kohana::config('session'); + Session::$config = Kohana::config('session'); // Makes a mirrored array, eg: foo=foo - self::$protect = array_combine(self::$protect, self::$protect); + Session::$protect = array_combine(Session::$protect, Session::$protect); // Configure garbage collection - ini_set('session.gc_probability', (int) self::$config['gc_probability']); + ini_set('session.gc_probability', (int) Session::$config['gc_probability']); ini_set('session.gc_divisor', 100); - ini_set('session.gc_maxlifetime', (self::$config['expiration'] == 0) ? 86400 : self::$config['expiration']); + ini_set('session.gc_maxlifetime', (Session::$config['expiration'] == 0) ? 86400 : Session::$config['expiration']); // Create a new session $this->create(); - if (self::$config['regenerate'] > 0 AND ($_SESSION['total_hits'] % self::$config['regenerate']) === 0) + if (Session::$config['regenerate'] > 0 AND ($_SESSION['total_hits'] % Session::$config['regenerate']) === 0) { // Regenerate session id and update session cookie $this->regenerate(); @@ -73,7 +73,7 @@ class Session_Core { else { // Always update session cookie to keep the session alive - cookie::set(self::$config['name'], $_SESSION['session_id'], self::$config['expiration']); + cookie::set(Session::$config['name'], $_SESSION['session_id'], Session::$config['expiration']); } // Close the session just before sending the headers, so that @@ -84,7 +84,7 @@ class Session_Core { register_shutdown_function(array($this, 'write_close')); // Singleton instance - self::$instance = $this; + Session::$instance = $this; } Kohana::log('debug', 'Session Library initialized'); @@ -111,45 +111,45 @@ class Session_Core { // Destroy any current sessions $this->destroy(); - if (self::$config['driver'] !== 'native') + if (Session::$config['driver'] !== 'native') { // Set driver name - $driver = 'Session_'.ucfirst(self::$config['driver']).'_Driver'; + $driver = 'Session_'.ucfirst(Session::$config['driver']).'_Driver'; // Load the driver if ( ! Kohana::auto_load($driver)) - throw new Kohana_Exception('core.driver_not_found', self::$config['driver'], get_class($this)); + throw new Kohana_Exception('core.driver_not_found', Session::$config['driver'], get_class($this)); // Initialize the driver - self::$driver = new $driver(); + Session::$driver = new $driver(); // Validate the driver - if ( ! (self::$driver instanceof Session_Driver)) - throw new Kohana_Exception('core.driver_implements', self::$config['driver'], get_class($this), 'Session_Driver'); + if ( ! (Session::$driver instanceof Session_Driver)) + throw new Kohana_Exception('core.driver_implements', Session::$config['driver'], get_class($this), 'Session_Driver'); // Register non-native driver as the session handler session_set_save_handler ( - array(self::$driver, 'open'), - array(self::$driver, 'close'), - array(self::$driver, 'read'), - array(self::$driver, 'write'), - array(self::$driver, 'destroy'), - array(self::$driver, 'gc') + array(Session::$driver, 'open'), + array(Session::$driver, 'close'), + array(Session::$driver, 'read'), + array(Session::$driver, 'write'), + array(Session::$driver, 'destroy'), + array(Session::$driver, 'gc') ); } // Validate the session name - if ( ! preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', self::$config['name'])) - throw new Kohana_Exception('session.invalid_session_name', self::$config['name']); + if ( ! preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', Session::$config['name'])) + throw new Kohana_Exception('session.invalid_session_name', Session::$config['name']); // Name the session, this will also be the name of the cookie - session_name(self::$config['name']); + session_name(Session::$config['name']); // Set the session cookie parameters session_set_cookie_params ( - self::$config['expiration'], + Session::$config['expiration'], Kohana::config('cookie.path'), Kohana::config('cookie.domain'), Kohana::config('cookie.secure'), @@ -173,7 +173,7 @@ class Session_Core { } // Set up flash variables - self::$flash =& $_SESSION['_kf_flash_']; + Session::$flash =& $_SESSION['_kf_flash_']; // Increase total hits $_SESSION['total_hits'] += 1; @@ -182,7 +182,7 @@ class Session_Core { if ($_SESSION['total_hits'] > 1) { // Validate the session - foreach (self::$config['validate'] as $valid) + foreach (Session::$config['validate'] as $valid) { switch ($valid) { @@ -214,17 +214,17 @@ class Session_Core { $_SESSION['last_activity'] = time(); // Set the new data - self::set($vars); + Session::set($vars); } /** * Regenerates the global session id. - * + * * @return void */ public function regenerate() { - if (self::$config['driver'] === 'native') + if (Session::$config['driver'] === 'native') { // Generate a new session id // Note: also sets a new session cookie with the updated id @@ -236,7 +236,7 @@ class Session_Core { else { // Pass the regenerating off to the driver in case it wants to do anything special - $_SESSION['session_id'] = self::$driver->regenerate(); + $_SESSION['session_id'] = Session::$driver->regenerate(); } // Get the session name @@ -315,7 +315,7 @@ class Session_Core { foreach ($keys as $key => $val) { - if (isset(self::$protect[$key])) + if (isset(Session::$protect[$key])) continue; // Set the key @@ -345,8 +345,8 @@ class Session_Core { if ($key == FALSE) continue; - self::$flash[$key] = 'new'; - self::set($key, $val); + Session::$flash[$key] = 'new'; + Session::set($key, $val); } } @@ -358,13 +358,13 @@ class Session_Core { */ public function keep_flash($keys = NULL) { - $keys = ($keys === NULL) ? array_keys(self::$flash) : func_get_args(); + $keys = ($keys === NULL) ? array_keys(Session::$flash) : func_get_args(); foreach ($keys as $key) { - if (isset(self::$flash[$key])) + if (isset(Session::$flash[$key])) { - self::$flash[$key] = 'new'; + Session::$flash[$key] = 'new'; } } } @@ -382,19 +382,19 @@ class Session_Core { if ($run === TRUE) return; - if ( ! empty(self::$flash)) + if ( ! empty(Session::$flash)) { - foreach (self::$flash as $key => $state) + foreach (Session::$flash as $key => $state) { if ($state === 'old') { // Flash has expired - unset(self::$flash[$key], $_SESSION[$key]); + unset(Session::$flash[$key], $_SESSION[$key]); } else { // Flash will expire - self::$flash[$key] = 'old'; + Session::$flash[$key] = 'old'; } } } @@ -429,8 +429,8 @@ class Session_Core { */ public function get_once($key, $default = FALSE) { - $return = self::get($key, $default); - self::delete($key); + $return = Session::get($key, $default); + Session::delete($key); return $return; } @@ -447,7 +447,7 @@ class Session_Core { foreach ($args as $key) { - if (isset(self::$protect[$key])) + if (isset(Session::$protect[$key])) continue; // Unset the key diff --git a/kohana/libraries/URI.php b/kohana/libraries/URI.php index 0c99f0f0..f012e78a 100644 --- a/kohana/libraries/URI.php +++ b/kohana/libraries/URI.php @@ -40,7 +40,7 @@ class URI_Core extends Router { { if (is_string($index)) { - if (($key = array_search($index, self::$segments)) === FALSE) + if (($key = array_search($index, URI::$segments)) === FALSE) return $default; $index = $key + 2; @@ -48,7 +48,7 @@ class URI_Core extends Router { $index = (int) $index - 1; - return isset(self::$segments[$index]) ? self::$segments[$index] : $default; + return isset(URI::$segments[$index]) ? URI::$segments[$index] : $default; } /** @@ -62,7 +62,7 @@ class URI_Core extends Router { { if (is_string($index)) { - if (($key = array_search($index, self::$rsegments)) === FALSE) + if (($key = array_search($index, URI::$rsegments)) === FALSE) return $default; $index = $key + 2; @@ -70,7 +70,7 @@ class URI_Core extends Router { $index = (int) $index - 1; - return isset(self::$rsegments[$index]) ? self::$rsegments[$index] : $default; + return isset(URI::$rsegments[$index]) ? URI::$rsegments[$index] : $default; } /** @@ -85,7 +85,7 @@ class URI_Core extends Router { { if (is_string($index)) { - if (($key = array_search($index, self::$arguments)) === FALSE) + if (($key = array_search($index, URI::$arguments)) === FALSE) return $default; $index = $key + 2; @@ -93,7 +93,7 @@ class URI_Core extends Router { $index = (int) $index - 1; - return isset(self::$arguments[$index]) ? self::$arguments[$index] : $default; + return isset(URI::$arguments[$index]) ? URI::$arguments[$index] : $default; } /** @@ -105,7 +105,7 @@ class URI_Core extends Router { */ public function segment_array($offset = 0, $associative = FALSE) { - return $this->build_array(self::$segments, $offset, $associative); + return $this->build_array(URI::$segments, $offset, $associative); } /** @@ -117,7 +117,7 @@ class URI_Core extends Router { */ public function rsegment_array($offset = 0, $associative = FALSE) { - return $this->build_array(self::$rsegments, $offset, $associative); + return $this->build_array(URI::$rsegments, $offset, $associative); } /** @@ -129,7 +129,7 @@ class URI_Core extends Router { */ public function argument_array($offset = 0, $associative = FALSE) { - return $this->build_array(self::$arguments, $offset, $associative); + return $this->build_array(URI::$arguments, $offset, $associative); } /** @@ -171,7 +171,7 @@ class URI_Core extends Router { */ public function string() { - return self::$current_uri; + return URI::$current_uri; } /** @@ -181,7 +181,7 @@ class URI_Core extends Router { */ public function __toString() { - return self::$current_uri; + return URI::$current_uri; } /** @@ -191,7 +191,7 @@ class URI_Core extends Router { */ public function total_segments() { - return count(self::$segments); + return count(URI::$segments); } /** @@ -201,7 +201,7 @@ class URI_Core extends Router { */ public function total_rsegments() { - return count(self::$rsegments); + return count(URI::$rsegments); } /** @@ -211,7 +211,7 @@ class URI_Core extends Router { */ public function total_arguments() { - return count(self::$arguments); + return count(URI::$arguments); } /** @@ -225,7 +225,7 @@ class URI_Core extends Router { if (($end = $this->total_segments()) < 1) return $default; - return self::$segments[$end - 1]; + return URI::$segments[$end - 1]; } /** @@ -239,7 +239,7 @@ class URI_Core extends Router { if (($end = $this->total_segments()) < 1) return $default; - return self::$rsegments[$end - 1]; + return URI::$rsegments[$end - 1]; } /** @@ -251,7 +251,7 @@ class URI_Core extends Router { */ public function controller_path($full = TRUE) { - return ($full) ? url::site(self::$controller_path) : self::$controller_path; + return ($full) ? url::site(URI::$controller_path) : URI::$controller_path; } /** @@ -262,7 +262,7 @@ class URI_Core extends Router { */ public function controller($full = TRUE) { - return ($full) ? url::site(self::$controller_path.self::$controller) : self::$controller; + return ($full) ? url::site(URI::$controller_path.URI::$controller) : URI::$controller; } /** @@ -273,7 +273,7 @@ class URI_Core extends Router { */ public function method($full = TRUE) { - return ($full) ? url::site(self::$controller_path.self::$controller.'/'.self::$method) : self::$method; + return ($full) ? url::site(URI::$controller_path.URI::$controller.'/'.URI::$method) : URI::$method; } } // End URI Class diff --git a/kohana/libraries/View.php b/kohana/libraries/View.php index 5dba706c..87b15fc3 100644 --- a/kohana/libraries/View.php +++ b/kohana/libraries/View.php @@ -152,13 +152,13 @@ class View_Core { foreach ($key as $property) { // Set the result to an associative array - $result[$property] = (array_key_exists($property, $this->kohana_local_data) OR array_key_exists($property, self::$kohana_global_data)) ? TRUE : FALSE; + $result[$property] = (array_key_exists($property, $this->kohana_local_data) OR array_key_exists($property, View::$kohana_global_data)) ? TRUE : FALSE; } } else { // Otherwise just check one property - $result = (array_key_exists($key, $this->kohana_local_data) OR array_key_exists($key, self::$kohana_global_data)) ? TRUE : FALSE; + $result = (array_key_exists($key, $this->kohana_local_data) OR array_key_exists($key, View::$kohana_global_data)) ? TRUE : FALSE; } // Return the result @@ -192,12 +192,12 @@ class View_Core { { foreach ($name as $key => $value) { - self::$kohana_global_data[$key] = $value; + View::$kohana_global_data[$key] = $value; } } else { - self::$kohana_global_data[$name] = $value; + View::$kohana_global_data[$name] = $value; } } @@ -225,8 +225,8 @@ class View_Core { if (isset($this->kohana_local_data[$key])) return $this->kohana_local_data[$key]; - if (isset(self::$kohana_global_data[$key])) - return self::$kohana_global_data[$key]; + if (isset(View::$kohana_global_data[$key])) + return View::$kohana_global_data[$key]; if (isset($this->$key)) return $this->$key; @@ -266,7 +266,7 @@ class View_Core { if (is_string($this->kohana_filetype)) { // Merge global and local data, local overrides global with the same name - $data = array_merge(self::$kohana_global_data, $this->kohana_local_data); + $data = array_merge(View::$kohana_global_data, $this->kohana_local_data); // Load the view in the controller for access to $this $output = Kohana::$instance->_kohana_load_view($this->kohana_filename, $data); diff --git a/kohana/libraries/drivers/Cache.php b/kohana/libraries/drivers/Cache.php index 0e825bcf..6f24ccac 100644 --- a/kohana/libraries/drivers/Cache.php +++ b/kohana/libraries/drivers/Cache.php @@ -14,7 +14,7 @@ interface Cache_Driver { /** * Set a cache item. */ - public function set($id, $data, $tags, $lifetime); + public function set($id, $data, array $tags = NULL, $lifetime); /** * Find all of the cache ids for a given tag. diff --git a/kohana/libraries/drivers/Cache/Apc.php b/kohana/libraries/drivers/Cache/Apc.php index 39d47dd3..29431ed4 100644 --- a/kohana/libraries/drivers/Cache/Apc.php +++ b/kohana/libraries/drivers/Cache/Apc.php @@ -22,27 +22,38 @@ class Cache_Apc_Driver implements Cache_Driver { return (($return = apc_fetch($id)) === FALSE) ? NULL : $return; } - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { - count($tags) and Kohana::log('error', 'Cache: tags are unsupported by the APC driver'); + if ( ! empty($tags)) + { + Kohana::log('error', 'Cache: tags are unsupported by the APC driver'); + } return apc_store($id, $data, $lifetime); } public function find($tag) { - return FALSE; + Kohana::log('error', 'Cache: tags are unsupported by the APC driver'); + + return array(); } public function delete($id, $tag = FALSE) { - if ($id === TRUE) + if ($tag === TRUE) + { + Kohana::log('error', 'Cache: tags are unsupported by the APC driver'); + return FALSE; + } + elseif ($id === TRUE) + { return apc_clear_cache('user'); - - if ($tag == FALSE) + } + else + { return apc_delete($id); - - return TRUE; + } } public function delete_expired() diff --git a/kohana/libraries/drivers/Cache/Eaccelerator.php b/kohana/libraries/drivers/Cache/Eaccelerator.php index 8fd32471..0710d483 100644 --- a/kohana/libraries/drivers/Cache/Eaccelerator.php +++ b/kohana/libraries/drivers/Cache/Eaccelerator.php @@ -24,30 +24,43 @@ class Cache_Eaccelerator_Driver implements Cache_Driver { public function find($tag) { - return FALSE; + Kohana::log('error', 'tags are unsupported by the eAccelerator driver'); + + return array(); } - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { - count($tags) and Kohana::log('error', 'tags are unsupported by the eAccelerator driver'); + if ( ! empty($tags)) + { + Kohana::log('error', 'tags are unsupported by the eAccelerator driver'); + } return eaccelerator_put($id, $data, $lifetime); } public function delete($id, $tag = FALSE) { - if ($id === TRUE) + if ($tag === TRUE) + { + Kohana::log('error', 'tags are unsupported by the eAccelerator driver'); + return FALSE; + } + elseif ($id === TRUE) + { return eaccelerator_clean(); - - if ($tag == FALSE) + } + else + { return eaccelerator_rm($id); - - return TRUE; + } } public function delete_expired() { eaccelerator_gc(); + + return TRUE; } } // End Cache eAccelerator Driver
\ No newline at end of file diff --git a/kohana/libraries/drivers/Cache/File.php b/kohana/libraries/drivers/Cache/File.php index 16fa08e1..db27f02d 100644 --- a/kohana/libraries/drivers/Cache/File.php +++ b/kohana/libraries/drivers/Cache/File.php @@ -35,25 +35,25 @@ class Cache_File_Driver implements Cache_Driver { * @param string cache id or tag * @param bool search for tags * @return array of filenames matching the id or tag - * @return void if no matching files are found */ public function exists($id, $tag = FALSE) { if ($id === TRUE) { // Find all the files - $files = glob($this->directory.'*~*~*'); + return glob($this->directory.'*~*~*'); } - elseif ($tag == TRUE) + elseif ($tag === TRUE) { // Find all the files that have the tag name - $files = glob($this->directory.'*~*'.$id.'*~*'); + $paths = glob($this->directory.'*~*'.$id.'*~*'); // Find all tags matching the given tag - foreach ($files as $i => $file) + $files = array(); + foreach ($paths as $path) { // Split the files - $tags = explode('~', $file); + $tags = explode('~', basename($path)); // Find valid tags if (count($tags) !== 3 OR empty($tags[1])) @@ -62,20 +62,20 @@ class Cache_File_Driver implements Cache_Driver { // Split the tags by plus signs, used to separate tags $tags = explode('+', $tags[1]); - if ( ! in_array($tag, $tags)) + if (in_array($tag, $tags)) { - // This entry does not match the tag - unset($files[$i]); + // Add the file to the array, it has the requested tag + $files[] = $path; } } + + return $files; } else { - // Find all the files matching the given id - $files = glob($this->directory.$id.'~*'); + // Find the file matching the given id + return glob($this->directory.$id.'~*'); } - - return empty($files) ? NULL : $files; } /** @@ -87,7 +87,7 @@ class Cache_File_Driver implements Cache_Driver { * @param integer lifetime * @return bool */ - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { // Remove old cache files $this->delete($id); @@ -98,11 +98,14 @@ class Cache_File_Driver implements Cache_Driver { $lifetime += time(); } - // Construct the filename - $filename = $id.'~'.implode('+', $tags).'~'.$lifetime; + if ( ! empty($tags)) + { + // Convert the tags into a string list + $tags = implode('+', $tags); + } - // Write the file, appending the sha1 signature to the beginning of the data - return (bool) file_put_contents($this->directory.$filename, sha1($data).$data); + // Write out a serialized cache + return (bool) file_put_contents($this->directory.$id.'~'.$tags.'~'.$lifetime, serialize($data)); } /** @@ -113,23 +116,29 @@ class Cache_File_Driver implements Cache_Driver { */ public function find($tag) { - if ($files = $this->exists($tag, TRUE)) + // An array will always be returned + $result = array(); + + if ($paths = $this->exists($tag, TRUE)) { // Length of directory name $offset = strlen($this->directory); // Find all the files with the given tag - $array = array(); - foreach ($files as $file) + foreach ($paths as $path) { // Get the id from the filename - $array[] = substr(current(explode('~', $file)), $offset); - } + list($id, $junk) = explode('~', basename($path), 2); - return $array; + if (($data = $this->get($id)) !== FALSE) + { + // Add the result to the array + $result[$id] = $data; + } + } } - return FALSE; + return $result; } /** @@ -143,7 +152,7 @@ class Cache_File_Driver implements Cache_Driver { { if ($file = $this->exists($id)) { - // Always process the first result + // Use the first file $file = current($file); // Validate that the cache has not expired @@ -154,22 +163,22 @@ class Cache_File_Driver implements Cache_Driver { } else { - $data = file_get_contents($file); - - // Find the hash of the data - $hash = substr($data, 0, 40); - - // Remove the hash from the data - $data = substr($data, 40); + // Turn off errors while reading the file + $ER = error_reporting(0); - if ($hash !== sha1($data)) + if (($data = file_get_contents($file)) !== FALSE) { - // Remove this cache, it doesn't validate - $this->delete($id); - - // Unset data to prevent it from being returned + // Unserialize the data + $data = unserialize($data); + } + else + { + // Delete the data unset($data); } + + // Turn errors back on + error_reporting($ER); } } @@ -216,14 +225,21 @@ class Cache_File_Driver implements Cache_Driver { { if ($files = $this->exists(TRUE)) { + // Disable all error reporting while deleting + $ER = error_reporting(0); + foreach ($files as $file) { if ($this->expired($file)) { // The cache file has already expired, delete it - @unlink($file) or Kohana::log('error', 'Cache: Unable to delete cache file: '.$file); + if ( ! unlink($file)) + Kohana::log('error', 'Cache: Unable to delete cache file: '.$file); } } + + // Turn on error reporting again + error_reporting($ER); } } diff --git a/kohana/libraries/drivers/Cache/Memcache.php b/kohana/libraries/drivers/Cache/Memcache.php index ef5b8440..f443b997 100644 --- a/kohana/libraries/drivers/Cache/Memcache.php +++ b/kohana/libraries/drivers/Cache/Memcache.php @@ -11,17 +11,28 @@ */ class Cache_Memcache_Driver implements Cache_Driver { + const TAGS_KEY = 'memcache_tags_array'; + // Cache backend object and flags protected $backend; protected $flags; + // The persistent lifetime value for expirations of 0 + protected $persistent_lifetime; + + // Tags array + protected $tags; + + // Have the tags been changed? + protected $tags_changed = FALSE; + public function __construct() { if ( ! extension_loaded('memcache')) throw new Kohana_Exception('cache.extension_not_loaded', 'memcache'); $this->backend = new Memcache; - $this->flags = Kohana::config('cache_memcache.compression') ? MEMCACHE_COMPRESSED : 0; + $this->flags = Kohana::config('cache_memcache.compression') ? MEMCACHE_COMPRESSED : FALSE; $servers = Kohana::config('cache_memcache.servers'); @@ -34,11 +45,44 @@ class Cache_Memcache_Driver implements Cache_Driver { $this->backend->addServer($server['host'], $server['port'], (bool) $server['persistent']) or Kohana::log('error', 'Cache: Connection failed: '.$server['host']); } + + // Set "persistent lifetime" value to one year + $this->persistent_lifetime = strtotime('now +1 year'); + + // Load tags + $this->tags = $this->backend->get(self::TAGS_KEY); + + if ( ! is_array($this->tags)) + { + // Create a new tags array + $this->tags = array(); + + // Tags have been created + $this->tags_changed = TRUE; + } + } + + public function __destruct() + { + if ($this->tags_changed === TRUE) + { + // Save the tags + $this->backend->set(self::TAGS_KEY, $this->tags, $this->flags, $this->persistent_lifetime); + } } public function find($tag) { - return FALSE; + if (isset($this->tags[$tag]) AND $results = $this->backend->get($this->tags[$tag])) + { + // Return all the found caches + return $results; + } + else + { + // No matching tags + return array(); + } } public function get($id) @@ -46,32 +90,110 @@ class Cache_Memcache_Driver implements Cache_Driver { return (($return = $this->backend->get($id)) === FALSE) ? NULL : $return; } - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { - count($tags) and Kohana::log('error', 'Cache: Tags are unsupported by the memcache driver'); + if ( ! empty($tags)) + { + // Tags will be changed + $this->tags_changed = TRUE; + + foreach ($tags as $tag) + { + // Add the id to each tag + $this->tags[$tag][$id] = $id; + } + } - // Memcache driver expects unix timestamp - if ($lifetime !== 0) + if ($lifetime === 0) { + // Using an expiration of zero is unreliable, as memcache may delete + // it without warning. @see http://php.net/memcache_set + $lifetime = $this->persistent_lifetime; + } + else + { + // Memcache driver expects unix timestamp $lifetime += time(); } + // Set a new value return $this->backend->set($id, $data, $this->flags, $lifetime); } public function delete($id, $tag = FALSE) { + // Tags will be changed + $this->tags_changed = TRUE; + if ($id === TRUE) - return $this->backend->flush(); + { + if ($status = $this->backend->flush()) + { + // Remove all tags, all items have been deleted + $this->tags = array(); - if ($tag == FALSE) - return $this->backend->delete($id); + // We must sleep after flushing, or overwriting will not work! + // @see http://php.net/manual/en/function.memcache-flush.php#81420 + sleep(1); + } - return TRUE; + return $status; + } + elseif ($tag === TRUE) + { + if (isset($this->tags[$id])) + { + foreach ($this->tags[$id] as $_id) + { + // Delete each id in the tag + $this->backend->delete($_id); + } + + // Delete the tag + unset($this->tags[$id]); + } + + return TRUE; + } + else + { + foreach ($this->tags as $tag => $_ids) + { + if (isset($this->tags[$tag][$id])) + { + // Remove the id from the tags + unset($this->tags[$tag][$id]); + } + } + + return $this->backend->delete($id); + } } public function delete_expired() { + // Tags will be changed + $this->tags_changed = TRUE; + + foreach ($this->tags as $tag => $_ids) + { + foreach ($_ids as $id) + { + if ( ! $this->backend->get($id)) + { + // This id has disappeared, delete it from the tags + unset($this->tags[$tag][$id]); + } + } + + if (empty($this->tags[$tag])) + { + // The tag no longer has any valid ids + unset($this->tags[$tag]); + } + } + + // Memcache handles garbage collection internally return TRUE; } diff --git a/kohana/libraries/drivers/Cache/Sqlite.php b/kohana/libraries/drivers/Cache/Sqlite.php index 7413b08c..a86efaba 100644 --- a/kohana/libraries/drivers/Cache/Sqlite.php +++ b/kohana/libraries/drivers/Cache/Sqlite.php @@ -91,16 +91,16 @@ class Cache_Sqlite_Driver implements Cache_Driver { * @param integer lifetime * @return bool */ - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { - // Find the data hash - $hash = sha1($data); + // Serialize and escape the data + $data = sqlite_escape_string(serialize($data)); - // Escape the data - $data = sqlite_escape_string($data); - - // Escape the tags - $tags = sqlite_escape_string(implode(',', $tags)); + if ( ! empty($tags)) + { + // Escape the tags, adding brackets so the tag can be explicitly matched + $tags = sqlite_escape_string('<'.implode('>,<', $tags).'>'); + } // Cache Sqlite driver expects unix timestamp if ($lifetime !== 0) @@ -109,15 +109,21 @@ class Cache_Sqlite_Driver implements Cache_Driver { } $query = $this->exists($id) - ? "UPDATE caches SET hash = '$hash', tags = '$tags', expiration = '$lifetime', cache = '$data' WHERE id = '$id'" - : "INSERT INTO caches VALUES('$id', '$hash', '$tags', '$lifetime', '$data')"; + ? "UPDATE caches SET tags = '$tags', expiration = '$lifetime', cache = '$data' WHERE id = '$id'" + : "INSERT INTO caches VALUES('$id', '$tags', '$lifetime', '$data')"; // Run the query $this->db->unbufferedQuery($query, SQLITE_BOTH, $error); - empty($error) or self::log_error($error); - - return empty($error); + if ( ! empty($error)) + { + self::log_error($error); + return FALSE; + } + else + { + return TRUE; + } } /** @@ -128,23 +134,32 @@ class Cache_Sqlite_Driver implements Cache_Driver { */ public function find($tag) { - $query = "SELECT id FROM caches WHERE tags LIKE '%{$tag}%'"; + $query = "SELECT id,cache FROM caches WHERE tags LIKE '%<{$tag}>%'"; $query = $this->db->query($query, SQLITE_BOTH, $error); - empty($error) or self::log_error($error); + // An array will always be returned + $result = array(); - if (empty($error) AND $query->numRows() > 0) + if ( ! empty($error)) + { + self::log_error($error); + } + elseif ($query->numRows() > 0) { - $array = array(); + // Disable notices for unserializing + $ER = error_reporting(~E_NOTICE); + while ($row = $query->fetchObject()) { - // Add each id to the array - $array[] = $row->id; + // Add each cache to the array + $result[$row->id] = unserialize($row->cache); } - return $array; + + // Turn notices back on + error_reporting($ER); } - return FALSE; + return $result; } /** @@ -156,23 +171,31 @@ class Cache_Sqlite_Driver implements Cache_Driver { */ public function get($id) { - $query = "SELECT id, hash, expiration, cache FROM caches WHERE id = '{$id}' LIMIT 0, 1"; + $query = "SELECT id, expiration, cache FROM caches WHERE id = '$id' LIMIT 0, 1"; $query = $this->db->query($query, SQLITE_BOTH, $error); - empty($error) or self::log_error($error); - - if (empty($error) AND $cache = $query->fetchObject()) + if ( ! empty($error)) + { + self::log_error($error); + } + elseif ($cache = $query->fetchObject()) { // Make sure the expiration is valid and that the hash matches - if (($cache->expiration != 0 AND $cache->expiration <= time()) OR $cache->hash !== sha1($cache->cache)) + if ($cache->expiration != 0 AND $cache->expiration <= time()) { // Cache is not valid, delete it now $this->delete($cache->id); } else { + // Disable notices for unserializing + $ER = error_reporting(~E_NOTICE); + // Return the valid cache data - return $cache->cache; + $data = $cache->cache; + + // Turn notices back on + error_reporting($ER); } } @@ -184,7 +207,7 @@ class Cache_Sqlite_Driver implements Cache_Driver { * Deletes a cache item by id or tag * * @param string cache id or tag, or TRUE for "all items" - * @param bool use tags + * @param bool delete a tag * @return bool */ public function delete($id, $tag = FALSE) @@ -194,22 +217,28 @@ class Cache_Sqlite_Driver implements Cache_Driver { // Delete all caches $where = '1'; } - elseif ($tag == FALSE) + elseif ($tag === TRUE) { - // Delete by id - $where = "id = '{$id}'"; + // Delete by tag + $where = "tags LIKE '%<{$id}>%'"; } else { - // Delete by tag - $where = "tags LIKE '%{$tag}%'"; + // Delete by id + $where = "id = '$id'"; } $this->db->unbufferedQuery('DELETE FROM caches WHERE '.$where, SQLITE_BOTH, $error); - empty($error) or self::log_error($error); - - return empty($error); + if ( ! empty($error)) + { + self::log_error($error); + return FALSE; + } + else + { + return TRUE; + } } /** diff --git a/kohana/libraries/drivers/Cache/Xcache.php b/kohana/libraries/drivers/Cache/Xcache.php index 5d027eec..8d31993a 100644 --- a/kohana/libraries/drivers/Cache/Xcache.php +++ b/kohana/libraries/drivers/Cache/Xcache.php @@ -25,9 +25,12 @@ class Cache_Xcache_Driver implements Cache_Driver { return NULL; } - public function set($id, $data, $tags, $lifetime) + public function set($id, $data, array $tags = NULL, $lifetime) { - count($tags) and Kohana::log('error', 'Cache: tags are unsupported by the Xcache driver'); + if ( ! empty($tags)) + { + Kohana::log('error', 'Cache: tags are unsupported by the Xcache driver'); + } return xcache_set($id, $data, $lifetime); } |