Created
November 25, 2011 21:45
-
-
Save jjt/1394482 to your computer and use it in GitHub Desktop.
Arbitrary redis caching of output and serializable objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Needs a global $redis_config | |
function get_redis($force=false) { | |
global $redis_config,$redis_instance; | |
if(!is_object($redis_config)) | |
die("Couldn't find \$redis_config or it's not an object!"); | |
// No redis? No problem! | |
if(!class_exists('Redis') || !extension_loaded('redis')) { | |
$redis_instance = new Fake_Redis(); | |
return $redis_instance; | |
} | |
if(!$redis_instance || $force !== false) { | |
$redis_instance = new Redis(); | |
$redis_ip = $redis_config->ip; | |
if(!$redis_ip) | |
$redis_ip = 'localhost'; | |
$redis_instance->connect($redis_ip); | |
// Let's keep the redis databases separate! | |
if(!isset($redis_config->db_id)) | |
die('Warning! No redis db selected'); | |
else | |
$redis_instance->select($redis_config->db_id); | |
} | |
return $redis_instance; | |
} | |
// Base class for a cached object, represents one redis entry | |
class Redis_Cache { | |
var $key_prefix = ''; | |
function __construct($user_key,$opts='') { | |
$default_opts = array( | |
'output_cache' => true, | |
'profile' => false, | |
'profile_noisy' => true, | |
'expires' => false | |
); | |
$this->opts = array_merge($default_opts,(array)$opts); | |
if(isset($_GET['redis_debug'])) | |
$this->opts['profile'] = true; | |
// We add info to our keys | |
$this->user_key = $user_key; | |
$this->key = $user_key; | |
if($this->key_prefix !== '') | |
$this->key = "$this->key_prefix:$this->key"; | |
$this->redis = get_redis(); | |
$this->cache = $this->redis->get($this->key); | |
// Bust the cache! | |
if(isset($_GET['redis_bust'])) | |
$this->cache = false; | |
$this->cache_hit = $this->cache !== false; | |
$this->cache_miss = !$this->cache_hit; | |
$this->cache_hit_str = $this->cache !== false ? 'hit' : 'miss'; | |
} | |
function write_cache($val,$expires=false) { | |
if(!$expires) | |
$expires = $this->opts['expires']; | |
if($expires) | |
return $this->redis->setex($this->key,$expires,$val); | |
$this->redis->set($this->key,$val); | |
} | |
function profile_start($noisy=true) { | |
if(!$this->opts['profile']) | |
return; | |
$this->time_start = microtime(true); | |
if($noisy && $this->opts['profile_noisy']) | |
echo "\n\n<!-- REDIS BEGIN: $this->user_key, $this->cache_hit_str -->\n\n"; | |
} | |
function profile_end($noisy=true) { | |
if(!$this->opts['profile']) | |
return; | |
$this->time_end = microtime(true); | |
$this->time_delta = round($this->time_end - $this->time_start,5); | |
if($noisy && $this->opts['profile_noisy']) | |
echo "\n\n<!-- REDIS END: $this->user_key, $this->cache_hit_str, $this->time_delta -->\n\n"; | |
} | |
} | |
// Redis output buffering for caching arbitrary output | |
// You have to do the (strict) checking yourself: | |
// | |
// $rob = new Redis_OB('my-key'); | |
// if($rob->cache === false) | |
// ... your code ... | |
// $rob->output(); | |
class Redis_Cache_OB extends Redis_Cache { | |
var $key_prefix = 'Cache_OB'; | |
function __construct($key,$opts='') { | |
parent::__construct($key,$opts); | |
$this->profile_start(); | |
if($this->cache_miss) | |
ob_start(); | |
} | |
function end() { | |
if($this->cache_miss) { | |
$this->cache = ob_get_clean(); | |
$this->write_cache($this->cache); | |
} | |
} | |
function output() { | |
$this->end(); | |
if($this->opts['output_cache']) | |
echo $this->cache; | |
$this->profile_end(); | |
} | |
} | |
// Makes a one liner out of the caching process | |
// You can pass through a string with a function name, or an anonymous function | |
// Optional args array for the called fn | |
class Redis_Cache_OB_Func extends Redis_Cache_OB { | |
function __construct($key,$func,$args=false,$opts='') { | |
parent::__construct($key,$opts); | |
if($this->cache_miss) { | |
if($args !== false && is_array($args)) | |
call_user_func_array($func,$args); | |
else | |
call_user_func($func); | |
} | |
$this->output(); | |
} | |
} | |
// Caching a php variable through serialize() | |
class Redis_Cache_Var extends Redis_Cache { | |
var $key_prefix = 'Cache_Var'; | |
} | |
// Since we can't delay instantiation of a new object at call time, we have to wrap it in a callback function that returns the new object | |
// We could do it with new Redis_Cache_Var('key','class_name',array('constructor','params')) but anon fns are more flexible | |
// | |
// Before caching: | |
// $my_obj = new MyObj(); | |
// After caching: | |
// $my_obj = redis_cache_var('my_obj',function(){ | |
// return new MyObj(); | |
// }); | |
// | |
function redis_cache_var($key,$cb_func,$opts='') { | |
$rcv = new Redis_Cache_Var($key,$opts); | |
$rcv->profile_start(); | |
if($rcv->cache_hit) | |
$obj = unserialize($rcv->cache); | |
else { | |
$obj = $cb_func(); | |
$rcv->write_cache(serialize($obj)); | |
} | |
$rcv->profile_end(); | |
return $obj; | |
} | |
// Allows us silent redis errors in case we don't have it | |
class Fake_Redis { | |
// Need to have some way of telling if we're a dirty faker! | |
var $is_fake_redis = true; | |
// Stubbbbzz | |
function connect($a='',$b='',$c='',$d='',$e='') { return false; } | |
function pconnect($a='',$b='',$c='',$d='',$e='') { return false; } | |
function close($a='',$b='',$c='',$d='',$e='') { return false; } | |
function ping($a='',$b='',$c='',$d='',$e='') { return false; } | |
function get($a='',$b='',$c='',$d='',$e='') { return false; } | |
function set($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setex($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setnx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getSet($a='',$b='',$c='',$d='',$e='') { return false; } | |
function randomKey($a='',$b='',$c='',$d='',$e='') { return false; } | |
function renameKey($a='',$b='',$c='',$d='',$e='') { return false; } | |
function renameNx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getMultiple($a='',$b='',$c='',$d='',$e='') { return false; } | |
function exists($a='',$b='',$c='',$d='',$e='') { return false; } | |
function delete($a='',$b='',$c='',$d='',$e='') { return false; } | |
function incr($a='',$b='',$c='',$d='',$e='') { return false; } | |
function incrBy($a='',$b='',$c='',$d='',$e='') { return false; } | |
function decr($a='',$b='',$c='',$d='',$e='') { return false; } | |
function decrBy($a='',$b='',$c='',$d='',$e='') { return false; } | |
function type($a='',$b='',$c='',$d='',$e='') { return false; } | |
function append($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getRange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setRange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getBit($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setBit($a='',$b='',$c='',$d='',$e='') { return false; } | |
function strlen($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getKeys($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sort($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sortAsc($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sortAscAlpha($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sortDesc($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sortDescAlpha($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lPush($a='',$b='',$c='',$d='',$e='') { return false; } | |
function rPush($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lPushx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function rPushx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lPop($a='',$b='',$c='',$d='',$e='') { return false; } | |
function rPop($a='',$b='',$c='',$d='',$e='') { return false; } | |
function blPop($a='',$b='',$c='',$d='',$e='') { return false; } | |
function brPop($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lSize($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lRemove($a='',$b='',$c='',$d='',$e='') { return false; } | |
function listTrim($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lGet($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lGetRange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lSet($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lInsert($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sAdd($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sSize($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sRemove($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sMove($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sPop($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sRandMember($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sContains($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sMembers($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sInter($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sInterStore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sUnion($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sUnionStore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sDiff($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sDiffStore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setTimeout($a='',$b='',$c='',$d='',$e='') { return false; } | |
function save($a='',$b='',$c='',$d='',$e='') { return false; } | |
function bgSave($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lastSave($a='',$b='',$c='',$d='',$e='') { return false; } | |
function flushDB($a='',$b='',$c='',$d='',$e='') { return false; } | |
function flushAll($a='',$b='',$c='',$d='',$e='') { return false; } | |
function dbSize($a='',$b='',$c='',$d='',$e='') { return false; } | |
function auth($a='',$b='',$c='',$d='',$e='') { return false; } | |
function ttl($a='',$b='',$c='',$d='',$e='') { return false; } | |
function persist($a='',$b='',$c='',$d='',$e='') { return false; } | |
function info($a='',$b='',$c='',$d='',$e='') { return false; } | |
function resetStat($a='',$b='',$c='',$d='',$e='') { return false; } | |
function select($a='',$b='',$c='',$d='',$e='') { return false; } | |
function move($a='',$b='',$c='',$d='',$e='') { return false; } | |
function bgrewriteaof($a='',$b='',$c='',$d='',$e='') { return false; } | |
function slaveof($a='',$b='',$c='',$d='',$e='') { return false; } | |
function object($a='',$b='',$c='',$d='',$e='') { return false; } | |
function mset($a='',$b='',$c='',$d='',$e='') { return false; } | |
function msetnx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function rpoplpush($a='',$b='',$c='',$d='',$e='') { return false; } | |
function brpoplpush($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zAdd($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zDelete($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zReverseRange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRevRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zCount($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zDeleteRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zDeleteRangeByRank($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zCard($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRank($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRevRank($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zInter($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zUnion($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zIncrBy($a='',$b='',$c='',$d='',$e='') { return false; } | |
function expireAt($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hGet($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hSet($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hSetNx($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hDel($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hLen($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hKeys($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hVals($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hGetAll($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hExists($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hIncrBy($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hMset($a='',$b='',$c='',$d='',$e='') { return false; } | |
function hMget($a='',$b='',$c='',$d='',$e='') { return false; } | |
function multi($a='',$b='',$c='',$d='',$e='') { return false; } | |
function discard($a='',$b='',$c='',$d='',$e='') { return false; } | |
function exec($a='',$b='',$c='',$d='',$e='') { return false; } | |
function pipeline($a='',$b='',$c='',$d='',$e='') { return false; } | |
function watch($a='',$b='',$c='',$d='',$e='') { return false; } | |
function unwatch($a='',$b='',$c='',$d='',$e='') { return false; } | |
function publish($a='',$b='',$c='',$d='',$e='') { return false; } | |
function subscribe($a='',$b='',$c='',$d='',$e='') { return false; } | |
function unsubscribe($a='',$b='',$c='',$d='',$e='') { return false; } | |
function getOption($a='',$b='',$c='',$d='',$e='') { return false; } | |
function setOption($a='',$b='',$c='',$d='',$e='') { return false; } | |
function open($a='',$b='',$c='',$d='',$e='') { return false; } | |
function popen($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lLen($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sGetMembers($a='',$b='',$c='',$d='',$e='') { return false; } | |
function mget($a='',$b='',$c='',$d='',$e='') { return false; } | |
function expire($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zunionstore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zinterstore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRemove($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRem($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRemoveRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRemRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zRemRangeByRank($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zSize($a='',$b='',$c='',$d='',$e='') { return false; } | |
function substr($a='',$b='',$c='',$d='',$e='') { return false; } | |
function rename($a='',$b='',$c='',$d='',$e='') { return false; } | |
function del($a='',$b='',$c='',$d='',$e='') { return false; } | |
function keys($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lrem($a='',$b='',$c='',$d='',$e='') { return false; } | |
function ltrim($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lindex($a='',$b='',$c='',$d='',$e='') { return false; } | |
function lrange($a='',$b='',$c='',$d='',$e='') { return false; } | |
function scard($a='',$b='',$c='',$d='',$e='') { return false; } | |
function srem($a='',$b='',$c='',$d='',$e='') { return false; } | |
function sismember($a='',$b='',$c='',$d='',$e='') { return false; } | |
function zrevrange($a='',$b='',$c='',$d='',$e='') { return false; } | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment