Memcached PHP Class
by z3n on Nov.21, 2010, under Coding
Problem:
I needed a realiable memcached php class. I know there should be a bunch of them around, but i wanted to write my own anyway, just for fun maybe.
Solution:
<?php
/**
* WSA Memcached
*
* @category Class
* @package WSA/Memcached/
* @author Rodrigo Moraes Orph <rodrigo.orph@gmail.com>
* @license Copyright 2010 http://www.overflow.biz
* @version 1.01
* @note This is a standalone script, it will be able to work without all the
* rest of WSA framework.
*/
interface iWSAMemcached {
public function set($key, $val);
public function get($key);
public function delete($key);
public function increment($key);
public function decrement($key);
public function flush();
public function debug($bool);
public function addServer($host, $port);
}
class WSAMemcached implements iWSAMemcached {
/**
* Memcache_id key prefix
* Will by applied to all memcache fetch/save related functions
*
* @string
*/
public $key_prefix;
/**
* Always serialize a set string
* This will also speed up get function by avoiding is_serialized function
*
* @bool default true
*/
public $always_serialize = true;
/**
* Default Expiration Time of a set in seconds
*
* @int default 86400
*/
public $expires = 86400;
/**
* Connection Max Retries
* Sets a limit to retry when connection fails
*
* @int default 10
*/
public $max_retry = 10;
/**
* Connection Retry Delay
* Sets the delay in ms between connection retries
*
* @int default 2500
*/
public $retry_delay = 2500;
/**
* Connection Timeout in seconds
*
* @int default 30
*/
public $timeout = 30;
/**
* Enables Persistent Connection Mode
*
* @bool default false
*/
public $pmode = false;
/**
* Change key process hash algorithm
*
* @string hash() compatible algo default md5 (eg: md5 , sha1 , crc32 , haval160 etc)
*/
public $key_hash = "md5";
/**
* Connected Flag
*
* @bool default true
*/
protected $connected = false;
/**
* Memcached object
*
* @object memcache
*/
protected $memcache;
/**
* Memcached host
*
* @string
*/
protected $host;
/**
* Memcached port
*
* @int
*/
protected $port;
/**
* Current retry number
*
* @int
*/
private $retry = 0;
/**
* Constructor
*
* @param $host string memcached host
* @param $port int memcached port
* @opt param $key_prefix string memcached key prefix
*/
public function __construct($host, $port, $key_prefix = "") {
$this->host = $host;
$this->port = $port;
$this->key_prefix = $key_prefix;
}
/**
* Destruct
*
* Will try to gracefully close memcached connection
*/
public function __destruct() {
$this->close();
}
/**
* Add Server to memcache cluster
*
* @requires memcache 2.0.0+
*
* @param $host string memcached host
* @param $port int memcached port
*
* @return $bool
*/
public function addServer($host, $port, $persistent = true, $weight = 0, $timeout = 1, $retry_interval = 15, $status = false, $failure_callback = null) {
return $this->memcache->addServer(
$host,
$post,
$persistent,
$weight,
$timeout,
$retry_interval,
$status,
$failure_callback
);
}
/**
* Stores a value on memcache
*
* @param $key string memcache key
* @param $val mixed value to be stored
* @opt param $flag mixed memcache flag
* @opt param $expires int cache expiration in seconds
*
* @return bool
*/
public function set($key, $val, $flag = MEMCACHE_COMPRESSED, $expires = 0, $no_serialize = false) {
if (empty($expires) || intval($expires) <= 0)
$expires = $this->expires;
$this->connect();
// check key
if (empty($key))
throw new Expection("Empty key when setting a value", 2);
// encode key
$key = $this->key_process($key);
// make sure val is a valid entry
if (!$no_serialize && ($this->always_serialize || is_array($val)))
$val = serialize($val);
return $this->memcache->set($key, $val, $flag, $expires);
}
/**
* Fetches a value on memcache
*
* @param $key string memcache key
*
* @return mixed serialized values will be unserialized automatically
*/
public function get($key, $no_unserialize = false) {
if (empty($key))
throw new Expection("Empty key when fetching a value", 3);
$this->connect();
// encode key
$key = $this->key_process($key);
// fetch value
$val = $this->memcache->get($key);
if (!$no_unserialize && ($this->always_serialize || $this->is_serialized($val)))
return unserialize($val);
else
return $val;
}
/**
* Deletes a vlue from memcache
*
* @param $key string memcache key
* @opt param $timeout int delete timeout
* @note timeout don't work with memcached version i've tested.
*
* @return bool delete result
*/
public function delete($key, $timeout = 0) {
if (empty($key))
throw new Expection("Empty key when deleting a value", 5);
if (empty($timeout) || intval($timeout) <= 0)
$timeout = 1;
$this->connect();
// encode key
$key = $this->key_process($key);
// delete value
return $this->memcache->delete($key); //, $timeout);
}
/**
* Increment a int value
*
* @param $key string memcache key
*
* @return int current value
*/
public function increment($key, $val = 1) {
if (empty($key))
throw new Expection("Empty key when incrementing a value", 5);
if (empty($val))
$val = 1;
$this->connect();
// encode key
$key = $this->key_process($key);
// increment value
return $this->memcache->increment($key, abs($val));
}
/**
* Increment a int value
*
* @param $key string memcache key
*
* @return int current value
*/
public function decrement($key, $val = 1) {
if (empty($key))
throw new Expection("Empty key when decrementing a value", 6);
if (empty($val))
$val = 1;
$this->connect();
// encode key
$key = $this->key_process($key);
// increment value
return $this->memcache->decrement($key, abs($val));
}
/**
* Flush - Mark all entries as expired
*
* @return bool
*/
public function flush() {
$this->connect();
return $this->memcache->flush();
}
/**
* Debug - Enables/Disables Memcache debug mode
*
* @note This is a global function
*
* @return bool
*/
public function debug($bool) {
return memcache_debug($bool ? "on" : "off");
}
/**
* Main memcache connector
* Will try to connect to memcached, on fail retries a specified number of
* times with a configurable delay between attempts; If a connection is
* already established will return it's state (bool);
*
* @return bool
*/
protected function connect() {
if (!$this->connected) {
$this->memcache = new Memcache();
// connect to memcache
if ($this->pmode)
$ret = $this->memcache->pconnect($this->host, $this->port, $this->timeout);
else
$ret = $this->memcache->connect($this->host, $this->port, $this->timeout);
if (!$ret && $this->retry < $this->max_retry) {
$this->retry++;
usleep($this->retry_delay);
return $this->connect();
} elseif (!$ret) {
throw new Exception("Unable to connect to memcached - Tried: ".$this->max_retry." times", 1);
}
$this->connected = $ret;
return $this->connected;
}
}
/**
* Main memcache connection close
*
* @return bool
*/
protected function close() {
if ($this->connected) {
$this->memcache->close();
$this->connected = false;
$this->memcache = null;
return true;
}
return false;
}
/**
* Process a key value adding prefix and encoding it to a suitable hash
*
* @param $key string key value
*
* @return encoded key value
*/
protected function key_process($key) {
if (empty($key))
throw new Expection("Empty key when processing key.", 4);
return hash($this->key_hash, $this->key_prefix.$key);
}
/**
* Checks if a variable is serialized
*
* @param $val mixed
* @opt param &$result bool return value
*
* @return bool
*/
protected function is_serialized($value, &$result = null) {
// Bit of a give away this one
if (!is_string($value)) {
return false;
}
// Serialized false, return true. unserialize() returns false on an
// invalid string or it could return false if the string is serialized
// false, eliminate that possibility.
if ($value === 'b:0;') {
$result = false;
return true;
}
$length = strlen($value);
$end = '';
switch ($value[0]) {
case 's':
if ($value[$length - 2] !== '"') {
return false;
}
case 'b':
case 'i':
case 'd':
// This looks odd but it is quicker than isset()ing
$end .= ';';
case 'a':
case 'O':
$end .= '}';
if ($value[1] !== ':') {
return false;
}
switch ($value[2]) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
break;
default:
return false;
}
case 'N':
$end .= ';';
if ($value[$length - 1] !== $end[0]) {
return false;
}
break;
default:
return false;
}
if (($result = @unserialize($value)) === false) {
$result = null;
return false;
}
return true;
}
}
More:
No comments for this entry yet...