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]