2 // +----------------------------------------------------------------------+
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 1997-2003 The PHP Group |
6 // +----------------------------------------------------------------------+
7 // | This source file is subject to version 2.0 of the PHP license, |
8 // | that is bundled with this package in the file LICENSE, and is |
9 // | available at through the world-wide-web at |
10 // | http://www.php.net/license/2_02.txt. |
11 // | If you did not receive a copy of the PHP license and are unable to |
12 // | obtain it through the world-wide-web, please send a note to |
13 // | license@php.net so we can mail you a copy immediately. |
14 // +----------------------------------------------------------------------+
15 // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de> |
16 // | Sebastian Bergmann <sb@sebastian-bergmann.de> |
17 // +----------------------------------------------------------------------+
19 // $Id: Cache.php 267047 2008-10-07 08:58:46Z dufuz $
21 require_once 'PEAR.php';
22 require_once 'Cache/Error.php';
25 * Cache is a base class for cache implementations.
27 * The pear cache module is a generic data cache which can be used to
28 * cache script runs. The idea behind the cache is quite simple. If you have
29 * the same input parameters for whatever tasks/algorithm you use you'll
30 * usually get the same output. So why not caching templates, functions calls,
31 * graphic generation etc. Caching certain actions e.g. XSLT tranformations
32 * saves you lots of time.
34 * The design of the cache reminds of PHPLibs session implementation. A
35 * (PHPLib: session) controller uses storage container (PHPLib: ct_*.inc) to save
36 * certain data (PHPLib: session data). In contrast to the session stuff it's up to
37 * you to generate an ID for the data to cache. If you're using the output cache
38 * you might use the script name as a seed for cache::generateID(), if your using the
39 * function cache you'd use an array with all function parameters.
41 * Usage example of the generic data cache:
43 * require_once('Cache.php');
45 * $cache = new Cache('file', array('cache_dir' => 'cache/') );
46 * $id = $cache->generateID('testentry');
48 * if ($data = $cache->get($id)) {
49 * print "Cache hit.<br>Data: $data";
52 * $data = 'data of any kind';
53 * $cache->save($id, $data);
54 * print 'Cache miss.<br>';
57 * WARNING: No File/DB-Table-Row locking is implemented yet,
58 * it's possible, that you get corrupted data-entries under
59 * bad circumstances (especially with the file container)
61 * @author Ulf Wendel <ulf.wendel@phpdoc.de>
62 * @version $Id: Cache.php 267047 2008-10-07 08:58:46Z dufuz $
66 class Cache extends PEAR
70 * Enables / disables caching.
72 * TODO: Add explanation what this is good for.
80 * Garbage collection: probability in seconds
82 * If set to a value above 0 a garbage collection will
83 * flush all cache entries older than the specified number
87 * @see $gc_probability, $gc_maxlifetime
93 * Garbage collection: probability in percent
95 * TODO: Add an explanation.
97 * @var integer 0 => never
98 * @see $gc_time, $gc_maxlifetime
101 var $gc_probability = 1;
104 * Garbage collection: delete all entries not use for n seconds.
106 * Default is one day, 60 * 60 * 24 = 86400 seconds.
109 * @see $gc_probability, $gc_time
111 var $gc_maxlifetime = 86400;
114 * Storage container object.
116 * @var object Cache_Container
126 * @param string Name of container class
127 * @param array Array with container class options
129 function Cache($container, $container_options = '')
131 parent::__construct();
132 $container = strtolower($container);
133 $container_class = 'Cache_Container_' . $container;
134 $container_classfile = 'Cache/Container/' . $container . '.php';
136 include_once $container_classfile;
137 $this->container = new $container_class($container_options);
143 $this->garbageCollection();
147 * Returns the current caching state.
149 * @return boolean The current caching state.
152 function getCaching()
154 return $this->caching;
158 * Enables or disables caching.
160 * @param boolean The new caching state.
163 function setCaching($state)
165 $this->caching = $state;
169 * Returns the requested dataset it if exists and is not expired
171 * @param string dataset ID
172 * @param string cache group
173 * @return mixed cached data or null on failure
176 function get($id, $group = 'default')
178 if (!$this->caching) {
182 if ($this->isCached($id, $group) && !$this->isExpired($id, $group)) {
183 return $this->load($id, $group);
189 * Stores the given data in the cache.
191 * @param string dataset ID used as cache identifier
192 * @param mixed data to cache
193 * @param integer lifetime of the cached data in seconds - 0 for endless
194 * @param string cache group
198 function save($id, $data, $expires = 0, $group = 'default')
200 if (!$this->caching) {
203 return $this->extSave($id, $data, '',$expires, $group);
207 * Stores a dataset with additional userdefined data.
209 * @param string dataset ID
210 * @param mixed data to store
211 * @param string additional userdefined data
212 * @param mixed userdefined expire date
213 * @param string cache group
215 * @throws Cache_Error
219 function extSave($id, $cachedata, $userdata, $expires = 0, $group = 'default')
221 if (!$this->caching) {
224 return $this->container->save($id, $cachedata, $expires, $group, $userdata);
225 } // end func extSave
228 * Loads the given ID from the cache.
230 * @param string dataset ID
231 * @param string cache group
232 * @return mixed cached data or null on failure
235 function load($id, $group = 'default')
237 if (!$this->caching) {
240 return $this->container->load($id, $group);
244 * Returns the userdata field of a cached data set.
246 * @param string dataset ID
247 * @param string cache group
248 * @return string userdata
252 function getUserdata($id, $group = 'default')
254 if (!$this->caching) {
257 return $this->container->getUserdata($id, $group);
258 } // end func getUserdata
261 * Removes the specified dataset from the cache.
263 * @param string dataset ID
264 * @param string cache group
268 function remove($id, $group = 'default')
270 if (!$this->caching) {
273 return $this->container->remove($id, $group);
277 * Flushes the cache - removes all data from it
279 * @param string cache group, if empty all groups will be flashed
280 * @return integer number of removed datasets
282 function flush($group = 'default')
284 if (!$this->caching) {
287 return $this->container->flush($group);
291 * Checks if a dataset exists.
293 * Note: this does not say that the cached data is not expired!
295 * @param string dataset ID
296 * @param string cache group
300 function isCached($id, $group = 'default')
302 if (!$this->caching) {
305 return $this->container->isCached($id, $group);
306 } // end func isCached
309 * Checks if a dataset is expired
311 * @param string dataset ID
312 * @param string cache group
313 * @param integer maximum age for the cached data in seconds - 0 for endless
314 * If the cached data is older but the given lifetime it will
315 * be removed from the cache. You don't have to provide this
316 * argument if you call isExpired(). Every dataset knows
317 * it's expire date and will be removed automatically. Use
318 * this only if you know what you're doing...
322 function isExpired($id, $group = 'default', $max_age = 0)
324 if (!$this->caching) {
327 return $this->container->isExpired($id, $group, $max_age);
328 } // end func isExpired
331 * Generates a "unique" ID for the given value
333 * This is a quick but dirty hack to get a "unique" ID for a any kind of variable.
334 * ID clashes might occur from time to time although they are extreme unlikely!
336 * @param mixed variable to generate a ID for
337 * @return string "unique" ID
340 function generateID($variable)
342 // WARNING: ID clashes are possible although unlikely
343 return md5(serialize($variable));
347 * Calls the garbage collector of the storage object with a certain probability
349 * @param boolean Force a garbage collection run?
350 * @see $gc_probability, $gc_time
352 function garbageCollection($force = false)
354 static $last_run = 0;
356 if (!$this->caching) {
360 // time and probability based
361 if (($force) || ($last_run && $last_run < time() + $this->gc_time) || (rand(1, 100) < $this->gc_probability)) {
362 $this->container->garbageCollection($this->gc_maxlifetime);
365 } // end func garbageCollection