<?php
/*
* name: wrappercache
* notes: wrapper cache for filecache, memcache/memcached, apc, xcache and eaccelerator
$cacheobj =wrappercache::getinstance('memcache',30,array(array('host'=>'localhost')));
echo $cacheobj->cache('key','value');
*/
class wrappercache {
const default_memcache_port = 11211;
const cache_type_auto = 'auto';
const cache_type_eaccelerator = 'eaccelerator';
const cache_type_apc = 'apc';
const cache_type_memcache = 'memcache';
const cache_type_memcached = 'memcached';
const cache_type_file = 'filecache';
const cache_type_xcache = 'xcache';
private $cache_params; //extra params for external caches like path or connection option memcached
public $cache_expire; //seconds that the cache expires
private $cache_type; //type of cache to use
private $cache_external; //external instance of cache, can be filecache or memcache
private static $instance;//instance of this class
// always returns only one instance
public static function getinstance($type=self::cache_type_auto, $exp_time=3600, $params='cache/'){
if (!isset(self::$instance)) { //doesn't exists the isntance
self::$instance = new self($type, $exp_time, $params); //goes to the constructor
}
return self::$instance;
}
//cache constructor, optional expiring time and cache path
private function __construct($type, $exp_time, $params) {
$this->cache_expire = $exp_time;
$this->cache_params = $params;
$this->setcachetype($type);
}
public function __destruct() {
unset($this->cache_external);
}
// prevent users to clone the instance
public function __clone(){
$this->cacheerror('clone is not allowed.');
}
//deletes cache from folder
public function clearcache(){
switch($this->cache_type){
case self::cache_type_eaccelerator :
eaccelerator_clean();
eaccelerator_clear();
break;
case self::cache_type_apc :
apc_clear_cache('user');
break;
case self::cache_type_xcache :
xcache_clear_cache(xc_type_var, 0);
break;
case self::cache_type_memcache :
$this->cache_external->flush();
break;
case self::cache_type_memcached :
$this->cache_external->flush();
break;
case self::cache_type_file:
$this->cache_external->deletecache();
break;
}
}
//writes or reads the cache
public function cache($key, $value = '', $ttl = '') {
if ($value != '') { //wants to write
if ($ttl == '') $ttl = $this->cache_expire;
$this->put($key, $value, $ttl);
} else return $this->get($key);
//reading value
}
//creates new cache files with the given data, $key== name of the cache, data the info/values to store
private function put($key, $data, $ttl = '') {
if ($ttl == '') $ttl = $this->cache_expire;
switch($this->cache_type){
case self::cache_type_eaccelerator :
eaccelerator_put($key, serialize($data), $ttl);
break;
case self::cache_type_apc :
apc_store($key, $data, $ttl);
break;
case self::cache_type_xcache :
xcache_set($key, serialize($data), $ttl);
break;
case self::cache_type_memcache :
$data=serialize($data);
$this->cache_external->set($key, $data, false, $ttl);
break;
case self::cache_type_memcached :
$data=serialize($data);
$this->cache_external->set($key, $data, $ttl);
break;
case self::cache_type_file :
$this->cache_external->cache($key,$data);
break;
}
}
//returns cache for the given key
private function get($key){
switch($this->cache_type){
case self::cache_type_eaccelerator :
$data = unserialize(eaccelerator_get($key));
break;
case self::cache_type_apc :
$data = apc_fetch($key);
break;
case self::cache_type_xcache :
$data = unserialize(xcache_get($key));
break;
case self::cache_type_memcache :
$data = unserialize($this->cache_external->get($key));
break;
case self::cache_type_memcached :
$data = unserialize($this->cache_external->get($key));
break;
case self::cache_type_file :
$data = $this->cache_external->cache($key);
break;
}
return $data;
}
//delete key from cache
public function delete($key){
switch($this->cache_type){
case self::cache_type_eaccelerator :
eaccelerator_rm($key);
break;
case self::cache_type_apc :
apc_delete($key);
break;
case self::cache_type_xcache :
xcache_unset($key);
break;
case self::cache_type_memcache :
$this->cache_external->delete($key);
break;
case self::cache_type_memcached :
$this->cache_external->delete($key);
break;
case self::cache_type_file :
$this->cache_external->delete($key);
break;
}
}
// overloading for the application variables and automatically cached
public function __set($name, $value) {
$this->put($name, $value, $this->cache_expire);
}
public function __get($name) {
return $this->get($name);
}
public function __isset($key) {//echo is '$name' set?\n
if ($this->get($key) !== false) return true;
else return false;
}
public function __unset($name) {//echo unsetting '$name'\n;
$this->delete($name);
}
//end overloads
public function getcachetype(){
return $this->cache_type;
}
//sets the cache if its installed if not triggers error
public function setcachetype($type){
$this->cache_type=strtolower($type);
switch($this->cache_type){
case self::cache_type_eaccelerator :
if (!function_exists('eaccelerator_get')) $this->cacheerror('eaccelerator not found');
break;
case self::cache_type_apc :
if (!function_exists('apc_fetch')) $this->cacheerror('apc not found');
break;
case self::cache_type_xcache :
if (function_exists('xcache_get')) $this->cacheerror('xcache not found');
break;
case self::cache_type_memcache :
if (class_exists('memcache')) $this->init_mem();
else $this->cacheerror('memcache not found');
break;
case self::cache_type_memcached :
if (class_exists('memcached')) $this->init_mem(true);
else $this->cacheerror('memcached not found');
break;
case self::cache_type_file :
if (class_exists('filecache'))$this->init_filecache();
else $this->cacheerror('filecache not found');
break;
case self::cache_type_auto ://try to auto select a cache system
if (function_exists('eaccelerator_get')) $this->cache_type = self::cache_type_eaccelerator;
elseif (function_exists('apc_fetch')) $this->cache_type = self::cache_type_apc ;
elseif (function_exists('xcache_get')) $this->cache_type = self::cache_type_xcache;
elseif (class_exists('memcache')) $this->init_mem();
elseif (class_exists('memcached')) $this->init_mem(true);
elseif (class_exists('filecache')) $this->init_filecache();
else $this->cacheerror('not any compatible cache was found');
break;
default://not any cache selected or wrong one selected
$msg='not any cache type selected';
if (isset($type)) $msg='unrecognized cache type selected <b>'.$type.'</b>';
$this->cacheerror($msg);
break;
}
}
private function init_mem($usememecached = false) { //get instance of the memcache/memcached class
if (is_array($this->cache_params)) {
if ($usememecached) {
$this->cache_type = self::cache_type_memcached;
$this->cache_external = new memcached();
} else {
$this->cache_type = self::cache_type_memcache;
$this->cache_external = new memcache;
}
foreach ($this->cache_params as $server) {
$server['port'] = isset($server['port']) ? (int)$server['port'] : self::default_memcache_port;
if ($usememecached) {
$this->cache_external->addserver($server['host'], $server['port']);
} else {
$server['persistent'] = isset($server['persistent']) ? (bool)$server['persistent'] : true;
$this->cache_external->addserver($server['host'], $server['port'], $server['persistent']);
}
}
} else $this->cacheerror($this->cache_type . ' needs an array, example:wrappercache::getinstance(' . $this->cache_type . ',30,array(array(host=>localhost)));');
}
private function init_filecache(){//get instance of the filecache class
$this->cache_type = self::cache_type_file ;
$this->cache_external = filecache::getinstance($this->cache_expire, $this->cache_params);
}
public function getavailablecache($return_format='html'){//returns the available cache
$avcaches = array();
$avcaches[] = array(self::cache_type_eaccelerator,function_exists('eaccelerator_get'));
$avcaches[] = array(self::cache_type_apc, function_exists('apc_fetch')) ;
$avcaches[] = array(self::cache_type_xcache, function_exists('xcache_get'));
$avcaches[] = array(self::cache_type_memcache, class_exists('memcache'));
$avcaches[] = array(self::cache_type_memcached, class_exists('memcached'));
$avcaches[] = array(self::cache_type_file, class_exists('filecache'));
if ($return_format == 'html') {
$ret = '<ul>';
foreach ($avcaches as $c) {
$ret .= '<li>' . $c[0] . ' - ';
if ($c[1]) $ret .= 'found/compatible';
else $ret .= 'not found/incompatible';
$ret .= '</ll>';
}
return $ret . '</ul>';
} else return $avcaches;
}
private function cacheerror($msg){//triggers error
trigger_error('<br /><b>wrappercache error</b>: '.$msg.
'<br />if you want you can try with \'auto\' for auto select a compatible cache.
<br />or choose a supported cache from list:'.$this->getavailablecache(), e_user_error);
}
}