<?php
/**
* @package cacher
* @author Adam Flatau of Reflect Studios
* @since 03/14/08
* @desc Class to mange both APC and memcache data transactions
*/
class cacher{
/**
* An array of server IPs defined in the config for our memcache
* @var array
*/
public $serverArray;
/**
* Reserved for the memcache object if initialized on construct
* @var object
*/
public $memCache;
/**
* Construct the cacher object
*
* @param bool[optional] $memcache Enable Memcache capabilities
*/
function __construct($memcache = null){
global $serverArray;
$this->serverArray = $serverArray;
if($memcache) $this->memCache = new Memcache;
}
/**
* Function to connect to the memCache server
*
* If failure to connecting to server, it will try next sever in the array.
*
* @param int|string[optional] $server Index of stored servers or custom server
* @param bool[optional] $pCon Pressistent connection
*/
function memConnect($server = null, $pCon = null) {
// Check if memCache was generated
if($this->memCache) {
// Check if pressistent connection was requested
// Determin which memCache function to use for connection
$pCon = ($pCon ? 'pconnect' : 'connect');
// Check if a server was specified
if($server) {
// Check if passed value is a server array key retrieve key's value
if(strpos($server, '.') === false) {
$server1 = $this->serverArray[$server];
} else {
$server1 = split(':', $server);
}
// Split server IP from Port
// If Port not specified store default
if(!array_key_exists(1, $server1)) $server1[1] = '11211';
// Attempt connection
$memcon = @$this->memCache->$pCon($server1[0], $server1[1]);
} else {
$serverArrayCount = count($this->serverArray);
// Loop through the server array untill connection
for ($i = 0; $i <= $serverArrayCount; ++$i) {
// Attempt connection
$memcon = @$this->memCache->$pCon($this->serverArray[$i][0],
(array_key_exists(1, $this->serverArray[$i]) ?
$this->serverArray[$i][1] : '11211'));
// If connection made drop out of for loop
if($memcon) break;
}
}
// Check if connection made
if($memcon) {
return array(1, 1);
} else {
if ($server) {
$this->p_error(0, 'There was an error while trying to connect to the memcache server IP: ' . $server[0] . ' Port: ' . $server[1]);
return array(0, 'Error with connection to memcache server');
} else {
$this->p_error(0,'Error with connecting to memcache server, exhausted all servers trough serverArray');
return array(0,"Error with connecting to memcach server, exhausted all attempts");
}
}
} else {
// memcache object was not created in the constructor
return array(0,"Memcache object was not created in the constructor");
}
}
function add($key, $value, $engine, $ttl = null, $memPCon = null, $memServer = null, $memFlag = false){
/* --------------------------------------
Function to add data to our cache.
Do a switch on engine to add our data
to the right cache.
------------------------------------*/
switch($engine){
case "APC":
// add to our APC memory cache system.
$add = apc_add($key,$value,$ttl);
if($add){
return array(1,1);
}else{
$this->p_error(0,"Error with storing data into the APC system. Key:" . $key);
return array(0,"Error with storing data into the APC cache system");
}
break;
case "MEM":
// add to our memcache memory cache system.
if($memServer){
$memcon = $this->memConnect($memServer,$memPCon);
if($memcon[0]){
$add = $this->memCache->add($key,$value,$memFlag,$ttl);
if($add){
return array(1,1);
}else{
$this->p_error(0,"Error with storing data into the memcache system. Key:" . $key);
return array(0,"Error with storing data into the memcache system");
}
}else{
return array(0,$memcon[1]);
}
}else{
$memcon = $this->memConnect();
if($memcon[0]){
$add = $this->memCache->add($key,$value,$memFlag,$ttl);
if($add){
return array(1,1);
}else{
$this->p_error(0,"Error with storing datainto the memcache system. Key:" . $key);
return array(0,"Error with storing data into the memcache system");
}
}else{
return array(0,$memcon[1]);
}
}
break;
case "APCMEM":
// add to both memcache and APC caching systems.
$errs = array();
// APC
$APCadd = apc_add($key,$value,$ttl);
if(!$APCadd){
$this->p_error(0,"Error with storing data into the APC system. Key:" . $key);
$errs[] = 'Error with storing data into the APC cache system';
}
//memcache
if($memServer){
$memcon = $this->memConnect($memServer,$memPCon);
if($memcon[0]){
$add = $this->memCache->add($key,$value,$memFlag,$ttl);
if(!$add){
$this->p_error(0,"Error with storing data into the memcache system. Key:" . $key);
$errs[] = "Error with storing data into the memcache system";
}
}else{
$errs[] = $memcon[1];
}
}else{
$memcon = $this->memConnect();
if($memcon[0]){
$add = $this->memCache->add($key,$value,$memFlag,$ttl);
if(!$add){
$this->p_error(0,"Error with storing datainto the memcache system. Key:" . $key);
$errs[] = "Error with storing data into the memcache system";
}
}else{
$errs[] = $memcon[1];
}
}
// check to make sure there are no errors
if(empty($errs)) return array(1,1); else return array(0,$errs);
break;
default:
return array(0,"Unkown memory engine supllied");
break;
}
}
function get($key, $engine, $memServer = null){
/* ----------------------------------------
Function to get dat from system defined
cached.
--------------------------------------*/
switch($engine){
case "APC":
$fetch = apc_fetch($key);
if($fetch){
return array(1,$fetch);
}else{
//$this->p_error(0,"Error with getting data from cache. Key:" . $key);
return array(0,"Error with getting data from cache");
}
break;
case "MEM":
$memcon = $this->memConnect($memServer);
if($memcon[0]){
$get = $this->memCache->get($key);
if($get){
return array(1,$get);
}else{
return array(0,"Error with getting data from cache");
}
}else{
return array(0,$memcon[1]);
}
break;
case "APCMEM":
$errs = array();
//APC
$APCData = apc_fetch($key);
if(!$APCData){
$errs[] = 'Error with getting data from APC system cache';
}
//memcache
$memcon = $this->memConnect($memServer);
if($memcon[0]){
$memData = $this->memCache->get($key);
if(!$memData){
$errs[] = 'Error with getting data from memcache system';
}
}else{
$errs[] = 'Error with connecting to memcache server';
}
if(empty($errs)) return array(1,$APCData,$memData); else return array(0,$errs);
break;
default:
return array(0,"Unkown memory engine supllied");
break;
}
}
function replace($key, $value, $engine, $ttl = null, $memFlag = false, $memPCon = null, $memServer = null){
/* --------------------------------------------
Function to replace data that is currently
stored into the system cache. To update
items in the system cache with out reseting
the ttl/ expirartion time. We will do the
following. Inside the array of data or data
its self. Simply put a time stamp + the ttl
value inside. Parse out the the time and
do simple math to figure out time reaming
to set as new TTL/ expirartion time.
--------------------------------------------*/
switch($engine){
case "APC":
$store = apc_store($key,$value,$ttl);
if($store){
return array(1,1);
}else{
$this->p_error(0,"Error with updating APC system cache on key:" . $key);
return array(0,"Error with updating system cache");
}
break;
case "MEM":
$memcon = $this->memConnect($memServer, $memPCon);
if($memcon[0]){
$replace = $this->memCache->replace($key,$value,$memFlag,$ttl);
if($replace){
return array(1,1);
}else{
$this->p_error(0,"Error with updating memcache system cache on key:" . $key);
return array(0,"Error with updating system cache");
}
}else{
return array(0,$memcon[1]);
}
break;
case "APCMEM":
$errs = array();
//APC
$store = apc_store($key,$value,$ttl);
if(!$store){
$errs[] = 'Error with updating APC system cache';
}
//memcache
$memcon = $this->memConnect($memServer, $memPCon);
if($memcon[0]){
$replace = $this->memCache->replace($key,$value,$memFlag,$ttl);
if(!$replace){
$errs[] = 'Error with updating memcache system cache';
}
}else{
$errs[] = $memcon[1];
}
if(empty($errs)) return array(1,1); else return array(0,$errs);
break;
default:
return array(0,"Unkown memory engine supllied");
break;
}
}
function delete($key,$engine,$memServer = null){
switch($engine){
case "APC":
$del = apc_delete($key);
if($del) return true; else return false;
break;
case "MEM":
$memcon = $this->memConnect($memServer);
if($memcon[0]){
$del = $this->memCache->delete($key);
if($del) return true; else return false;
}else{
return false;
}
break;
case "APCMEM":
$errs = array();
//APC
$del = apc_delete($key);
if(!$del) $errs[] = 'Error with removing key from APC';
//memcahce
$memcon = $this->memConnect($memServer);
if($memcon[0]){
$del = $this->memCache->delete($key);
if(!$del) $errs[] = 'Error with removing key from memcache';
}
if(empty($errs)) return true; else return false;
break;
default:
return array(0,"Unkown memory engine supllied");
break;
}
}
function flushIt(){
/* --------------------------------------------
Function to removoe the entire system cache
from ALL servers.
--------------------------------------------*/
// first flush out our APC
@apc_clear_cache();
if($this->memCache){
for($i=0;$i<count($this->serverArray);$i++){
$memcon = $this->memConnect($this->serverArray[$i]);
if($memcon) $this->memCache->flush();
$this->memCache->close();
}
}
}
function prepTTL($ttl){
/* --------------------------------------------
Function to take a current ttl value and
compare to system time , to figure out a new
ttl value for updating/replacing data in cache
for example.
1207100600 stored ttl value
1207100200 current system time
400 new TTL value
--------------------------------------------*/
$curTime = time();
$newTTL = $ttl - $curTime;
return $newTTL;
}
function p_error($err,$sql = ""){
switch($err){
case 0:
// custom error
$err = "0 - " . date("m-j-y") . " Custom Error: " . $sql;
write_error("CACHER",$err);
break;
default:
break;
}
}
function __destruct(){
if($this->memCache){
$this->memCache->close();
}
}
}
?>