chagenbu Thu Mar 1 08:32:30 2001 EDT Added files: /php4/pear Cache.php /php4/pear/Cache Container.php /php4/pear/Cache/Container file.php phplib.php shm.php Removed files: /php4/pear/Cache Cache.php /php4/pear/Cache/Container cache_container.php cache_container_file.php cache_container_phplib.php cache_container_shm.php Log: use standard naming/capitalization, and do a bit of error checking when instantiating the storage classfile.
Index: php4/pear/Cache.php +++ php4/pear/Cache.php <?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | [EMAIL PROTECTED] so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Ulf Wendel <[EMAIL PROTECTED]> | // | Sebastian Bergmann <[EMAIL PROTECTED]> | // +----------------------------------------------------------------------+ // // $Id: Cache.php,v 1.1 2001/03/01 16:32:28 chagenbu Exp $ /** * Cache is a base class for cache implementations. * * TODO: Simple usage example goes here. * * @author Ulf Wendel <[EMAIL PROTECTED]> * @version $Id: Cache.php,v 1.1 2001/03/01 16:32:28 chagenbu Exp $ * @package Cache * @access public */ class Cache { /** * Disables the caching. * * TODO: Add explanation what this is good for. * * @var boolean * @access public */ var $no_cache = false; /** * Garbage collection: probability in seconds * * If set to a value above 0 a garbage collection will * flush all cache entries older than the specified number * of seconds. * * @var integer * @see $gc_probability * @access public */ var $gc_time = 1; /** * Garbage collection: probability in percent * * TODO: Add an explanation. * * @var integer 0 => never * @see $gc_time * @access public */ var $gc_probability = 1; /** * Storage container object. * * @var object Cache_Container */ var $container; // // public methods // /** * * @param string Name of storage container class * @param array Array with storage class dependend config options * @see setOptions() */ function Cache($storage_driver, $storage_options = "") { $storage_driver = strtolower($storage_driver); $storage_class = 'Cache_Container_' . $storage_driver; $storage_classfile = 'Cache/Container/' . $storage_driver . '.php'; if (@include_once $storage_classfile) { $this->container = new $storage_class($storage_options); $this->garbageCollection(); } else { return null; } } /** * Returns the requested dataset it if exists and is not expired * * @param string dataset ID * @return mixed cached data or NULL on failure * @access public */ function get($id) { if ($this->no_cache) return ""; if ($this->isCached($id) && !$this->isExpired($id)) return $this->load($id); return NULL; } // end func get /** * Stores the given data in the cache. * * @param string dataset ID used as cache identifier * @param mixed data to cache * @param integer lifetime of the cached data in seconds - 0 for endless * @return boolean * @access public */ function save($id, $data, $expires = 0) { if ($this->no_cache) return true; return $this->container->save($id, $data, $expires); } // end func save /** * Loads the given ID from the cache. * * @param string dataset ID * @return mixed cached data or NULL on failure * @access public */ function load($id) { if ($this->no_cache) return ""; return $this->container->load($id); } // end func load /** * Removes the specified dataset from the cache. * * @param string dataset ID * @return boolean * @access public */ function delete($id) { if ($this->no_cache) return true; return $this->container->delete($id); } // end func delete /** * Flushes the cache - removes all data from it * * @return integer number of removed datasets */ function flush() { if ($this->no_cache) return true; return $this->container->flush(); } // end func flush /** * Checks if a dataset exists. * * Note: this does not say that the cached data is not expired! * * @param string dataset ID * @return boolean * @access public */ function isCached($id) { if ($this->no_cache) return false; return $this->container->isCached($id); } // end func isCached /** * Checks if a dataset is expired * * @param string dataset ID * @param integer maximum age for the cached data in seconds - 0 for endless * If the cached data is older but the given lifetime it will * be removed from the cache. You don't have to provide this * argument if you call isExpired(). Every dataset knows * it's expire date and will be removed automatically. Use * this only if you know what you're doing... * @return boolean * @access public */ function isExpired($id, $max_age = 0) { if ($this->no_cache) return true; return $this->container->isExpired($id, $max_age); } // end func isExpired /** * Generates a "unique" ID for the given value * * This is a quick but dirty hack to get a "unique" ID for a any kind of variable. * ID clashes might occur from time to time although they are extreme unlikely! * * @param mixed variable to generate a ID for * @return string "unique" ID * @access public */ function generateID($variable) { // WARNING: ID clashes are possible although unlikely return md5(serialize($variable)); } /** * Calls the garbage collector of the storage object with a certain probability * * @param boolean Force a garbage collection run? * @see $gc_probability, $gc_time, setOptions() */ function garbageCollection($force = false) { static $last_run = 0; if ($this->no_cache) return; srand((double) microtime() * 1000000); // time and probability based if (($force) || ($last_run && $last_run < time() + $this->gc_time) || (rand(1, 100) < $this->gc_probability)) { $this->container->garbageCollection(); $last_run = time(); } } // end func garbageCollection } // end class cache ?> Index: php4/pear/Cache/Container.php +++ php4/pear/Cache/Container.php <?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | [EMAIL PROTECTED] so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Ulf Wendel <[EMAIL PROTECTED]> | // | Sebastian Bergmann <[EMAIL PROTECTED]> | // +----------------------------------------------------------------------+ // // $Id: Container.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ /** * Common base class of all cache storage container. * * To speed up things we do a preload you should know about, otherwise it might * play you a trick. The Cache controller classes (Cache/Cache, Cache/Output, ...) * usually do something like is (isCached($id) && !isExpired($id)) return $container->load($id). * if you implement isCached(), isExpired() and load() straight ahead, each of this * functions will result in a storage medium (db, file,...) access. This generates too much load. * Now, a simple speculative preload should saves time in most cases. Whenever * one of the mentioned methods is invoked we preload the cached dataset into class variables. * That means that we have only one storage medium access for the sequence * (isCached($id) && !isExpired($id)) return $container->load($id). * The bad thing is that the preloaded data might be outdated meanwhile, which is * unlikely but for you power users, be warned. If you do not want the preload * you should switch it off by setting the class variable $preload to false. Anyway, this is * not recommended! * * @author Ulf Wendel <[EMAIL PROTECTED]> * @version $Id: Container.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ * @package Cache * @access public * @abstract */ class Cache_Container { /** * Flag indicating wheter to preload datasets. * * See the class description for more details. * * @var boolean */ var $preload = true; /** * ID of a preloaded dataset * * @var string */ var $id = ""; /** * Expiration timestamp of a preloaded dataset. * * @var integer 0 means never, endless */ var $expires = 0; /** * Value of a preloaded dataset. * * @var string */ var $data = ""; /** * Flag indicating that the dataset requested for preloading is unknown. * * @var boolean */ var $unknown = true; /** * Encoding mode for cache data: base64 or addslashes() (slash). * * @var string base64 or slash */ var $encoding_mode = "base64"; /** * Loads a dataset from the cache. * * @param string dataset ID * @return mixed dataset value or NULL on failure * @access public */ function load($id) { if ($this->preload) { if ($this->id != $id) $this->preload($id); return $this->data; } else { list( , $data) = $this->fetch($id); return $data; } } // end func load /** * Checks if a dataset is expired. * * @param string dataset ID * @param integer maximum age in seconds of the data set * @return boolean * @access public */ function isExpired($id, $max_age = 0) { if ($this->preload) { if ($this->id != $id) $this->preload($id); if ($this->unknown) return false; } else { // check if at all it is cached if (!$this->isCached($id)) return false; // I'm lazy... list($this->expires, ) = $this->fetch($id); } // endless if (0 == $this->expires) return false; // you feel fine, Ulf? if ($expired = ($this->expires <= time() || ($max_age && $this->expires <= time() + $max_age)) ) { $this->delete($id); // remove preloaded values $this->id = ""; $this->data = ""; $this->expires = 0; $this->unknown = true; } return $expired; } // end func isExpired /** * Checks if a dataset is cached. * * @param string dataset ID * @return boolean */ function isCached($id) { if ($this->preload) { if ($this->id != $id) $this->preload($id); return !($this->unknown); } else { return $this->idExists($id); } } // end func isCached // // abstract methods // /** * Fetches a dataset from the storage medium. * * @param string dataset ID * @return array format: [expire date, cached data] * @throws CacheError * @abstract */ function fetch($id) { return array(NULL, NULL); } // end func fetch /** * Stores a dataset. * * @param string dataset ID * @param mixed data to store * @param mixed userdefined expire date * @return boolean * @throws CacheError * @access public * @abstract */ function save($id, $data, $expire = 0) { return NULL; } // end func save /** * Deletes a dataset. * * @param string dataset ID * @return boolean * @access public * @abstract */ function delete($id) { return NULL; } // end func delete /** * Flushes the cache - removes all caches datasets from the cache * * @return integer Number of removed datasets, -1 on failure * @throws CacheError * @access public * @abstract */ function flush() { return NULL; } // end func flush /** * Checks if a dataset exists * * @param string dataset ID * @return boolean * @access public * @abstract */ function idExists($id) { return NULL; } // end func idExists /** * Starts the garbage collection. * * @access public * @abstract */ function garbageCollection() { } // end func garbageCollection /** * Does a speculative preload of a dataset * * @param string dataset ID * @return boolean */ function preload($id) { // whatever happens, remember the preloaded ID $this->id = $id; list($this->expires, $this->data) = $this->fetch($id); if (NULL === $this->data) { // Uuups, unknown ID // clear the internal preload values $this->data = ""; $this->expires = -1; $this->unknown = true; return false; } $this->unknown = false; return true; } // end func preload /** * Imports the requested datafields as object variables if allowed * * @param array List of fields to be imported as object variables * @param array List of allowed datafields */ function setOptions($requested, $allowed) { foreach ($allowed as $k => $field) if (isset($requested[$field])) $this->$field = $requested[$field]; } // end func setOptions /** * Encodes the data for the storage container * * @var mixed data to encode */ function encode($data) { if ("base64" == $this->encoding_mode) return base64_encode(serialize($data)); else return addslashes(serialize($data)); } // end func encode /** * Decodes the data from the storage container. * * @var mixed */ function decode($data) { if ("base64" == $this->encoding_mode) return unserialize(base64_decode($data)); else return unserialize(stripslashes($data)); } // end func decode } ?> Index: php4/pear/Cache/Container/file.php +++ php4/pear/Cache/Container/file.php <?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | [EMAIL PROTECTED] so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Ulf Wendel <[EMAIL PROTECTED]> | // | Sebastian Bergmann <[EMAIL PROTECTED]> | // +----------------------------------------------------------------------+ // // $Id: file.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ require_once 'Cache/Container.php'; /** * Stores cache contents in a file. * * @author Ulf Wendel <[EMAIL PROTECTED]> * @version $Id: file.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ */ class Cache_Container_file extends Cache_Container { /** * Directory where to put the cache files. * * @var string Make sure to add a trailing slash */ var $cache_dir = ""; /** * Filename prefix for cache files. * * You can use the filename prefix to implement a "domain" based cache or just * to give the files a more descriptive name. The word "domain" is borroed from * a user authentification system. One user id (cached dataset with the ID x) * may exists in different domains (different filename prefix). You might want * to use this to have different cache values for a production, development and * quality assurance system. If you want the production cache not to be influenced * by the quality assurance activities, use different filename prefixes for them. * * I personally don't think that you'll never need this, but 640kb happend to be * not enough, so... you know what I mean. If you find a useful application of the * feature please update this inline doc. * * @var string */ var $filename_prefix = ""; /** * Creates the cache directory if neccessary * * @param array Config options: ["cache_dir" => ..., "filename_prefix" => ...] */ function Cache_Container_file($options = "") { if (is_array($options)) $this->setOptions($options, array("cache_dir", "filename_prefix")); if (!file_exists($this->cache_dir) || !is_dir($this->cache_dir)) mkdir($this->cache_dir, 0755); } // end func contructor function fetch($id) { $file = $this->getFilename($id); if (!file_exists($file)) return array(NULL, NULL); // retrive the content if (!($fh = @fopen($file, "rb"))) return new CacheError("Can't access cache file '$file'. Check access rights and path.", __FILE__, __LINE__); // file format: // 1st line: expiration date // 2nd+ lines: cache data $expire = trim(fgets($fh, 11)); $data = $this->decode(fread($fh, filesize($file))); fclose($fh); return array($expire, $data); } // end func fetch function save($id, $data, $expire = 0) { $file = $this->getFilename($id); if (!($fh = @fopen($file, "wb"))) return new CacheError("Can't access '$file' to store cache data. Check access rights and path.", __FILE__, __LINE__); // file format: // 1st line: expiration date // 2nd+ lines: cache data fwrite($fh, $expire . "\r\n"); fwrite($fh, $this->encode($data)); fclose($fh); // I'm not sure if we need this touch($file); return true; } // end func save function delete($id) { $file = $this->getFilename($id); if (file_exists($file)) { unlink($file); clearstatcache(); return true; } return false; } // end func delete function flush() { if (!($dh = opendir($this->cache_dir))) return new CacheError("Can't access the cache directory '$this->cache_dir'. Check access rights and path", __FILE__, __LINE__); $num_removed = 0; while ($file = readdir($dh)) { if ("." == $file || ".." == $file) continue; unlink($this->cache_dir . $file); $num_removed++; } clearstatcache(); return $num_removed; } // end func flush function idExists($id) { return file_exists($this->cache_dir . $this->filename_prefix . $id); } // end func idExists /** * Deletes all expired files. * * Garbage collection for files is a rather "expensive", "long time" * operation. All files in the cache directory have to be examined which * means that they must be opened for reading, the expiration date has to be * read from them and if neccessary they have to be unlinked (removed). * If you have a user comment for a good default gc probability please add it to * to the inline docs. */ function garbageCollection() { if (!($dh = opendir($this->cache_dir))) return new CacheError("Can't access cache directory.", __FILE__, __LINE__); while ($file = readdir($dh)) { if ("." == $file || ".." == $file) continue; $file = $this->cache_dir . $file; // skip trouble makers but inform the user if (!($fh = @fopen($file, "rb"))) { new CacheError("Can't access cache file '$file' skipping for garbage collection. Check access rights and path.", __FILE__, __LINE__); continue; } $expire = time(fgets($fh, 11)); fclose($fh); // remove if expired if ($expire && $expire <= time()) unlink($file); } closedir($dh); // flush the disk state cache clearstatcache(); } // end func garbageCollection /** * Returns the filename for the specified id. * * @param string dataset ID * @return string full filename with the path * @access public */ function getFilename($id) { return $this->cache_dir . $this->filename_prefix . $id; } // end func getFilename } ?> Index: php4/pear/Cache/Container/phplib.php +++ php4/pear/Cache/Container/phplib.php <?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | [EMAIL PROTECTED] so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Ulf Wendel <[EMAIL PROTECTED]> | // | Sebastian Bergmann <[EMAIL PROTECTED]> | // +----------------------------------------------------------------------+ // // $Id: phplib.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ require_once 'Cache/Container.php'; /* CREATE TABLE cache ( id CHAR(32) NOT NULL DEFAULT '', data TEXT NOT NULL DEFAULT '', expires INT(9) NOT NULL DEFAULT 0, changed TIMESTAMP(14), INDEX (expires), PRIMARY KEY (id) ) */ /** * Stores cache data into a database table. * * @author Ulf Wendel <[EMAIL PROTECTED]>, Sebastian Bergmann <[EMAIL PROTECTED]> * @version $Id: phplib.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ * @package Cache */ class Cache_Container_phplib extends Cache_Container { /** * Name of the DB table to store caching data * * @see Cache_Container_file::$filename_prefix */ var $cache_table = "cache"; /** * PHPLib object * * @var object PEAR_DB */ var $db; /** * Name of the PHPLib DB class to use * * @var string * @see $db_path, $local_path */ var $db_class = ""; /** * Filename of your local.inc * * If empty, "local.inc" is assumed. * * @var string */ var $local_file = ""; /** * Include path for you local.inc * * HINT: If your're not using prepend.php you must * take care that all classes (files) references by you * local.inc are included automatically. So you might * want to write a new local2.inc that only referrs to * the database class (file) you're using and includes all required files! * * @var string path to your local.inc - make sure to add a trailing slash * @see $local_file */ var $local_path = ""; /** * * @param mixed */ function Cache_Container_phplib($options = "") { if (is_array($options)) $this->setOptions($options, array("db_class", "db_file", "db_path", "local_file", "local_path")); if (!$this->db_class) return new CacheError("No database class specified.", __FILE__, __LINE__); // include the required files include_once($this->local_path . $this->local_file); // create a db object $this->db = new $this->db_class; } // end constructor function fetch($id) { $query = sprintf("SELECT expires, data FROM %s WHERE id = '%s'", $this->cache_table, $id ); $this->db->query($query); if (!$this->db->Next_Record()) return array(NULL, NULL); return array($this->db->f("expires"), $this->decode($this->db->f("data"))); } // end func fetch function save($id, $data, $expires = 0) { $query = sprintf("REPLACE INTO %s (data, expires, id) VALUES ('%s', %d, '%s')", $this->cache_table, $this->encode($data), $expires, $id ); $this->db->query($query); return (boolean)$this->db->affected_rows(); } // end func save function delete($id) { $query = sprintf("DELETE FROM %s WHERE id = '%s'", $this->cache_table, $id ); $this->db->query($query); return (boolean)$this->db->affected_rows(); } // end func delete function flush() { $query = sprintf("DELETE FROM %s", $this->cache_table); $this->db->query($query); return $this->db->affected_rows(); } // end func flush function idExists($id) { $query = sprintf("SELECT id FROM %s WHERE ID = '%s'", $this->cache_table, $id ); } // end func isExists function garbageCollection() { $query = sprintf("DELETE FORM %s WHERE expires <= %d AND expires > 0", $this->cache_table, time() ); #$this->db->query($query); } // end func garbageCollection } ?> Index: php4/pear/Cache/Container/shm.php +++ php4/pear/Cache/Container/shm.php <?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | [EMAIL PROTECTED] so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Ulf Wendel <[EMAIL PROTECTED]> | // | Sebastian Bergmann <[EMAIL PROTECTED]> | // | Björn Schotte <[EMAIL PROTECTED]> | // +----------------------------------------------------------------------+ // // $Id: shm.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ require_once 'Cache/Container.php'; /** * Stores cache data into shared memory. * * @author Björn Schotte <[EMAIL PROTECTED]> * @version $Id: shm.php,v 1.1 2001/03/01 16:32:29 chagenbu Exp $ * @package Cache */ class Cache_Container_shm extends Cache_Container { function Cache_Container_shm($options = "") { } function fetch($id) { } // end func fetch function save($id, $data, $expires = 0) { } // end func save function delete($id) { } // end func delete function flush() { } // end func flush function idExists($id) { } // end func isExists function garbageCollection() { } // end func garbageCollection } ?>
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] To contact the list administrators, e-mail: [EMAIL PROTECTED]