├── README.markdown ├── cache.class.php ├── composer.json └── license.txt /README.markdown: -------------------------------------------------------------------------------- 1 | # Simple PHP Cache # 2 | 3 | ## About ## 4 | 5 | A light, simple but powerful PHP5 Cache Class which uses the filesystem for caching. 6 | Your feedback is always welcome. 7 | 8 | ## Requirements ## 9 | 10 | - PHP 5.2.x or higher 11 | 12 | ## Introduction ## 13 | 14 | Basically the caching class stores its data in files in the JSON format. These files will be created if you store data under a Cache name. 15 | 16 | If you set a new Cache name with `setCache()`, a new cache file will be generated. The Cache will store all further data in the new file. The Setter method allows you to switch between the different Cache files. 17 | 18 | ## Quick Start ## 19 | 20 | ### Setup Cache class ### 21 | 22 | It's not much trouble to setup the Cache. 23 | First create a writable directory `cache/` and include the Cache class: 24 | 25 | ```php 26 | 32 | ``` 33 | 34 | Now we've setup the Cache instance and can start caching! 35 | 36 | ```php 37 | store('hello', 'Hello World!'); 40 | 41 | // generate a new cache file with the name 'newcache' 42 | $c->setCache('newcache'); 43 | 44 | // store an array 45 | $c->store('movies', array( 46 | 'description' => 'Movies on TV', 47 | 'action' => array( 48 | 'Tropic Thunder', 49 | 'Bad Boys', 50 | 'Crank' 51 | ) 52 | )); 53 | 54 | // get cached data by its key 55 | $result = $c->retrieve('movies'); 56 | 57 | // display the cached array 58 | echo '
'; 59 | print_r($result); 60 | echo ''; 61 | 62 | // grab array entry 63 | $description = $result['description']; 64 | 65 | // switch back to the first cache 66 | $c->setCache('mycache'); 67 | 68 | // update entry by simply overwriting an existing key 69 | $c->store('hello', 'Hello everybody out there!'); 70 | 71 | // erase entry by its key 72 | $c->erase('hello'); 73 | ?> 74 | ``` 75 | 76 | You can also make use of the Method Chaining feature, introduced in PHP5. 77 | So you can do something like that: 78 | 79 | ```php 80 | setCache('mycache') // generate new file 82 | ->store('hello', 'world') // store data string 83 | ->retrieve('hello'); // retrieve cached data 84 | ?> 85 | ``` 86 | 87 | ## Available methods ## 88 | 89 | ### Setup the Cache ### 90 | 91 | `new Cache(/ )` 92 | 93 | `string` gives you the basic setup. 94 | It's the name of your Cache (standard Cache name is *'default'*): 95 | 96 | new Cache('YOUR-CACHE-NAME'); 97 | 98 | `array` allows you to define multiple optional parameters: 99 | 100 | new Cache(array( 101 | 'name' => 'YOUR-CACHE-NAME', 102 | 'path' => 'cache/', 103 | 'extension' => '.cache' 104 | )); 105 | 106 | If you don't define a Cache name with the constructor or the `setCache()` method, it'll be 'default'. 107 | 108 | ### Store data ### 109 | 110 | `store($key, $data, <$expiration>)` 111 | 112 | - The `key` value defines a tag with which the cached data will be associated. 113 | - The `data` value can be any type of object (will be serialized). 114 | - The `expiration` value allows you to define an expiration time. 115 | 116 | To change data you can overwrite it by using the same key identifier. 117 | Beside the data, the Cache will also store a timestamp. 118 | 119 | A sample Cache entry looks like this: 120 | 121 | ```json 122 | { 123 | "christmas": { 124 | "time": 1324664631, 125 | "expire": 28000, 126 | "data": "s:29:"A great time to bake cookies.";" // serialized 127 | } 128 | } 129 | ``` 130 | 131 | ### Retrieve data ### 132 | 133 | `retrieve($key, <$timestamp>)` 134 | 135 | Get particular cached data by its key. 136 | To retrieve the timestamp of a key, set the second parameter to `true`. 137 | 138 | `retrieveAll(<$meta>)` 139 | 140 | This allows you retrieve all the cached data at once. You get the meta data by setting the `$meta` argument to `true`. 141 | 142 | ### Erase data ### 143 | 144 | For erasing cached data are these three methods available: 145 | 146 | - `erase($key)` Erases a single entry by its key. 147 | - `eraseAll()` Erases all entries from the Cache file. 148 | - `eraseExpired()` Erases all expired entries. 149 | 150 | ```php 151 | eraseExpired() . ' expired items erased!'; 154 | ?> 155 | ``` 156 | 157 | ### Check cached data ### 158 | 159 | `isCached($key)` 160 | 161 | Check whether any data is associated with the given key. 162 | Returns `true` or `false`. 163 | 164 | ### Set Cache name ### 165 | 166 | `setCache($name)` 167 | 168 | If you want to switch to another Cache or create a new one, then use this method to set a new Cache name. 169 | 170 | ### Set Cache path ### 171 | 172 | `setCachePath($path)` 173 | 174 | The path to the Cache folder must end with a backslash: `my_path_to_the_cache_folder/` 175 | 176 | ### Get Cache file path ### 177 | 178 | `getCacheDir()` 179 | 180 | The method returns the path to your current Cache file (the Cache name is always sh1 encoded): 181 | 182 | ``` 183 | cache/7505d64a54e061b7acd54ccd58b49dc43500b635.cache 184 | ``` 185 | 186 | ## Benchmarks ## 187 | 188 | > If you've done one, please let me know. 189 | 190 | ## History ## 191 | 192 | > Upcoming: Simple Cache 2.0 193 | > Implementation of an internal "soft cache", hash-sum handling and the switch to serialization. Thanks @dariushha for his contribution! 194 | 195 | **Simple Cache 1.6 - 04/01/2014** 196 | 197 | - `update` Updated docs. 198 | - `bug` Fixed `retrieveAll()` method to unserialize data. 199 | 200 | **Simple Cache 1.5 - 01/01/2014** 201 | 202 | - `feature` added `serialize` / `unserialize` to store any kind of data. 203 | 204 | **Simple Cache 1.4 - 08/09/2013** 205 | 206 | - `bug` Fixed loading file twice in `store()` method. 207 | - `bug` Fixed `retrieve()` method - made it fail safe (thanks @dariushha). 208 | 209 | **Simple Cache 1.3 - 28/02/2013** 210 | 211 | - `update` Updated docs for the added `retrieveAll()` method. 212 | - `feature` Added `retrieveAll()` method (thanks @rpnzl). 213 | 214 | **Simple Cache 1.2 - 09/05/2012** 215 | 216 | - `update` Formatted code 217 | - `bug` Fixed `isCached()` method so that it works as expected (thanks @TigerWolf). 218 | 219 | **Simple Cache 1.1 - 01/01/2012** 220 | 221 | - `change` The extension config has to start now with a dot. 222 | - `feature` Added expiration handling to the `store()` method 223 | - `feature` Added the methods `eraseExpired()` and `eraseAll()` 224 | - `feature` Added method to make sure that a writable directory exists 225 | 226 | **Simple Cache 1.0 - 29/12/2011** 227 | 228 | - `release` First public version 229 | - `feature` Added timestamp option to the `retrieve()` method 230 | 231 | **Simple Cache 0.9 - 25/12/2011** 232 | 233 | - `update` Added Quick Start guide to the documentation 234 | - `feature` Added Method Chaining possibility 235 | - `bug` Fixed constructor configuration string/array handling 236 | 237 | **Simple Cache 0.8 - 24/12/2011** 238 | 239 | - `release` First internal beta version (tested) 240 | - `feature` Added Setter and Getter methods 241 | - `update` Detailed documentation 242 | 243 | **Simple Cache 0.5 - 22/12/2011** 244 | 245 | - `release` First internal alpha version 246 | - `update` Small documentation 247 | 248 | ## Credits ## 249 | 250 | Copyright (c) 2011-2013 - Programmed by Christian Metz / [@cosenary](http://twitter.com/cosenary) 251 | Released under the [BSD License](http://www.opensource.org/licenses/bsd-license.php). -------------------------------------------------------------------------------- /cache.class.php: -------------------------------------------------------------------------------- 1 | setCache($config); 47 | } else if (is_array($config)) { 48 | $this->setCache($config['name']); 49 | $this->setCachePath($config['path']); 50 | $this->setExtension($config['extension']); 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * Check whether data accociated with a key 57 | * 58 | * @param string $key 59 | * @return boolean 60 | */ 61 | public function isCached($key) { 62 | if (false != $this->_loadCache()) { 63 | $cachedData = $this->_loadCache(); 64 | return isset($cachedData[$key]['data']); 65 | } 66 | } 67 | 68 | /** 69 | * Store data in the cache 70 | * 71 | * @param string $key 72 | * @param mixed $data 73 | * @param integer [optional] $expiration 74 | * @return object 75 | */ 76 | public function store($key, $data, $expiration = 0) { 77 | $storeData = array( 78 | 'time' => time(), 79 | 'expire' => $expiration, 80 | 'data' => serialize($data) 81 | ); 82 | $dataArray = $this->_loadCache(); 83 | if (true === is_array($dataArray)) { 84 | $dataArray[$key] = $storeData; 85 | } else { 86 | $dataArray = array($key => $storeData); 87 | } 88 | $cacheData = json_encode($dataArray); 89 | file_put_contents($this->getCacheDir(), $cacheData); 90 | return $this; 91 | } 92 | 93 | /** 94 | * Retrieve cached data by its key 95 | * 96 | * @param string $key 97 | * @param boolean [optional] $timestamp 98 | * @return string 99 | */ 100 | public function retrieve($key, $timestamp = false) { 101 | $cachedData = $this->_loadCache(); 102 | (false === $timestamp) ? $type = 'data' : $type = 'time'; 103 | if (!isset($cachedData[$key][$type])) return null; 104 | return unserialize($cachedData[$key][$type]); 105 | } 106 | 107 | /** 108 | * Retrieve all cached data 109 | * 110 | * @param boolean [optional] $meta 111 | * @return array 112 | */ 113 | public function retrieveAll($meta = false) { 114 | if ($meta === false) { 115 | $results = array(); 116 | $cachedData = $this->_loadCache(); 117 | if ($cachedData) { 118 | foreach ($cachedData as $k => $v) { 119 | $results[$k] = unserialize($v['data']); 120 | } 121 | } 122 | return $results; 123 | } else { 124 | return $this->_loadCache(); 125 | } 126 | } 127 | 128 | /** 129 | * Erase cached entry by its key 130 | * 131 | * @param string $key 132 | * @return object 133 | */ 134 | public function erase($key) { 135 | $cacheData = $this->_loadCache(); 136 | if (true === is_array($cacheData)) { 137 | if (true === isset($cacheData[$key])) { 138 | unset($cacheData[$key]); 139 | $cacheData = json_encode($cacheData); 140 | file_put_contents($this->getCacheDir(), $cacheData); 141 | } else { 142 | throw new Exception("Error: erase() - Key '{$key}' not found."); 143 | } 144 | } 145 | return $this; 146 | } 147 | 148 | /** 149 | * Erase all expired entries 150 | * 151 | * @return integer 152 | */ 153 | public function eraseExpired() { 154 | $cacheData = $this->_loadCache(); 155 | if (true === is_array($cacheData)) { 156 | $counter = 0; 157 | foreach ($cacheData as $key => $entry) { 158 | if (true === $this->_checkExpired($entry['time'], $entry['expire'])) { 159 | unset($cacheData[$key]); 160 | $counter++; 161 | } 162 | } 163 | if ($counter > 0) { 164 | $cacheData = json_encode($cacheData); 165 | file_put_contents($this->getCacheDir(), $cacheData); 166 | } 167 | return $counter; 168 | } 169 | } 170 | 171 | /** 172 | * Erase all cached entries 173 | * 174 | * @return object 175 | */ 176 | public function eraseAll() { 177 | $cacheDir = $this->getCacheDir(); 178 | if (true === file_exists($cacheDir)) { 179 | $cacheFile = fopen($cacheDir, 'w'); 180 | fclose($cacheFile); 181 | } 182 | return $this; 183 | } 184 | 185 | /** 186 | * Load appointed cache 187 | * 188 | * @return mixed 189 | */ 190 | private function _loadCache() { 191 | if (true === file_exists($this->getCacheDir())) { 192 | $file = file_get_contents($this->getCacheDir()); 193 | return json_decode($file, true); 194 | } else { 195 | return false; 196 | } 197 | } 198 | 199 | /** 200 | * Get the cache directory path 201 | * 202 | * @return string 203 | */ 204 | public function getCacheDir() { 205 | if (true === $this->_checkCacheDir()) { 206 | $filename = $this->getCache(); 207 | $filename = preg_replace('/[^0-9a-z\.\_\-]/i', '', strtolower($filename)); 208 | return $this->getCachePath() . $this->_getHash($filename) . $this->getExtension(); 209 | } 210 | } 211 | 212 | /** 213 | * Get the filename hash 214 | * 215 | * @return string 216 | */ 217 | private function _getHash($filename) { 218 | return sha1($filename); 219 | } 220 | 221 | /** 222 | * Check whether a timestamp is still in the duration 223 | * 224 | * @param integer $timestamp 225 | * @param integer $expiration 226 | * @return boolean 227 | */ 228 | private function _checkExpired($timestamp, $expiration) { 229 | $result = false; 230 | if ($expiration !== 0) { 231 | $timeDiff = time() - $timestamp; 232 | ($timeDiff > $expiration) ? $result = true : $result = false; 233 | } 234 | return $result; 235 | } 236 | 237 | /** 238 | * Check if a writable cache directory exists and if not create a new one 239 | * 240 | * @return boolean 241 | */ 242 | private function _checkCacheDir() { 243 | if (!is_dir($this->getCachePath()) && !mkdir($this->getCachePath(), 0775, true)) { 244 | throw new Exception('Unable to create cache directory ' . $this->getCachePath()); 245 | } elseif (!is_readable($this->getCachePath()) || !is_writable($this->getCachePath())) { 246 | if (!chmod($this->getCachePath(), 0775)) { 247 | throw new Exception($this->getCachePath() . ' must be readable and writeable'); 248 | } 249 | } 250 | return true; 251 | } 252 | 253 | /** 254 | * Cache path Setter 255 | * 256 | * @param string $path 257 | * @return object 258 | */ 259 | public function setCachePath($path) { 260 | $this->_cachepath = $path; 261 | return $this; 262 | } 263 | 264 | /** 265 | * Cache path Getter 266 | * 267 | * @return string 268 | */ 269 | public function getCachePath() { 270 | return $this->_cachepath; 271 | } 272 | 273 | /** 274 | * Cache name Setter 275 | * 276 | * @param string $name 277 | * @return object 278 | */ 279 | public function setCache($name) { 280 | $this->_cachename = $name; 281 | return $this; 282 | } 283 | 284 | /** 285 | * Cache name Getter 286 | * 287 | * @return void 288 | */ 289 | public function getCache() { 290 | return $this->_cachename; 291 | } 292 | 293 | /** 294 | * Cache file extension Setter 295 | * 296 | * @param string $ext 297 | * @return object 298 | */ 299 | public function setExtension($ext) { 300 | $this->_extension = $ext; 301 | return $this; 302 | } 303 | 304 | /** 305 | * Cache file extension Getter 306 | * 307 | * @return string 308 | */ 309 | public function getExtension() { 310 | return $this->_extension; 311 | } 312 | 313 | } 314 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cosenary/simple-php-cache", 3 | "type": "library", 4 | "description": "A light, simple but powerful PHP5 Cache Class which uses the filesystem for caching.", 5 | "keywords": ["cache", "simple", "filesystem", "json"], 6 | "homepage": "https://github.com/cosenary/Simple-PHP-Cache", 7 | "license": "BSD", 8 | "authors": [ 9 | { 10 | "name": "Christian Metz", 11 | "email": "christian-metz1@gmx.net", 12 | "homepage": "http://metzweb.net" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.2.0", 17 | "ext-curl": "*" 18 | }, 19 | "autoload": { 20 | "classmap": [ 21 | "." 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Christian Metz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | * Neither the name of the organisation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------