├── README ├── example_cache_table.sql ├── MCache.php ├── FileCache.php ├── SQLCache.php └── Cache.php /README: -------------------------------------------------------------------------------- 1 | Please see http://www.derivante.com/2010/04/23/extensible-php-caching-library/ for directions on use. 2 | 3 | NOTE: The SQLCache currently is set up to use database abstraction for Drupal. If you don't use drupal 4 | please modify the calls for your use. 5 | 6 | -------------------------------------------------------------------------------- /example_cache_table.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE TABLE IF NOT EXISTS `cache` ( 3 | `column1` int(11) NOT NULL, 4 | `column2` int(11) NOT NULL, 5 | `column3` int(11) NOT NULL, 6 | `data` mediumblob NOT NULL, 7 | `expiration` int(11) NOT NULL, 8 | UNIQUE KEY `key1` (`column1`,`column2`,`column3`) 9 | ) ENGINE=MyISAM; 10 | -------------------------------------------------------------------------------- /MCache.php: -------------------------------------------------------------------------------- 1 | . 23 | */ 24 | 25 | 26 | require_once('Cache.php'); 27 | 28 | 29 | /** 30 | * MCache is a Memcached specific extension of the Cache class. 31 | * 32 | * @author jleider 33 | */ 34 | class MCache extends Cache { 35 | 36 | private $memcache; 37 | private $server = "localhost"; 38 | private $port = 11211; 39 | 40 | 41 | /** 42 | * Connect to memcache and set key. 43 | */ 44 | public function __construct($key) { 45 | $this->memcache = new Memcache; 46 | $this->memcache->connect($this->server, $this->port); 47 | parent::__construct($key); 48 | } 49 | 50 | /** 51 | * Make sure we call Cache->__destruct() first so variables arent unset too early 52 | */ 53 | public function __destruct() { 54 | parent::__destruct(); 55 | } 56 | 57 | /** 58 | * Set the data into Memcached. 59 | */ 60 | protected function _setCache() { 61 | $this->memcache->set($this->_getKey(), $this->data, MEMCACHE_COMPRESSED, $this->expiration); 62 | } 63 | 64 | /** 65 | * Delete the data from Memcached. 66 | */ 67 | protected function _deleteCache() { 68 | $this->memcache->delete($this->_getKey()); 69 | } 70 | 71 | /** 72 | * Fetch the cached data from Memcached. 73 | */ 74 | protected function _getCache() { 75 | $this->data = $this->memcache->get($this->_getKey()); 76 | if(!$this->data) { 77 | $this->expiration = 0; 78 | } 79 | } 80 | 81 | 82 | private function _getKey() { 83 | asort($this->key); 84 | $key = ''; 85 | foreach($this->key as $k => $v) { 86 | $key .= $k.':'.$v; 87 | } 88 | return $key; 89 | } 90 | 91 | } 92 | 93 | 94 | class MCacheException extends CacheException {} 95 | 96 | 97 | -------------------------------------------------------------------------------- /FileCache.php: -------------------------------------------------------------------------------- 1 | . 23 | */ 24 | 25 | 26 | require_once('Cache.php'); 27 | 28 | 29 | /** 30 | * FileCache is filesystem specific extension of the Cache class. 31 | * 32 | * @author jleider 33 | */ 34 | class FileCache extends Cache { 35 | 36 | private $cacheDir; 37 | 38 | /** 39 | * Set key and cacheDir 40 | */ 41 | public function __construct($key, $dir) { 42 | $dir = trim($dir); 43 | $this->cacheDir = (substr($dir, -1) == '/') ? rtrim($dir, '/') : $dir; 44 | parent::__construct($key); 45 | } 46 | 47 | /** 48 | * Make sure we call Cache->__destruct() first so variables arent unset too early 49 | */ 50 | public function __destruct() { 51 | parent::__destruct(); 52 | } 53 | 54 | 55 | /** 56 | * Save data to file. 57 | */ 58 | protected function _setCache() { 59 | $fp = fopen($this->cacheDir.'/'.$this->_getKey().'.cache', 'w'); 60 | $data = $this->expiration."\n".$this->data; 61 | fwrite($fp, $data); 62 | fclose($fp); 63 | } 64 | 65 | /** 66 | * Delete the file 67 | */ 68 | protected function _deleteCache() { 69 | @unlink($this->cacheDir.'/'.$this->_getKey().'.cache'); 70 | } 71 | 72 | /** 73 | * Fetch the cached data from file. 74 | */ 75 | protected function _getCache() { 76 | $file = @file_get_contents($this->cacheDir.'/'.$this->_getKey().'.cache'); 77 | if($file) { 78 | $pos = strpos($file, "\n"); 79 | $this->expiration = substr($file, 0, $pos); 80 | $this->data = substr($file, $pos+1); 81 | } 82 | } 83 | 84 | 85 | private function _getKey() { 86 | asort($this->key); 87 | $key = ''; 88 | foreach($this->key as $k => $v) { 89 | $key .= $k.'-'.$v; 90 | } 91 | return $key; 92 | } 93 | 94 | } 95 | 96 | 97 | class FileCacheException extends CacheException {} 98 | 99 | 100 | -------------------------------------------------------------------------------- /SQLCache.php: -------------------------------------------------------------------------------- 1 | . 22 | */ 23 | 24 | 25 | require_once('Cache.php'); 26 | 27 | 28 | /** 29 | * SQLCache is a SQL specific extension of the Cache class. 30 | * Currently uses native drupal 5 database abstraction and MySQL specific SQL (REPLACE INTO). 31 | * 32 | * @author jleider 33 | */ 34 | class SQLCache extends Cache { 35 | 36 | /** 37 | * Make sure we call Cache->__destruct() first so variables arent unset too early 38 | */ 39 | public function __destruct() { 40 | parent::__destruct(); 41 | } 42 | 43 | /** 44 | * Set the data into the SQL cache. 45 | */ 46 | protected function _setCache() { 47 | $values = array(); 48 | $query = "REPLACE INTO data_cache SET "; 49 | foreach($this->key as $col => $val) { 50 | $values[] = $col; 51 | $values[] = $val; 52 | $query .= "%s = '%s', "; 53 | } 54 | $values[] = 'data'; 55 | $values[] = gzcompress($this->data); 56 | $values[] = 'expiration'; 57 | $values[] = $this->expiration; 58 | $query .= "%s = '%s', %s = %d"; 59 | 60 | db_query($query, $values); 61 | } 62 | 63 | /** 64 | * Delete the data from the SQL cache. 65 | */ 66 | protected function _deleteCache() { 67 | $values = array(); 68 | $query = "DELETE FROM data_cache WHERE "; 69 | foreach($this->key as $col => $val) { 70 | $values[] = $col; 71 | $values[] = $val; 72 | $query .= "%s = '%s' AND "; 73 | } 74 | $query = substr($query, 0, -4); 75 | 76 | db_query($query, $values); 77 | } 78 | 79 | /** 80 | * Fetch the cached data from SQL. 81 | */ 82 | protected function _getCache() { 83 | $values = array(); 84 | $query = "SELECT expiration, data FROM data_cache WHERE "; 85 | foreach($this->key as $col => $val) { 86 | $values[] = $col; 87 | $values[] = $val; 88 | $query .= "%s = '%s' AND "; 89 | } 90 | $query = substr($query, 0, -4); 91 | $query .= 'LIMIT 1'; 92 | 93 | $cachedData = db_fetch_object(db_query($query, $values)); 94 | if($cachedData) { 95 | $this->expiration = $cachedData->expiration; 96 | $this->data = gzuncompress($cachedData->data); 97 | } 98 | } 99 | 100 | } 101 | 102 | 103 | class SQLCacheException extends CacheException {} 104 | 105 | 106 | -------------------------------------------------------------------------------- /Cache.php: -------------------------------------------------------------------------------- 1 | . 22 | */ 23 | 24 | 25 | /** 26 | * Base abstract Cache class. Extend this class instead of using it directly. 27 | * 28 | * @author jleider 29 | */ 30 | abstract class Cache { 31 | 32 | protected $time; 33 | 34 | protected $key = array(); 35 | protected $data; 36 | protected $expiration; 37 | protected $cacheNow = false; 38 | protected $dataPrimed = false; 39 | 40 | protected $debug = false; 41 | 42 | 43 | /** 44 | * Error messages 45 | */ 46 | protected static $INVALID_KEY = 'Key must be an associative array of column => value pairs'; 47 | protected static $NO_CONNECTION = 'Can not connect to cache'; 48 | protected static $NO_KEY = 'Key has not been set'; 49 | 50 | 51 | /** 52 | * Set the cache key. 53 | * 54 | * @see Extending class' for further information. 55 | * 56 | * @param array $key An associative array with index => value pairs 57 | */ 58 | public function __construct($key) { 59 | $this->time = time(); 60 | $this->setKey($key); 61 | } 62 | 63 | 64 | /** 65 | * Set $this->data. If $data is an array or object, serialize it. 66 | * Generally called by setCache(). 67 | * 68 | * @see setCache() 69 | * 70 | * @param mixed $data 71 | */ 72 | public function setData($data) { 73 | if(is_object($data) || is_array($data)) { 74 | $this->data = serialize($data); 75 | } else { 76 | $this->data = $data; 77 | } 78 | $this->dataPrimed = true; 79 | } 80 | 81 | 82 | /** 83 | * Return the data unseriailzed. 84 | * Generally called by getCache(). 85 | * 86 | * @see getCache() 87 | * 88 | * @return mixed $data 89 | */ 90 | public function getData() { 91 | $data = unserialize($this->data); 92 | return ($data) ? $data : $this->data; 93 | } 94 | 95 | 96 | /** 97 | * Set the cache. This is the suggested way of setting the cached data. 98 | * 99 | * @param mixed $data 100 | * @param mixed $expiration unix timestamp or formatted date string 101 | * @param boolean $cacheNow (Optional) Set to true to force a cache write else defaults to write on __destruct(). 102 | * @see setExpiration() for accepted values 103 | */ 104 | public function setCache($data, $expiration = null, $cacheNow = false) { 105 | $this->setData($data); 106 | $this->setExpiration($expiration); 107 | $this->cacheNow = $cacheNow; 108 | 109 | if(empty($this->key)) { 110 | throw new CacheException(Cache::$NO_KEY); 111 | } 112 | 113 | // Query the respective cache types. 114 | if($cacheNow) { 115 | $this->_setCache(); 116 | $this->dataPrimed = false; 117 | } 118 | } 119 | 120 | 121 | /** 122 | * Delete data from the cache. 123 | * @param array $key An associative array of column => value pairs (Optional if key already set) 124 | */ 125 | public function deleteCache($key = null) { 126 | if($key) { 127 | $this->setKey($key); 128 | } 129 | 130 | // Query the respective cache types 131 | $this->_deleteCache(); 132 | } 133 | 134 | 135 | /** 136 | * Fetch the data from the cache. This is the suggested way of getting cached data. 137 | * 138 | * @param array $key An associative array of column => value pairs (Optional if key already set) 139 | * @see setKey() 140 | * @return mixed $data 141 | */ 142 | public function getCache($key = null) { 143 | if($key) { 144 | $this->setKey($key); 145 | } 146 | 147 | // Query the respective cache types. 148 | $this->_getCache(); 149 | if($this->is_expired()) { 150 | return false; 151 | } else { 152 | return $this->getData(); 153 | } 154 | } 155 | 156 | 157 | /** 158 | * Set the $this->expiration time to a future unix timestamp, defaults to 1 day if no expiration given. 159 | * 160 | * @param mixed $expiration unix timestamp or formatted date string 161 | * @see strtotime() for accepted string inputs. 162 | */ 163 | public function setExpiration($expiration) { 164 | if(is_numeric($expiration) && $expiration > $this->time) { 165 | $this->expiration = $expiration; 166 | } else { 167 | $this->expiration = strtotime($expiration, $this->time); 168 | if(!$this->expiration || $this->expiration < $this->time) { 169 | // Set to daily if something goes wrong 170 | $this->expiration = $this->time + 86400; 171 | } 172 | } 173 | } 174 | 175 | 176 | /** 177 | * Get $this->expiration time in unix timestamp or pass in a valid date format for a date string. 178 | * 179 | * @param string $format @see date() 180 | * @return mixed unix timestamp or formatted date string 181 | */ 182 | public function getExpiration($format = null) { 183 | if($format) { 184 | return strfrtime($format, $this->expiration); 185 | } else { 186 | return $this->expiration; 187 | } 188 | } 189 | 190 | 191 | /** 192 | * Set the key for accessing the cache via an associative array. 193 | * Array must contain column => value pairs for accessing indexes in SQL queries. 194 | * Any keys set with this function will override any existing keys where column is the same. 195 | * 196 | * @param array $key An associative array of column => value pairs 197 | */ 198 | public function setKey($key) { 199 | if(empty($key)) { 200 | throw new CacheException(Cache::$NO_KEY); 201 | } 202 | if(!is_array($key)) { 203 | throw new CacheException(Cache::$INVALID_KEY); 204 | } 205 | $this->key = array_merge($this->key, $key); 206 | } 207 | 208 | 209 | /** 210 | * Returns the current key 211 | * 212 | * @return $this->key 213 | */ 214 | public function getKey() { 215 | return $this->key; 216 | } 217 | 218 | 219 | protected function is_expired() { 220 | if(!$this->expiration || $this->expiration < $this->time) { 221 | return true; 222 | } else { 223 | return false; 224 | } 225 | } 226 | 227 | /** 228 | * Save the cache if it hasnt been saved already. 229 | * 230 | * The destructor will be called even if script execution is stopped using exit() 231 | */ 232 | public function __destruct() { 233 | if($this->dataPrimed) { 234 | $this->_setCache(); 235 | } 236 | } 237 | 238 | 239 | /** 240 | * Cache type specific queries to fetch data. 241 | * Sets all returned values from the cache into variables belonging to $this. 242 | */ 243 | abstract protected function _getCache(); 244 | 245 | /** 246 | * Sets the cache with type specific queries. 247 | * Pulls all values from already instantiated variables belonging to $this. 248 | */ 249 | abstract protected function _setCache(); 250 | 251 | /** 252 | * Delete the cache with type specific queries. 253 | * Pulls all values from already instantiated variables belonging to $this. 254 | */ 255 | abstract protected function _deleteCache(); 256 | 257 | } 258 | 259 | 260 | class CacheException extends Exception {} 261 | 262 | 263 | 264 | 265 | --------------------------------------------------------------------------------