Skip to content

Instantly share code, notes, and snippets.

@rbraband
Created February 18, 2014 07:31
Show Gist options
  • Save rbraband/9066162 to your computer and use it in GitHub Desktop.
Save rbraband/9066162 to your computer and use it in GitHub Desktop.
<?php
/**
* php_XCache
*
* @package XCache
* @version $Id$
* @copyright 2014
* @author Roland Braband <rbraband@web.de>
* @license BSD {@link http://www.opensource.org/licenses/bsd-license.php}
*/
/**
* HowTo
*
$cache = php_XCache::getInstance();
$xc_key = $cache->generateKey('DomainKey', 'Identifier');
// determine the current user_id
if (is_null($user_id = $cache->get($xc_key))) {
$user_id = 1;
$cache->set($xc_key, $user_id);
}
// flush the domain cache
php_XCache::getInstance()->flushKeys('DomainKey');
*/
if (!defined('XC_TYPE_PHP')) define('XC_TYPE_PHP', 0);
if (!defined('XC_TYPE_VAR')) define('XC_TYPE_VAR', 1);
/**
* @property mixed FORCE_HASH
* @property mixed FORCE_TTL
* @property mixed SKIP_EXISTING
* @property mixed XC_ENABLE
*/
class php_XCache {
private static $xcobj;
private $enabled;
private $xcnamespace;
private $xcttl;
private $xccrypt;
const SKIP_EXISTING = 'skipExisting';
const FORCE_HASH = 'forceHash';
const FORCE_TTL = 'forceTTL';
const CACHE_SUFFIX = '.cache';
const KEY_PREFIX = 'XCK';
const XC_KEYVALUE = 'XC_KeyValue';
const XC_LIST = 'XC_List';
const XC_HASH = 'XC_Hash';
const XC_ENABLE = 'XC_Enable';
private function __construct($container, $options = array()) {
if (!extension_loaded('Xcache')) throw new RuntimeException('Unable to use XcacheClassLoader as Xcache is not enabled.');
if (defined('STDIN')) {
$this->enabled = false;
return;
}
switch ($container) {
case 'XCACHE_KEY':
if (!isset($_SERVER['XCACHE_KEY'])) {
$this->enabled = false;
return;
}
$this->xccrypt = (isset($option[$this->FORCE_HASH])) ? (bool) $option[$this->FORCE_HASH] : false;
$this->xcttl = (isset($option[$this->FORCE_TTL])) ? (int) $option[$this->FORCE_TTL] : 60 * 60 * 24;
$this->xcnamespace = $_SERVER['XCACHE_KEY'];
break;
case 'HTTP_HOST':
if (!isset($_SERVER['HTTP_HOST'])) {
$this->enabled = false;
return;
}
$this->xccrypt = (isset($option[$this->FORCE_HASH])) ? (bool) $option[$this->FORCE_HASH] : false;
$this->xcttl = (isset($option[$this->FORCE_TTL])) ? (int) $option[$this->FORCE_TTL] : 60 * 60 * 1;
$this->xcnamespace = $_SERVER['HTTP_HOST'];
break;
case 'SESSION':
$this->xccrypt = (isset($option[$this->FORCE_HASH])) ? (bool) $option[$this->FORCE_HASH] : true;
$this->xcttl = (isset($option[$this->FORCE_TTL])) ? (int) $option[$this->FORCE_TTL] : 60 * 60 * 2;
$this->xcnamespace = session_id();
break;
case 'GLOBAL':
$this->xccrypt = (isset($option[$this->FORCE_HASH])) ? (bool) $option[$this->FORCE_HASH] : false;
$this->xcttl = (isset($option[$this->FORCE_TTL])) ? (int) $option[$this->FORCE_TTL] : 0;
$this->xcnamespace = 'GLOBAL';
break;
default:
$this->xccrypt = (isset($option[$this->FORCE_HASH])) ? (bool) $option[$this->FORCE_HASH] : false;
$this->xcttl = (isset($option[$this->FORCE_TTL])) ? (int) $option[$this->FORCE_TTL] : 300;
$this->xcnamespace = $container;
}
$this->enabled = (isset($option[$this->XC_ENABLE])) ? (bool) $option[$this->XC_ENABLE] : true;
}
public final function __clone() {
throw new BadMethodCallException("Clone is not allowed");
}
/**
* getInstance
*
* @static
* @access public
*
* @param string $container
* @param array $options
*
* @return object XCache instance
*/
public static function getInstance($container = 'XCACHE_KEY', $options = array()) {
$container = str_replace(array('/', '\\', ' '), '_', trim(strtoupper($container)));
if (!(isset(self::$xcobj[$container]) || self::$xcobj[$container] instanceof php_XCache)) {
self::$xcobj[$container] = new php_XCache($container, $options);
}
return self::$xcobj[$container];
}
/**
* set
*
* @param mixed $name
* @param mixed $value
* @param int $time
* @param mixed $option
*
* @throws InvalidArgumentException
* @access public
* @return bool
*/
public function set($name, $value, $time = null, $option = array()) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
if (is_resource($value) || is_object($value) || is_callable($value)) throw new InvalidArgumentException("At the moment, It is not possible to store resources, callbacks or objects!");
$time = (is_null($time)) ? $this->xcttl : intval($time);
if (isset($option[$this->SKIP_EXISTING]) && $option[$this->SKIP_EXISTING] === true) {
if (!$this->isExisting($name)) {
return xcache_set($this->_sanitize_id($name, $this->xcnamespace), $value, $time);
}
} else {
return xcache_set($this->_sanitize_id($name, $this->xcnamespace), $value, $time);
}
return false;
}
/**
* __set
*
* @param mixed $name
* @param mixed $value
*
* @throws InvalidArgumentException
* @internal param int $time
* @internal param mixed $option
* @access public
* @return bool
*/
public function __set($name, $value) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
if (is_resource($value) || is_object($value) || is_callable($value)) throw new InvalidArgumentException("At the moment, It is not possible to store resources, callbacks or objects!");
return xcache_set($this->_sanitize_id($name, $this->xcnamespace), $value, $this->xcttl);
}
/**
* touch
*
* @param mixed $name
*
* @internal param int $time
* @access public
* @return bool
*/
public function touch($name) {
if (!$this->enabled) return false;
$data = $this->get($name);
if ($data == null) {
return false;
} else {
$this->set($name, $data);
return true;
}
}
/**
* get
*
* @param mixed $name
*
* @access public
* @return mixed
*/
public function get($name) {
if (!$this->enabled) return null;
if (is_array($name)) $name = $this->generateKey($name);
$data = xcache_get($this->_sanitize_id($name, $this->xcnamespace));
if ($data === false || $data == "") {
return null;
}
return $data;
}
/**
* __get
*
* @param mixed $name
*
* @access public
* @return mixed
*/
public function __get($name) {
if (!$this->enabled) return null;
$data = xcache_get($this->_sanitize_id($name, $this->xcnamespace));
if ($data === false || $data == "") {
return null;
}
return $data;
}
/**
* __isset
*
* @param mixed $name
*
* @access public
* @return bool
*/
public function __isset($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_isset($this->_sanitize_id($name, $this->xcnamespace));
}
/**
* isExisting
*
* @param mixed $name
*
* @access public
* @return bool
*/
function isExisting($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
if (xcache_isset($this->_sanitize_id($name, $this->xcnamespace))) {
return true;
} else {
return false;
}
}
/**
* __unset
*
* @param mixed $name
*
* @access public
* @return bool
*/
public function __unset($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_unset($this->_sanitize_id($name, $this->xcnamespace));
}
/**
* delete
*
* @param mixed $name
*
* @access public
* @return bool
*/
public function delete($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_unset($this->_sanitize_id($name, $this->xcnamespace));
}
/**
* clean
*
* @access public
* @return void
*/
public function clean() {
$cnt = xcache_count(XC_TYPE_VAR);
for ($i = 0; $i < $cnt; $i++) {
xcache_clear_cache(XC_TYPE_VAR, $i);
}
}
/**
* info
*
* @access public
*
* @param $html
*
* @return array
*/
public function info($html = false) {
$_bool = Array(false => 'false', true => 'true');
if ($html === true) {
return "crypted: {$_bool[$this->xccrypt]}, ttl: {$this->xcttl}, namespace: {$this->xcnamespace}, enabled: {$_bool[$this->enabled]}";
} else {
return array('crypted' => $this->xccrypt,
'ttl' => $this->xcttl,
'namespace' => $this->xcnamespace,
'enabled' => $this->enabled
);
}
}
/**
* flushKeys
*
* @access public
*
* @param $pattern
*
* @return void
*/
public function flushKeys($pattern) {
if (!$this->enabled) return;
$varCacheCount = xcache_count(XC_TYPE_VAR);
for ($i = 0; $i < $varCacheCount; $i++) {
$items = xcache_list(XC_TYPE_VAR, $i);
foreach ($items['cache_list'] as $item) {
preg_match('/^(?P<prefix>' . $this->xcnamespace . '):(?P<key>' . self::KEY_PREFIX . '):(?P<id>' . trim($pattern) . '.{0,})(?P<suffix>' . self::CACHE_SUFFIX . ')$/i', $item['name'], $match);
if (!empty($match)) xcache_unset($match[0]);
}
}
}
/**
* getKeys
*
* @access public
*
* @param $pattern
*
* @return array
*/
public function getKeys($pattern) {
if (!$this->enabled) return array();
$_keys = array();
$varCacheCount = xcache_count(XC_TYPE_VAR);
for ($i = 0; $i < $varCacheCount; $i++) {
$items = xcache_list(XC_TYPE_VAR, $i);
$_keys = array();
foreach ($items['cache_list'] as $item) {
preg_match('/^(?P<prefix>' . $this->xcnamespace . '):(?P<key>' . self::KEY_PREFIX . '):(?P<id>' . trim($pattern) . ')(?P<suffix>' . self::CACHE_SUFFIX . ')$/i', $item['name'], $match);
if (!empty($match)) array_push($_keys, $match['key']);
}
}
return $_keys;
}
/**
* increment
*
* @param mixed $name
* @param int $step
*
* @access public
* @return int
*/
public function increment($name, $step = 1) {
if (!$this->enabled) return 0;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_inc($this->_sanitize_id($name, $this->xcnamespace), (int) $step);
}
/**
* decrement
*
* @param mixed $name
* @param int $step
*
* @access public
* @return int
*/
public function decrement($name, $step = 1) {
if (!$this->enabled) return 0;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_dec($this->_sanitize_id($name, $this->xcnamespace), (int) $step);
}
/**
* lock
*
* @param mixed $name
*
* @access public
* @return bool
*/
public function lock($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_inc($this->_sanitize_id($name, 'LOCK')) === 1;
}
/**
* unlock
*
* @param mixed $name
*
* @access public
* @return bool
*/
public function unlock($name) {
if (!$this->enabled) return false;
if (is_array($name)) $name = $this->generateKey($name);
return xcache_unset($this->_sanitize_id($name, 'LOCK'));
}
/**
* clear
*
* @access public
* @return void
*/
public function clear() {
xcache_clear_cache(XC_TYPE_PHP, 0);
}
/**
* generateKey
*
* @access public
*
* @param $string
*
* @throws InvalidArgumentException
* @return string
*/
public function generateKey($string) {
if (empty($string)) throw new InvalidArgumentException("It is not possible to generate empty keys!");
if (func_num_args() > 1) {
$args = func_get_args();
// http://php.net/manual/de/function.implode.php
$key = self::KEY_PREFIX . ':' . implode(':', $args);
} else $key = self::KEY_PREFIX . ':' . trim($string);
$key = preg_replace(array('/:{1,2}$/'), '', $key);
//echo "<!-- {$key} -->\n";
return $key;
}
/**
* _sanitize_id
*
* @param mixed $id
* @param $prefix
*
* @access protected
* @return string
*/
protected function _sanitize_id($id, $prefix) {
if ($this->xccrypt) {
return hash('md5', $prefix . ':' . str_replace(array('/', '\\', ' '), '_', trim($id)) . self::CACHE_SUFFIX);
} else {
return $prefix . ':' . str_replace(array('/', '\\', ' '), '_', trim($id)) . self::CACHE_SUFFIX;
}
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment