/surosql/suracache/SuraCache.class.php
PHP | 213 lines | 179 code | 33 blank | 1 comment | 38 complexity | a46635817080e05cb173ddafaba2c073 MD5 | raw file
Possible License(s): LGPL-3.0, AGPL-1.0, GPL-2.0, LGPL-2.1
- <?php
-
- // version 0.2
-
- class SuraCache {
- const RECURSIVE = true;
- const NON_RECURSIVE = false;
- const CACHE_PREFIX = 'suracache_';
-
- static $inst;
-
- public $backend;
- public $cachestack = array();
- public $options;
-
- static function register($args = array()) {
- if(is_string($args)) {
- parse_str($args, $args);
- }
- return new SuraCache(array_merge(array('register_func' => true), $args));
- }
-
- function __construct($args = array()) {
- $defaults = array(
- 'backend' => 'SuraCacheTrivial',
- 'cache_timeout' => 60, // seconds
- 'cache_timeout_randomization' => 2, // seconds
- 'content_creation_timeout' => 5, // seconds
- 'recursive' => true,
- 'register_func' => false,
- );
- if(is_string($args)) {
- parse_str($args, $args);
- }
- $args = array_merge($defaults, $args);
- extract($args);
-
- if(is_string($backend)) {
- $backend_class_vars = get_class_vars($backend);
- $this->backend = is_null($backend_class_vars['instance']) ? new $backend() : $backend_class_vars['instance'];
- } else {
- $this->backend = $backend;
- }
- if($register_func) {
- self::$inst = $this;
- self::register_func();
- }
- $this->options = $args;
- }
-
- static function register_func() {
- function suracache() {
- return SuraCache::$inst;
- }
- }
-
- function add_key_parts($key_parts) {
- if(!is_array($key_parts)) {
- return $this->add_key_parts(array($key_parts));
- } else {
- for($i = count($this->cachestack) - 1; $i >= 0; $i--) {
- $this->cachestack[$i]['extra_key_parts'] = array_merge($this->cachestack[$i]['extra_key_parts'], $key_parts);
- if(!$this->cachestack[$i]['args']['recursive']) {
- break;
- }
- }
- }
- }
-
- static function variable($var, $key = null) {
- return (object)compact('var', 'key');
- }
-
- static function func($func) {
- return (object)compact('func');
- }
-
- static function evaluate($keys) {
- $evaled_keys = array();
- foreach($keys as $key) {
- if(is_string($key)) {
- $evaled_keys[] = $key;
- } else if(isset($key->var)) {
- $var = isset($GLOBALS[$key->var]) ? $GLOBALS[$key->var] : null;
- $evaled_keys[] = !is_null($key->key) && isset($var[$key->key]) ? $var[$key->key] : null;
- } else if(isset($key->func)) {
- $func = create_function('', $key->func);
- $evaled_keys[] = $func();
- }
- }
- return $evaled_keys;
- }
-
- function get_cache($key) {
- $hashed_key = self::CACHE_PREFIX . md5(serialize($key));
- $cache = $this->backend->get($hashed_key);
- $cache = is_null($cache) ? (object)array() : @unserialize($cache);
- $cache = $cache === false ? (object)array() : $cache;
-
- $cache->hashed_key = $hashed_key;
- $cache->is_expired = !isset($cache->expiration_date) || time() >= $cache->expiration_date;
- $cache->is_recreating = !(!isset($cache->creation_exp_date) || time() >= $cache->creation_exp_date);
- $cache->is_usable = !$cache->is_expired || $cache->is_recreating;
-
- return $cache;
- }
-
- function cache_var($key, $content, $args = array()) {
- if(is_string($args)) {
- parse_str($args, $args);
- }
- $args = array_merge($this->options, $args);
- extract($args);
-
- $cache = $this->get_cache($key);
-
- if($cache->is_usable && isset($cache->content)) {
- return $cache->content;
- }
-
- $expiration_date = time() + $cache_timeout + rand(0, (int)$cache_timeout_randomization);
- $this->backend->set($cache->hashed_key, serialize((object)compact('content', 'expiration_date')));
- }
-
- function get_var_status($key) {
- $cache = $this->get_cache($key);
-
- if($cache->is_usable && isset($cache->content)) {
- return (object)array('content' => $cache->content, 'cache_available' => true);
- } else {
- return (object)array('cache_available' => false);
- }
- }
-
- function get_var($key, $default = null) {
- $status = $this->get_var_status($key);
- return $status->cache_available ? $status->content : $default;
- }
-
- function start($key, $args = array()) {
- if(is_string($args)) {
- parse_str($args, $args);
- }
- $args = array_merge($this->options, $args);
- extract($args);
-
- $cache = $this->get_cache($key);
-
- if($cache->is_usable) {
- if(isset($cache->content)) {
- print($cache->content);
- return false;
- } else if(isset($cache->extra_key_parts)) {
- $indirect_key = array($cache->hashed_key, $cache->extra_key_parts, self::evaluate($cache->extra_key_parts));
- $indirect_cache = $this->get_cache($indirect_key, $args);
- if($indirect_cache->is_usable && isset($indirect_cache->content)) {
- print($indirect_cache->content);
- return false;
- }
- }
- }
-
- $this->cachestack[] = array('cache' => $cache, 'args' => $args, 'extra_key_parts' => array());
- if(!$cache->is_usable) {
- $value = (object)array('creation_exp_date' => time() + $content_creation_timeout);
- if(isset($cache->content)) {
- $value->content = $cache->content;
- }
- $this->backend->set($cache->hashed_key, serialize($value));
- }
- ob_start();
- return true;
- }
-
- static function array_sort_unique($arr) {
- usort($arr, create_function('$a,$b', 'return strcmp(serialize($a), serialize($b));'));
- $ret_arr = array();
- $last_ser_val = '';
- foreach($arr as $val) {
- $ser_val = serialize($val);
- if($ser_val !== $last_ser_val) {
- $ret_arr[] = $val;
- }
- $last_ser_val = $ser_val;
- }
- return $ret_arr;
- }
-
- function end() {
- extract(array_merge($this->options, array_pop($this->cachestack)));
- extract($args);
-
- $expiration_date = time() + $cache_timeout + rand(0, (int)$cache_timeout_randomization);
- $content = ob_get_flush();
-
- if(count($extra_key_parts) != 0) {
- $extra_key_parts = $cache->is_expired ? $extra_key_parts : array_merge($cache->extra_key_parts, $extra_key_parts);
- $extra_key_parts = self::array_sort_unique($extra_key_parts);
- $indirect_key = array($cache->hashed_key, $extra_key_parts, self::evaluate($extra_key_parts));
-
- if($cache->is_expired) {
- $this->backend->set($cache->hashed_key, serialize((object)compact('extra_key_parts', 'expiration_date')));
- }
-
- $hashed_indirect_key = self::CACHE_PREFIX . md5(serialize($indirect_key));
- $this->backend->set($hashed_indirect_key, serialize((object)compact('content', 'expiration_date')));
- } else {
- $this->backend->set($cache->hashed_key, serialize((object)compact('content', 'expiration_date')));
- }
- }
- }
-
- ?>