├── README.md ├── config ├── autoload.php └── cache.php ├── libraries └── Cache.php └── spark.info /README.md: -------------------------------------------------------------------------------- 1 | # CodeIgniter-Cache 2 | 3 | CodeIgniter-Cache is a partial caching library for CodeIgniter. It allows you to write and get chunks 4 | of data to and from the filesystem. By storing complex or large chunks of data in serialized form 5 | on the file system you can relieve stress from the database or simply cache Twitter calls. 6 | 7 | ## Requirements 8 | 9 | 1. PHP 5.2.x 10 | 2. CodeIgniter 2.0.x to 2.1.0 11 | 12 | ## Usage 13 | 14 | ```php 15 | // Uncached model call 16 | $this->blog_m->getPosts($category_id, 'live'); 17 | 18 | // cached model call 19 | $this->cache->model('blog_m', 'getPosts', array($category_id, 'live'), 120); // keep for 2 minutes 20 | 21 | // cached library call 22 | $this->cache->library('some_library', 'calcualte_something', array($foo, $bar, $bla)); // keep for default time (0 = unlimited) 23 | 24 | // cached array or object 25 | $this->cache->write($data, 'cached-name'); 26 | $data = $this->cache->get('cached-name'); 27 | 28 | // Delete cache 29 | $this->cache->delete('cached-name'); 30 | 31 | // Delete all cache 32 | $this->cache->delete_all(); 33 | 34 | // Delete cache group 35 | $this->cache->write($data, 'nav_header'); 36 | $this->cache->write($data, 'nav_footer'); 37 | $this->cache->delete_group('nav_'); 38 | 39 | // Delete cache item 40 | // Call like a normal library or model but give a negative $expire 41 | $this->cache->model('blog_m', 'getPosts', array($category_id, 'live'), -1); // delete this specific cache file 42 | ``` 43 | 44 | ## Installation 45 | 46 | Permission your cache folder to be writeable by the web server. 47 | -------------------------------------------------------------------------------- /config/autoload.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libraries/Cache.php: -------------------------------------------------------------------------------- 1 | _ci =& get_instance(); 34 | $this->_reset(); 35 | 36 | $this->_ci->load->config('cache'); 37 | 38 | $this->_path = $this->_ci->config->item('cache_dir'); 39 | $this->_default_expires = $this->_ci->config->item('cache_default_expires'); 40 | if ( ! is_dir($this->_path)) 41 | { 42 | show_error("Cache Path not found: $this->_path"); 43 | } 44 | } 45 | 46 | /** 47 | * Initialize Cache object to empty 48 | * 49 | * @access private 50 | * @return void 51 | */ 52 | private function _reset() 53 | { 54 | $this->_contents = NULL; 55 | $this->_filename = NULL; 56 | $this->_expires = NULL; 57 | $this->_created = NULL; 58 | $this->_dependencies = array(); 59 | } 60 | 61 | /** 62 | * Call a library's cached result or create new cache 63 | * 64 | * @access public 65 | * @param string 66 | * @return array 67 | */ 68 | public function library($library, $method, $arguments = array(), $expires = NULL) 69 | { 70 | if ( ! class_exists(ucfirst($library))) 71 | { 72 | $this->_ci->load->library($library); 73 | } 74 | 75 | return $this->_call($library, $method, $arguments, $expires); 76 | } 77 | 78 | /** 79 | * Call a model's cached result or create new cache 80 | * 81 | * @access public 82 | * @return array 83 | */ 84 | public function model($model, $method, $arguments = array(), $expires = NULL) 85 | { 86 | if ( ! class_exists(ucfirst($model))) 87 | { 88 | $this->_ci->load->model($model); 89 | } 90 | 91 | return $this->_call($model, $method, $arguments, $expires); 92 | } 93 | 94 | // Depreciated, use model() or library() 95 | private function _call($property, $method, $arguments = array(), $expires = NULL) 96 | { 97 | $this->_ci->load->helper('security'); 98 | 99 | if ( ! is_array($arguments)) 100 | { 101 | $arguments = (array) $arguments; 102 | } 103 | 104 | // Clean given arguments to a 0-index array 105 | $arguments = array_values($arguments); 106 | 107 | $cache_file = $property.DIRECTORY_SEPARATOR.do_hash($method.serialize($arguments), 'sha1'); 108 | 109 | // See if we have this cached or delete if $expires is negative 110 | if($expires >= 0) 111 | { 112 | $cached_response = $this->get($cache_file); 113 | } 114 | else 115 | { 116 | $this->delete($cache_file); 117 | return; 118 | } 119 | 120 | // Not FALSE? Return it 121 | if($cached_response !== FALSE && $cached_response !== NULL) 122 | { 123 | return $cached_response; 124 | } 125 | 126 | else 127 | { 128 | // Call the model or library with the method provided and the same arguments 129 | $new_response = call_user_func_array(array($this->_ci->$property, $method), $arguments); 130 | $this->write($new_response, $cache_file, $expires); 131 | 132 | return $new_response; 133 | } 134 | } 135 | 136 | /** 137 | * Helper functions for the dependencies property 138 | */ 139 | function set_dependencies($dependencies) 140 | { 141 | if (is_array($dependencies)) 142 | { 143 | $this->_dependencies = $dependencies; 144 | } 145 | else 146 | { 147 | $this->_dependencies = array($dependencies); 148 | } 149 | 150 | return $this; 151 | } 152 | 153 | function add_dependencies($dependencies) 154 | { 155 | if (is_array($dependencies)) 156 | { 157 | $this->_dependencies = array_merge($this->_dependencies, $dependencies); 158 | } 159 | else 160 | { 161 | $this->_dependencies[] = $dependencies; 162 | } 163 | 164 | return $this; 165 | } 166 | 167 | function get_dependencies() { return $this->_dependencies; } 168 | 169 | /** 170 | * Helper function to get the cache creation date 171 | */ 172 | function get_created($created) { return $this->_created; } 173 | 174 | 175 | /** 176 | * Retrieve Cache File 177 | * 178 | * @access public 179 | * @param string 180 | * @param boolean 181 | * @return mixed 182 | */ 183 | function get($filename = NULL, $use_expires = true) 184 | { 185 | // Check if cache was requested with the function or uses this object 186 | if ($filename !== NULL) 187 | { 188 | $this->_reset(); 189 | $this->_filename = $filename; 190 | } 191 | 192 | // Check directory permissions 193 | if ( ! is_dir($this->_path) OR ! is_really_writable($this->_path)) 194 | { 195 | return FALSE; 196 | } 197 | 198 | // Build the file path. 199 | $filepath = $this->_path.$this->_filename.'.cache'; 200 | 201 | // Check if the cache exists, if not return FALSE 202 | if ( ! @file_exists($filepath)) 203 | { 204 | return FALSE; 205 | } 206 | 207 | // Check if the cache can be opened, if not return FALSE 208 | if ( ! $fp = @fopen($filepath, FOPEN_READ)) 209 | { 210 | return FALSE; 211 | } 212 | 213 | // Lock the cache 214 | flock($fp, LOCK_SH); 215 | 216 | // If the file contains data return it, otherwise return NULL 217 | if (filesize($filepath) > 0) 218 | { 219 | $this->_contents = unserialize(fread($fp, filesize($filepath))); 220 | } 221 | else 222 | { 223 | $this->_contents = NULL; 224 | } 225 | 226 | // Unlock the cache and close the file 227 | flock($fp, LOCK_UN); 228 | fclose($fp); 229 | 230 | // Check cache expiration, delete and return FALSE when expired 231 | if ($use_expires && ! empty($this->_contents['__cache_expires']) && $this->_contents['__cache_expires'] < time()) 232 | { 233 | $this->delete($filename); 234 | return FALSE; 235 | } 236 | 237 | // Check Cache dependencies 238 | if(isset($this->_contents['__cache_dependencies'])) 239 | { 240 | foreach ($this->_contents['__cache_dependencies'] as $dep) 241 | { 242 | $cache_created = filemtime($this->_path.$this->_filename.'.cache'); 243 | 244 | // If dependency doesn't exist or is newer than this cache, delete and return FALSE 245 | if (! file_exists($this->_path.$dep.'.cache') or filemtime($this->_path.$dep.'.cache') > $cache_created) 246 | { 247 | $this->delete($filename); 248 | return FALSE; 249 | } 250 | } 251 | } 252 | 253 | // Instantiate the object variables 254 | $this->_expires = isset($this->_contents['__cache_expires']) ? $this->_contents['__cache_expires'] : NULL; 255 | $this->_dependencies = isset($this->_contents['__cache_dependencies']) ? $this->_contents['__cache_dependencies'] : NULL; 256 | $this->_created = isset($this->_contents['__cache_created']) ? $this->_contents['__cache_created'] : NULL; 257 | 258 | // Cleanup the meta variables from the contents 259 | $this->_contents = @$this->_contents['__cache_contents']; 260 | 261 | // Return the cache 262 | log_message('debug', "Cache retrieved: ".$filename); 263 | return $this->_contents; 264 | } 265 | 266 | /** 267 | * Write Cache File 268 | * 269 | * @access public 270 | * @param mixed 271 | * @param string 272 | * @param int 273 | * @param array 274 | * @return void 275 | */ 276 | function write($contents = NULL, $filename = NULL, $expires = NULL, $dependencies = array()) 277 | { 278 | // Check if cache was passed with the function or uses this object 279 | if ($contents !== NULL) 280 | { 281 | $this->_reset(); 282 | $this->_contents = $contents; 283 | $this->_filename = $filename; 284 | $this->_expires = $expires; 285 | $this->_dependencies = $dependencies; 286 | } 287 | 288 | // Put the contents in an array so additional meta variables 289 | // can be easily removed from the output 290 | $this->_contents = array('__cache_contents' => $this->_contents); 291 | 292 | // Check directory permissions 293 | if ( ! is_dir($this->_path) OR ! is_really_writable($this->_path)) 294 | { 295 | return; 296 | } 297 | 298 | // check if filename contains dirs 299 | $subdirs = explode(DIRECTORY_SEPARATOR, $this->_filename); 300 | if (count($subdirs) > 1) 301 | { 302 | array_pop($subdirs); 303 | $test_path = $this->_path.implode(DIRECTORY_SEPARATOR, $subdirs); 304 | 305 | // check if specified subdir exists 306 | if ( ! @file_exists($test_path)) 307 | { 308 | // create non existing dirs, asumes PHP5 309 | if ( ! @mkdir($test_path, DIR_WRITE_MODE, TRUE)) return FALSE; 310 | } 311 | } 312 | 313 | // Set the path to the cachefile which is to be created 314 | $cache_path = $this->_path.$this->_filename.'.cache'; 315 | 316 | // Open the file and log if an error occures 317 | if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE)) 318 | { 319 | log_message('error', "Unable to write Cache file: ".$cache_path); 320 | return; 321 | } 322 | 323 | // Meta variables 324 | $this->_contents['__cache_created'] = time(); 325 | $this->_contents['__cache_dependencies'] = $this->_dependencies; 326 | 327 | // Add expires variable if its set... 328 | if (! empty($this->_expires)) 329 | { 330 | $this->_contents['__cache_expires'] = $this->_expires + time(); 331 | } 332 | // ...or add default expiration if its set 333 | elseif (! empty($this->_default_expires) ) 334 | { 335 | $this->_contents['__cache_expires'] = $this->_default_expires + time(); 336 | } 337 | 338 | // Lock the file before writing or log an error if it failes 339 | if (flock($fp, LOCK_EX)) 340 | { 341 | fwrite($fp, serialize($this->_contents)); 342 | flock($fp, LOCK_UN); 343 | } 344 | else 345 | { 346 | log_message('error', "Cache was unable to secure a file lock for file at: ".$cache_path); 347 | return; 348 | } 349 | fclose($fp); 350 | @chmod($cache_path, DIR_WRITE_MODE); 351 | 352 | // Log success 353 | log_message('debug', "Cache file written: ".$cache_path); 354 | 355 | // Reset values 356 | $this->_reset(); 357 | } 358 | 359 | /** 360 | * Delete Cache File 361 | * 362 | * @access public 363 | * @param string 364 | * @return void 365 | */ 366 | function delete($filename = NULL) 367 | { 368 | if ($filename !== NULL) $this->_filename = $filename; 369 | 370 | $file_path = $this->_path.$this->_filename.'.cache'; 371 | 372 | if (file_exists($file_path)) unlink($file_path); 373 | 374 | // Reset values 375 | $this->_reset(); 376 | } 377 | 378 | /** 379 | * Delete a group of cached files 380 | * 381 | * Allows you to pass a group to delete cache. Example: 382 | * 383 | * 384 | * $this->cache->write($data, 'nav_title'); 385 | * $this->cache->write($links, 'nav_links'); 386 | * $this->cache->delete_group('nav_'); 387 | * 388 | * 389 | * @param string $group 390 | * @return void 391 | */ 392 | public function delete_group($group = null) 393 | { 394 | if ($group === null) 395 | { 396 | return FALSE; 397 | } 398 | 399 | $this->_ci->load->helper('directory'); 400 | $map = directory_map($this->_path, TRUE); 401 | 402 | foreach ($map AS $file) 403 | { 404 | if (strpos($file, $group) !== FALSE) 405 | { 406 | unlink($this->_path.$file); 407 | } 408 | } 409 | 410 | // Reset values 411 | $this->_reset(); 412 | } 413 | 414 | /** 415 | * Delete Full Cache or Cache subdir 416 | * 417 | * @access public 418 | * @param string 419 | * @return void 420 | */ 421 | function delete_all($dirname = '') 422 | { 423 | if (empty($this->_path)) 424 | { 425 | return FALSE; 426 | } 427 | 428 | $this->_ci->load->helper('file'); 429 | if (file_exists($this->_path.$dirname)) delete_files($this->_path.$dirname, TRUE); 430 | 431 | // Reset values 432 | $this->_reset(); 433 | } 434 | } 435 | 436 | /* End of file Cache.php */ 437 | /* Location: ./application/libraries/Cache.php */ -------------------------------------------------------------------------------- /spark.info: -------------------------------------------------------------------------------- 1 | name: cache 2 | version: 2.0.0 3 | compatibility: 2.1.0 --------------------------------------------------------------------------------