pax_global_header00006660000000000000000000000064116613605200014512gustar00rootroot0000000000000052 comment=fedf79a617ead9f7c794684aa4576323119ecbd2 php-cache-1.5.6/000077500000000000000000000000001166136052000133535ustar00rootroot00000000000000php-cache-1.5.6/Cache-1.5.6/000077500000000000000000000000001166136052000150235ustar00rootroot00000000000000php-cache-1.5.6/Cache-1.5.6/Application.php000066400000000000000000000130511166136052000177770ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: Application.php 178289 2005-01-26 09:47:28Z dufuz $ require_once 'Cache.php'; // Application level variables // // Purpose // Variables that are persisent across all user sessions, // not just a specific user ala normal sessions. // // Usage: // // Example 1: // // $app =& new Cache_Application(); // $_APP =& $app->getData(); // // In this case the $_APP variable is akin to the $_SESSION variable. // If you add/remove stuff, it will be reflected in the next request // (of any user). // // Example 2: // // $foo = 'Some data'; // $bar = 'Some other data'; // // $app =& new Cache_Application(); // $app->register('foo'); // $app->register('bar', $bar); // // $foo = 'Different data'; // // In this case the variables are registered with the register() function. // This is akin to session_register(). // // As with session_register(), the contents of the variable at the *end* of the // request is registered and not at the point of registration. Therefore in this // example, for the $foo variable, the string 'Different data' is stored and not // 'Some data'. The exception to this rule is if you use the second argument to // register() as in the second call to it above. This will cause the data supplied // in the second argument to be stored and not the contents at the end of the request. // // Note: If you use this method with register_globals turned on, the variables will be // automatically globalled upon startup, (ie. when you create the object). // // Note: If you register a variable that is not set when the script finishes, it will // registered as null. // // // *** You are strongly recommended to use only one method of the two above. *** // // (In fact if you use the register() function with register_globals Off, you have to // use the $_APP method to get at the data). class Cache_Application extends Cache { var $data; var $id; var $group; var $registered_vars; /** * Constructor * * @param string Name of container class * @param array Array with container class options */ function Cache_Application($container = 'file', $container_options = array('cache_dir' => '/tmp/', 'filename_prefix' => 'cache_'), $id = 'application_var', $group = 'application_cache') { $this->id = $id; $this->group = $group; $this->registered_vars = array(); $this->Cache($container, $container_options); $this->data = $this->isCached($this->id, $this->group) ? unserialize($this->get($this->id, $this->group)) : array(); // If register_globals on, global all registered variables if (ini_get('register_globals') && is_array($this->data)) { foreach ($this->data as $key => $value) { global $$key; $$key = $value; } } } /** * Destructor * * Gets values of all registered variables and stores them. Then calls save() to * write data away. */ function _Cache_Application() { // Get contents of all registered variables if (is_array($this->registered_vars) && !empty($this->registered_vars)) { foreach ($this->registered_vars as $varname) { global $$varname; $this->data[$varname] = $$varname; } } // Save the data $this->save($this->id, serialize($this->data), 0, $this->group); } /** * register() * * Registers a variable to be stored. * * @param string Name of variable to register * @param mixed Optional data to store */ function register($varname, $data = null) { if (isset($data)) { $this->data[$varname] = $data; } else { $this->registered_vars[] = $varname; } } /** * unregister() * * Unregisters a variable from being stored. * * @param string Name of variable to unregister */ function unregister($varname) { if (isset($this->data[$varname])) { unset($this->data[$varname]); } } /** * clear() * * Removes all stored data */ function clear() { $this->data = array(); } /** * getData() * * Use this to get a reference to the data to manipulate * in calling script. Eg. $_APP =& $obj->getData(); * * @return mixed A reference to the data */ function &getData() { return $this->data; } } ?>php-cache-1.5.6/Cache-1.5.6/Cache.php000066400000000000000000000254341166136052000165470ustar00rootroot00000000000000 | // | Sebastian Bergmann | // +----------------------------------------------------------------------+ // // $Id: Cache.php 267047 2008-10-07 08:58:46Z dufuz $ require_once 'PEAR.php'; require_once 'Cache/Error.php'; /** * Cache is a base class for cache implementations. * * The pear cache module is a generic data cache which can be used to * cache script runs. The idea behind the cache is quite simple. If you have * the same input parameters for whatever tasks/algorithm you use you'll * usually get the same output. So why not caching templates, functions calls, * graphic generation etc. Caching certain actions e.g. XSLT tranformations * saves you lots of time. * * The design of the cache reminds of PHPLibs session implementation. A * (PHPLib: session) controller uses storage container (PHPLib: ct_*.inc) to save * certain data (PHPLib: session data). In contrast to the session stuff it's up to * you to generate an ID for the data to cache. If you're using the output cache * you might use the script name as a seed for cache::generateID(), if your using the * function cache you'd use an array with all function parameters. * * Usage example of the generic data cache: * * require_once('Cache.php'); * * $cache = new Cache('file', array('cache_dir' => 'cache/') ); * $id = $cache->generateID('testentry'); * * if ($data = $cache->get($id)) { * print "Cache hit.
Data: $data"; * * } else { * $data = 'data of any kind'; * $cache->save($id, $data); * print 'Cache miss.
'; * } * * WARNING: No File/DB-Table-Row locking is implemented yet, * it's possible, that you get corrupted data-entries under * bad circumstances (especially with the file container) * * @author Ulf Wendel * @version $Id: Cache.php 267047 2008-10-07 08:58:46Z dufuz $ * @package Cache * @access public */ class Cache extends PEAR { /** * Enables / disables caching. * * TODO: Add explanation what this is good for. * * @var boolean * @access private */ var $caching = true; /** * 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, $gc_maxlifetime * @access public */ var $gc_time = 1; /** * Garbage collection: probability in percent * * TODO: Add an explanation. * * @var integer 0 => never * @see $gc_time, $gc_maxlifetime * @access public */ var $gc_probability = 1; /** * Garbage collection: delete all entries not use for n seconds. * * Default is one day, 60 * 60 * 24 = 86400 seconds. * * @var integer * @see $gc_probability, $gc_time */ var $gc_maxlifetime = 86400; /** * Storage container object. * * @var object Cache_Container */ var $container; // // public methods // /** * * @param string Name of container class * @param array Array with container class options */ function Cache($container, $container_options = '') { $this->PEAR(); $container = strtolower($container); $container_class = 'Cache_Container_' . $container; $container_classfile = 'Cache/Container/' . $container . '.php'; include_once $container_classfile; $this->container = new $container_class($container_options); } //deconstructor function _Cache() { $this->garbageCollection(); } /** * Returns the current caching state. * * @return boolean The current caching state. * @access public */ function getCaching() { return $this->caching; } /** * Enables or disables caching. * * @param boolean The new caching state. * @access public */ function setCaching($state) { $this->caching = $state; } /** * Returns the requested dataset it if exists and is not expired * * @param string dataset ID * @param string cache group * @return mixed cached data or null on failure * @access public */ function get($id, $group = 'default') { if (!$this->caching) { return ''; } if ($this->isCached($id, $group) && !$this->isExpired($id, $group)) { return $this->load($id, $group); } 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 * @param string cache group * @return boolean * @access public */ function save($id, $data, $expires = 0, $group = 'default') { if (!$this->caching) { return true; } return $this->extSave($id, $data, '',$expires, $group); } // end func save /** * Stores a dataset with additional userdefined data. * * @param string dataset ID * @param mixed data to store * @param string additional userdefined data * @param mixed userdefined expire date * @param string cache group * @return boolean * @throws Cache_Error * @access public * @see getUserdata() */ function extSave($id, $cachedata, $userdata, $expires = 0, $group = 'default') { if (!$this->caching) { return true; } return $this->container->save($id, $cachedata, $expires, $group, $userdata); } // end func extSave /** * Loads the given ID from the cache. * * @param string dataset ID * @param string cache group * @return mixed cached data or null on failure * @access public */ function load($id, $group = 'default') { if (!$this->caching) { return ''; } return $this->container->load($id, $group); } // end func load /** * Returns the userdata field of a cached data set. * * @param string dataset ID * @param string cache group * @return string userdata * @access public * @see extSave() */ function getUserdata($id, $group = 'default') { if (!$this->caching) { return ''; } return $this->container->getUserdata($id, $group); } // end func getUserdata /** * Removes the specified dataset from the cache. * * @param string dataset ID * @param string cache group * @return boolean * @access public */ function remove($id, $group = 'default') { if (!$this->caching) { return true; } return $this->container->remove($id, $group); } // end func remove /** * Flushes the cache - removes all data from it * * @param string cache group, if empty all groups will be flashed * @return integer number of removed datasets */ function flush($group = 'default') { if (!$this->caching) { return true; } return $this->container->flush($group); } // end func flush /** * Checks if a dataset exists. * * Note: this does not say that the cached data is not expired! * * @param string dataset ID * @param string cache group * @return boolean * @access public */ function isCached($id, $group = 'default') { if (!$this->caching) { return false; } return $this->container->isCached($id, $group); } // end func isCached /** * Checks if a dataset is expired * * @param string dataset ID * @param string cache group * @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, $group = 'default', $max_age = 0) { if (!$this->caching) { return true; } return $this->container->isExpired($id, $group, $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 */ function garbageCollection($force = false) { static $last_run = 0; if (!$this->caching) { return; } // time and probability based if (($force) || ($last_run && $last_run < time() + $this->gc_time) || (rand(1, 100) < $this->gc_probability)) { $this->container->garbageCollection($this->gc_maxlifetime); $last_run = time(); } } // end func garbageCollection } // end class cache ?> php-cache-1.5.6/Cache-1.5.6/Container.php000066400000000000000000000334421166136052000174640ustar00rootroot00000000000000 | // | Sebastian Bergmann | // | Christian Stocker | // +----------------------------------------------------------------------+ // // $Id: Container.php 293863 2010-01-23 03:46:52Z clockwerx $ require_once 'Cache/Error.php'; /** * 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 * @version $Id: Container.php 293863 2010-01-23 03:46:52Z clockwerx $ * @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 = ''; /** * Cache group of a preloaded dataset * * @var string */ var $group = ''; /** * Expiration timestamp of a preloaded dataset. * * @var integer 0 means never, endless */ var $expires = 0; /** * Value of a preloaded dataset. * * @var string */ var $cachedata = ''; /** * Preloaded userdata field. * * @var string */ var $userdata = ''; /** * 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'; /** * Highwater mark - maximum space required by all cache entries. * * Whenever the garbage collection runs it checks the amount of space * required by all cache entries. If it's more than n (highwater) bytes * the garbage collection deletes as many entries as necessary to reach the * lowwater mark. * * @var int * @see lowwater */ var $highwater = 2048000; /** * Lowwater mark * * @var int * @see highwater */ var $lowwater = 1536000; /** * Options that can be set in every derived class using it's constructor. * * @var array */ var $allowed_options = array('encoding_mode', 'highwater', 'lowwater'); /** * Loads a dataset from the cache. * * @param string dataset ID * @param string cache group * @return mixed dataset value or null on failure * @access public */ function load($id, $group) { if ($this->preload) { if ($this->id != $id || $this->group != $group) { $this->preload($id, $group); } return $this->cachedata; } $ret = $this->fetch($id, $group); if (PEAR::isError($ret)) { return $ret; } list( , $data, ) = $ret; return $data; } // end func load /** * Returns the userdata field of a cached data set. * * @param string dataset ID * @param string cache group * @return string userdata * @access public */ function getUserdata($id, $group) { if ($this->preload) { if ($this->id != $id || $this->group != $group) { $this->preload($id, $group); } return $this->userdata; } $ret = $this->fetch($id, $group); if (PEAR::isError($ret)) { return $ret; } list( , , $userdata) = $ret; return $userdata; } // end func getUserdata /** * Checks if a dataset is expired. * * @param string dataset ID * @param string cache group * @param integer maximum age timestamp * @return boolean * @access public */ function isExpired($id, $group, $max_age) { if ($this->preload) { if ($this->id != $id || $this->group != $group) { $this->preload($id, $group); } if ($this->unknown) { return false; } } else { // check if at all it is cached if (!$this->isCached($id, $group)) { return false; } // I'm lazy... $ret = $this->fetch($id, $group); if (PEAR::isError($ret)) { return $ret; } list($this->expires, , ) = $ret; } // endless if (0 == $this->expires) { return false; } // you feel fine, Ulf? if ($expired = ($this->expires <= time() || ($max_age && ($this->expires <= $max_age))) ) { $this->remove($id, $group); $this->flushPreload(); } return $expired; } // end func isExpired /** * Checks if a dataset is cached. * * @param string dataset ID * @param string cache group * @return boolean */ function isCached($id, $group) { if ($this->preload) { if ($this->id != $id || $this->group != $group) { $this->preload($id, $group); } return !($this->unknown); } return $this->idExists($id, $group); } // end func isCached // // abstract methods // /** * Fetches a dataset from the storage medium. * * @param string dataset ID * @param string cache group * @return array format: [expire date, cached data, user data] * @throws Cache_Error * @abstract */ function fetch($id, $group) { return array(null, null, null); } // end func fetch /** * Stores a dataset. * * @param string dataset ID * @param mixed data to store * @param mixed userdefined expire date * @param string cache group * @param string additional userdefined data * @return boolean * @throws Cache_Error * @access public * @abstract */ function save($id, $data, $expire, $group, $userdata) { // QUESTION: Should we update the preload buffer instead? // Don't think so as the sequence save()/load() is unlikely. $this->flushPreload($id, $group); return null; } // end func save /** * Removes a dataset. * * @param string dataset ID * @param string cache group * @return boolean * @access public * @abstract */ function remove($id, $group) { $this->flushPreload($id, $group); return null; } // end func remove /** * Flushes the cache - removes all caches datasets from the cache. * * @param string If a cache group is given only the group will be flushed * @return integer Number of removed datasets, -1 on failure * @access public * @abstract */ function flush($group) { $this->flushPreload(); return null; } // end func flush /** * Checks if a dataset exists. * * @param string dataset ID * @param string cache group * @return boolean * @access public * @abstract */ function idExists($id, $group) { return null; } // end func idExists /** * Starts the garbage collection. * * @param int $gc_maxlifetime The maximum lifetime (seconds) for a cache * entry. Implemented by containers, * * @access public * @abstract */ function garbageCollection($gc_maxlifetime) { $this->flushPreload(); } // end func garbageCollection /** * Does a speculative preload of a dataset * * @param string dataset ID * @param string cache group * @return boolean */ function preload($id, $group) { // whatever happens, remember the preloaded ID $this->id = $id; $this->group = $group; $ret = $this->fetch($id, $group); if (PEAR::isError($ret)) { return $ret; } list($this->expires, $this->cachedata, $this->userdata) = $ret; if ($this->expires === null) { // Uuups, unknown ID $this->flushPreload(); return false; } $this->unknown = false; return true; } // end func preload /** * Flushes the internal preload buffer. * * save(), remove() and flush() must call this method * to preevent differences between the preloaded values and * the real cache contents. * * @param string dataset ID, if left out the preloaded values will be flushed. * If given the preloaded values will only be flushed if they are * equal to the given id and group * @param string cache group * @see preload() */ function flushPreload($id = '', $group = 'default') { if (!$id || ($this->id == $id && $this->group == $group)) { // clear the internal preload values $this->id = ''; $this->group = ''; $this->cachedata = ''; $this->userdata = ''; $this->expires = -1; $this->unknown = true; } } // end func flushPreload /** * 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 ($this->encoding_mode == 'base64') { return base64_encode(serialize($data)); } else { return serialize($data); } } // end func encode /** * Decodes the data from the storage container. * * @var mixed */ function decode($data) { if ($this->encoding_mode == 'base64') { return unserialize(base64_decode($data)); } else { return unserialize($data); } } // end func decode /** * Translates human readable/relative times in unixtime * * @param mixed can be in the following formats: * human readable : yyyymmddhhmm[ss]] eg: 20010308095100 * relative in seconds (1) : +xx eg: +10 * relative in seconds (2) : x < 946681200 eg: 10 * absolute unixtime : x < 2147483648 eg: 2147483648 * see comments in code for details * @return integer unix timestamp */ function getExpiresAbsolute($expires) { if (!$expires) { return 0; } //for api-compatibility, one has not to provide a "+", // if integer is < 946681200 (= Jan 01 2000 00:00:00) if ($expires[0] == '+' || $expires < 946681200) { return(time() + $expires); } elseif ($expires < 100000000000) { //if integer is < 100000000000 (= in 3140 years), // it must be an absolut unixtime // (since the "human readable" definition asks for a higher number) return $expires; } else { // else it's "human readable"; $year = substr($expires, 0, 4); $month = substr($expires, 4, 2); $day = substr($expires, 6, 2); $hour = substr($expires, 8, 2); $minute = substr($expires, 10, 2); $second = substr($expires, 12, 2); return mktime($hour, $minute, $second, $month, $day, $year); } } // end func getExpireAbsolute } // end class Container ?> php-cache-1.5.6/Cache-1.5.6/Container/000077500000000000000000000000001166136052000167455ustar00rootroot00000000000000php-cache-1.5.6/Cache-1.5.6/Container/db.php000066400000000000000000000224041166136052000200450ustar00rootroot00000000000000 | // | Sebastian Bergmann | // | Chuck Hagenbuch | // +----------------------------------------------------------------------+ // // $Id: db.php 178288 2005-01-26 09:42:30Z dufuz $ require_once 'DB.php'; require_once 'Cache/Container.php'; /** * PEAR/DB Cache Container. * * WARNING: Other systems might or might not support certain datatypes of * the tables shown. As far as I know there's no large binary * type in SQL-92 or SQL-99. Postgres seems to lack any * BLOB or TEXT type, for MS-SQL you could use IMAGE, don't know * about other databases. Please add sugestions for other databases to * the inline docs. * * The field 'changed' has no meaning for the Cache itself. It's just there * because it's a good idea to have an automatically updated timestamp * field for debugging in all of your tables. * * For _MySQL_ you need this DB table: * * CREATE TABLE cache ( * id CHAR(32) NOT null DEFAULT '', * cachegroup VARCHAR(127) NOT null DEFAULT '', * cachedata BLOB NOT null DEFAULT '', * userdata VARCHAR(255) NOT null DEFAULT '', * expires INT(9) NOT null DEFAULT 0, * * changed TIMESTAMP(14) NOT null, * * INDEX (expires), * PRIMARY KEY (id, cachegroup) * ) * * @author Sebastian Bergmann * @version $Id: db.php 178288 2005-01-26 09:42:30Z dufuz $ * @package Cache */ class Cache_Container_db extends Cache_Container { /** * Name of the DB table to store caching data * * @see Cache_Container_file::$filename_prefix */ var $cache_table = ''; /** * PEAR DB dsn to use. * * @var string */ var $dsn = ''; /** * PEAR DB object * * @var object PEAR_DB */ var $db; function Cache_Container_db($options) { if (!is_array($options) || !isset($options['dsn'])) { return new Cache_Error('No dsn specified!', __FILE__, __LINE__); } $this->setOptions($options, array_merge($this->allowed_options, array('dsn', 'cache_table'))); if (!$this->dsn) { return new Cache_Error('No dsn specified!', __FILE__, __LINE__); } $this->db = DB::connect($this->dsn, true); if (PEAR::isError($this->db)) { return new Cache_Error('DB::connect failed: ' . DB::errorMessage($this->db), __FILE__, __LINE__); } $this->db->setFetchMode(DB_FETCHMODE_ASSOC); } function fetch($id, $group) { $query = sprintf("SELECT cachedata, userdata, expires FROM %s WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } $row = $res->fetchRow(); if (is_array($row)) { $data = array($row['expires'], $this->decode($row['cachedata']), $row['userdata']); } else { $data = array(null, null, null); } // last used required by the garbage collection // WARNING: might be MySQL specific $query = sprintf("UPDATE %s SET changed = (NOW() + 0) WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } return $data; } /** * Stores a dataset. * * WARNING: we use the SQL command REPLACE INTO this might be * MySQL specific. As MySQL is very popular the method should * work fine for 95% of you. */ function save($id, $data, $expires, $group, $userdata) { $this->flushPreload($id, $group); $query = sprintf("REPLACE INTO %s (userdata, cachedata, expires, id, cachegroup) VALUES ('%s', '%s', %d, '%s', '%s')", $this->cache_table, addslashes($userdata), addslashes($this->encode($data)), $this->getExpiresAbsolute($expires) , addslashes($id), addslashes($group) ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res) , __FILE__, __LINE__); } } function remove($id, $group) { $this->flushPreload($id, $group); $query = sprintf("DELETE FROM %s WHERE id = '%s' and cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } } function flush($group = '') { $this->flushPreload(); if ($group) { $query = sprintf("DELETE FROM %s WHERE cachegroup = '%s'", $this->cache_table, addslashes($group)); } else { $query = sprintf("DELETE FROM %s", $this->cache_table); } $res = $this->db->query($query); if (PEAR::isError($res)) return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } function idExists($id, $group) { $query = sprintf("SELECT id FROM %s WHERE ID = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } $row = $res->fetchRow(); if (is_array($row)) { return true; } return false; } function garbageCollection($maxlifetime) { $this->flushPreload(); $query = sprintf('DELETE FROM %s WHERE (expires <= %d AND expires > 0) OR changed <= %d', $this->cache_table, time(), time() - $maxlifetime ); $res = $this->db->query($query); $query = sprintf('select sum(length(cachedata)) as CacheSize from %s', $this->cache_table ); $cachesize = $this->db->GetOne($query); if (PEAR::isError($cachesize)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($cachesize), __FILE__, __LINE__); } //if cache is to big. if ($cachesize > $this->highwater) { //find the lowwater mark. $query = sprintf('select length(cachedata) as size, changed from %s order by changed DESC', $this->cache_table ); $res = $this->db->query($query); if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } $numrows = $this->db->numRows($res); $keep_size = 0; while ($keep_size < $this->lowwater && $numrows--) { $entry = $res->fetchRow(DB_FETCHMODE_ASSOC); $keep_size += $entry['size']; } //delete all entries, which were changed before the "lowwwater mark" $query = sprintf('delete from %s where changed <= '.($entry['changed'] ? $entry['changed'] : 0), $this->cache_table ); $res = $this->db->query($query); } if (PEAR::isError($res)) { return new Cache_Error('DB::query failed: ' . DB::errorMessage($res), __FILE__, __LINE__); } } } ?> php-cache-1.5.6/Cache-1.5.6/Container/dbx.php000066400000000000000000000227021166136052000202360ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: dbx.php 268860 2008-11-12 14:56:26Z clockwerx $ require_once 'Cache/Container.php'; /** * ext/dbx Cache Container. * * WARNING: Other systems might or might not support certain datatypes of * the tables shown. As far as I know there's no large binary * type in SQL-92 or SQL-99. Postgres seems to lack any * BLOB or TEXT type, for MS-SQL you could use IMAGE, don't know * about other databases. Please add sugestions for other databases to * the inline docs. * * The field 'changed' has no meaning for the Cache itself. It's just there * because it's a good idea to have an automatically updated timestamp * field for debugging in all of your tables. * * For _MySQL_ you need this DB table: * * CREATE TABLE cache ( * id CHAR(32) NOT null DEFAULT '', * cachegroup VARCHAR(127) NOT null DEFAULT '', * cachedata BLOB NOT null DEFAULT '', * userdata VARCHAR(255) NOT null DEFAULT '', * expires INT(9) NOT null DEFAULT 0, * * changed TIMESTAMP(14) NOT null, * * INDEX (expires), * PRIMARY KEY (id, cachegroup) * ) * * @author Christian Stocker * @version $Id: dbx.php 268860 2008-11-12 14:56:26Z clockwerx $ * @package Cache */ class Cache_Container_dbx extends Cache_Container { /** * Name of the DB table to store caching data * * @see Cache_Container_file::$filename_prefix */ var $cache_table = ''; /** * DBx module to use * * at the moment only mysql or odbc * * @var string */ var $module = ''; /** * DB host to use * * @var string */ var $host = ''; /** * DB database to use * * @var string */ var $db = ''; /** * DB username to use * * @var string */ var $username = ''; /** * DB password to use * * @var string */ var $password = ''; /** * Establish a persistent connection? * * @var boolean */ var $persistent = true; function Cache_Container_dbx($options) { if (!is_array($options) ) { return new Cache_Error('No options specified!', __FILE__, __LINE__); } $this->setOptions($options, array_merge($this->allowed_options, array('module','host','db','username','password', 'cache_table', 'persistent'))); if (!$this->module) return new Cache_Error('No module specified!', __FILE__, __LINE__); $this->db = dbx_connect($this->module, $this->host, $this->db, $this->username, $this->password, $this->persistent); if (dbx_error($this->db)) { return new Cache_Error('DBx connect failed: ' . dbx_error($this->db), __FILE__, __LINE__); } else { //not implemented yet in dbx //$this->db->setFetchMode(DB_FETCHMODE_ASSOC); } } function fetch($id, $group) { $query = sprintf("SELECT cachedata, userdata, expires FROM %s WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } $row = $res->data[0]; if (is_array($row)) { $data = array($row['expires'], $this->decode($row['cachedata']), $row['userdata']); } else { $data = array(null, null, null); } // last used required by the garbage collection // WARNING: might be MySQL specific $query = sprintf("UPDATE %s SET changed = (NOW() + 0) WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } return $data; } /** * Stores a dataset. * * WARNING: we use the SQL command REPLACE INTO this might be * MySQL specific. As MySQL is very popular the method should * work fine for 95% of you. */ function save($id, $data, $expires, $group, $userdata) { $this->flushPreload($id, $group); $query = sprintf("REPLACE INTO %s (userdata, cachedata, expires, id, cachegroup) VALUES ('%s', '%s', %d, '%s', '%s')", $this->cache_table, addslashes($userdata), addslashes($this->encode($data)), $this->getExpiresAbsolute($expires) , addslashes($id), addslashes($group) ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db) , __FILE__, __LINE__); } } function remove($id, $group) { $this->flushPreload($id, $group); $query = sprintf("DELETE FROM %s WHERE id = '%s' and cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } } function flush($group = '') { $this->flushPreload(); if ($group) { $query = sprintf("DELETE FROM %s WHERE cachegroup = '%s'", $this->cache_table, addslashes($group)); } else { $query = sprintf("DELETE FROM %s", $this->cache_table); } $res = dbx_query($this->db,$query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } } function idExists($id, $group) { $query = sprintf("SELECT id FROM %s WHERE ID = '%s' AND cachegroup = '%s'", $this->cache_table, addslashes($id), addslashes($group) ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } $row = $res[0]; if (is_array($row)) { return true; } return false; } function garbageCollection($maxlifetime) { $this->flushPreload(); $query = sprintf('DELETE FROM %s WHERE (expires <= %d AND expires > 0) OR changed <= (NOW() - %d)', $this->cache_table, time(), $maxlifetime ); $res = dbx_query($this->db, $query); if (dbx_error($this->db)) { return new Cache_Error('DBx query failed: ' . dbx_error($this->db), __FILE__, __LINE__); } $query = sprintf('select sum(length(cachedata)) as CacheSize from %s', $this->cache_table ); $res = dbx_query($this->db, $query); //if cache is to big. if ($res->data[0][CacheSize] > $this->highwater) { //find the lowwater mark. $query = sprintf('select length(cachedata) as size, changed from %s order by changed DESC', $this->cache_table ); $res = dbx_query($this->db, $query); $keep_size = 0; $i = 0; while ($keep_size < $this->lowwater && $i < $res->rows ) { $keep_size += $res->data[$i][size]; $i++; } //delete all entries, which were changed before the "lowwwater mark" $query = sprintf('delete from %s where changed <= %s', $this->cache_table, $res->data[$i][changed] ); $res = dbx_query($this->db, $query); } } } ?> php-cache-1.5.6/Cache-1.5.6/Container/file.php000066400000000000000000000326701166136052000204050ustar00rootroot00000000000000 | // | Sebastian Bergmann | // +----------------------------------------------------------------------+ // // $Id: file.php 293864 2010-01-23 03:49:21Z clockwerx $ require_once 'Cache/Container.php'; /** * Stores cache contents in a file. * * @author Ulf Wendel * @version $Id: file.php 293864 2010-01-23 03:49:21Z clockwerx $ */ class Cache_Container_file extends Cache_Container { /** * File locking * * With file container, it's possible, that you get corrupted * data-entries under bad circumstances. The file locking must * improve this problem but it's experimental stuff. So the * default value is false. But it seems to give good results * * @var boolean */ var $fileLocking = false; /** * 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 = ''; /** * List of cache entries, used within a gc run * * @var array */ var $entries; /** * Total number of bytes required by all cache entries, used within a gc run. * * @var int */ var $total_size = 0; /** * Max Line Length of userdata * * If set to 0, it will take the default * ( 1024 in php 4.2, unlimited in php 4.3) * see http://ch.php.net/manual/en/function.fgets.php * for details * * @var int */ var $max_userdata_linelength = 257; /** * 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_merge($this->allowed_options, array('cache_dir', 'filename_prefix', 'max_userdata_linelength'))); } clearstatcache(); if ($this->cache_dir) { // make relative paths absolute for use in deconstructor. // it looks like the deconstructor has problems with relative paths if (OS_UNIX && '/' != $this->cache_dir{0} ) $this->cache_dir = realpath( getcwd() . '/' . $this->cache_dir) . '/'; // check if a trailing slash is in cache_dir if ($this->cache_dir{strlen($this->cache_dir)-1} != DIRECTORY_SEPARATOR) $this->cache_dir .= '/'; if (!file_exists($this->cache_dir) || !is_dir($this->cache_dir)) mkdir($this->cache_dir, 0755); } $this->entries = array(); $this->group_dirs = array(); } // end func contructor function fetch($id, $group) { $file = $this->getFilename($id, $group); if (PEAR::isError($file)) { return $file; } if (!file_exists($file)) { return array(null, null, null); } // retrive the content if (!($fh = @fopen($file, 'rb'))) { return new Cache_Error("Can't access cache file '$file'. Check access rights and path.", __FILE__, __LINE__); } // File locking (shared lock) if ($this->fileLocking) { flock($fh, LOCK_SH); } // file format: // 1st line: expiration date // 2nd line: user data // 3rd+ lines: cache data $expire = trim(fgets($fh, 12)); if ($this->max_userdata_linelength == 0 ) { $userdata = trim(fgets($fh)); } else { $userdata = trim(fgets($fh, $this->max_userdata_linelength)); } $buffer = ''; while (!feof($fh)) { $buffer .= fread($fh, 8192); } $cachedata = $this->decode($buffer); // Unlocking if ($this->fileLocking) { flock($fh, LOCK_UN); } fclose($fh); // last usage date used by the gc - maxlifetime // touch without second param produced stupid entries... touch($file,time()); clearstatcache(); return array($expire, $cachedata, $userdata); } // end func fetch /** * Stores a dataset. * * WARNING: If you supply userdata it must not contain any linebreaks, * otherwise it will break the filestructure. */ function save($id, $cachedata, $expires, $group, $userdata) { $this->flushPreload($id, $group); $file = $this->getFilename($id, $group); if (!($fh = @fopen($file, 'wb'))) { return new Cache_Error("Can't access '$file' to store cache data. Check access rights and path.", __FILE__, __LINE__); } // File locking (exclusive lock) if ($this->fileLocking) { flock($fh, LOCK_EX); } // file format: // 1st line: expiration date // 2nd line: user data // 3rd+ lines: cache data $expires = $this->getExpiresAbsolute($expires); fwrite($fh, $expires . "\n"); fwrite($fh, $userdata . "\n"); fwrite($fh, $this->encode($cachedata)); // File unlocking if ($this->fileLocking) { flock($fh, LOCK_UN); } fclose($fh); // I'm not sure if we need this // i don't think we need this (chregu) // touch($file); return true; } // end func save function remove($id, $group) { $this->flushPreload($id, $group); $file = $this->getFilename($id, $group); if (PEAR::isError($file)) { return $file; } if (file_exists($file)) { $ok = unlink($file); clearstatcache(); return $ok; } return false; } // end func remove function flush($group) { $this->flushPreload(); $dir = ($group) ? $this->cache_dir . $group . '/' : $this->cache_dir; $num_removed = $this->deleteDir($dir); unset($this->group_dirs[$group]); clearstatcache(); return $num_removed; } // end func flush function idExists($id, $group) { return file_exists($this->getFilename($id, $group)); } // 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. * * @param integer Maximum lifetime in seconds of an no longer used/touched entry * @throws Cache_Error */ function garbageCollection($maxlifetime) { $this->flushPreload(); clearstatcache(); $ok = $this->doGarbageCollection($maxlifetime, $this->cache_dir); // check the space used by the cache entries if ($this->total_size > $this->highwater) { krsort($this->entries); reset($this->entries); while ($this->total_size > $this->lowwater && list($lastmod, $entry) = each($this->entries)) { if (@unlink($entry['file'])) { $this->total_size -= $entry['size']; } else { new CacheError("Can't delete {$entry['file']}. Check the permissions."); } } } $this->entries = array(); $this->total_size = 0; return $ok; } // end func garbageCollection /** * Does the recursive gc procedure, protected. * * @param integer Maximum lifetime in seconds of an no longer used/touched entry * @param string directory to examine - don't sets this parameter, it's used for a * recursive function call! * @throws Cache_Error */ function doGarbageCollection($maxlifetime, $dir) { if (!is_writable($dir) || !is_readable($dir) || !($dh = opendir($dir))) { return new Cache_Error("Can't remove directory '$dir'. Check permissions and path.", __FILE__, __LINE__); } while ($file = readdir($dh)) { if ('.' == $file || '..' == $file) continue; $file = $dir . $file; if (is_dir($file)) { $this->doGarbageCollection($maxlifetime,$file . '/'); continue; } // skip trouble makers but inform the user if (!($fh = @fopen($file, 'rb'))) { new Cache_Error("Can't access cache file '$file', skipping it. Check permissions and path.", __FILE__, __LINE__); continue; } $expire = fgets($fh, 11); fclose($fh); $lastused = filemtime($file); $this->entries[$lastused] = array('file' => $file, 'size' => filesize($file)); $this->total_size += filesize($file); // remove if expired if (( ($expire && $expire <= time()) || ($lastused <= (time() - $maxlifetime)) ) && !unlink($file)) { new Cache_Error("Can't unlink cache file '$file', skipping. Check permissions and path.", __FILE__, __LINE__); } } closedir($dh); // flush the disk state cache clearstatcache(); } // end func doGarbageCollection /** * Returns the filename for the specified id. * * @param string dataset ID * @param string cache group * @return string full filename with the path * @access public */ function getFilename($id, $group) { if (isset($this->group_dirs[$group])) { return $this->group_dirs[$group] . $this->filename_prefix . $id; } $dir = $this->cache_dir . $group . '/'; if (is_writeable($this->cache_dir)) { if (!file_exists($dir)) { mkdir($dir, 0755, true); clearstatcache(); } } else { return new Cache_Error("Can't make directory '$dir'. Check permissions and path.", __FILE__, __LINE__); } $this->group_dirs[$group] = $dir; return $dir . $this->filename_prefix . $id; } // end func getFilename /** * Deletes a directory and all files in it. * * @param string directory * @return integer number of removed files * @throws Cache_Error */ function deleteDir($dir) { if (!is_writable($dir) || !is_readable($dir) || !($dh = opendir($dir))) { return new Cache_Error("Can't remove directory '$dir'. Check permissions and path.", __FILE__, __LINE__); } $num_removed = 0; while (false !== $file = readdir($dh)) { if ('.' == $file || '..' == $file) continue; $file = $dir . $file; if (is_dir($file)) { $file .= '/'; $num = $this->deleteDir($file . '/'); if (is_int($num)) $num_removed += $num; } else { if (unlink($file)) $num_removed++; } } // according to php-manual the following is needed for windows installations. closedir($dh); unset( $dh); if ($dir != $this->cache_dir) { //delete the sub-dir entries itself also, but not the cache-dir. rmDir($dir); $num_removed++; } return $num_removed; } // end func deleteDir } // end class file ?> php-cache-1.5.6/Cache-1.5.6/Container/mdb.php000066400000000000000000000331721166136052000202260ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: mdb.php 174777 2004-12-15 09:09:33Z dufuz $ require_once 'MDB.php'; require_once 'Cache/Container.php'; /** * PEAR/MDB Cache Container. * * NB: The field 'changed' has no meaning for the Cache itself. It's just there * because it's a good idea to have an automatically updated timestamp * field for debugging in all of your tables. * * A XML MDB-compliant schema example for the table needed is provided. * Look at the file "mdb_cache_schema.xml" for that. * * ------------------------------------------ * A basic usage example: * ------------------------------------------ * * $dbinfo = array( * 'database' => 'dbname', * 'phptype' => 'mysql', * 'username' => 'root', * 'password' => '', * 'cache_table' => 'cache' * ); * * * $cache = new Cache('mdb', $dbinfo); * $id = $cache->generateID('testentry'); * * if ($data = $cache->get($id)) { * echo 'Cache hit.
Data: '.$data; * * } else { * $data = 'data of any kind'; * $cache->save($id, $data); * echo 'Cache miss.
'; * } * * ------------------------------------------ * * @author Lorenzo Alberton * @version $Id: mdb.php 174777 2004-12-15 09:09:33Z dufuz $ * @package Cache */ class Cache_Container_mdb extends Cache_Container { /** * Name of the MDB table to store caching data * * @see Cache_Container_file::$filename_prefix */ var $cache_table = ''; /** * PEAR MDB object * * @var object PEAR_MDB */ var $db; /** * Constructor * * @param mixed Array with connection info or dsn string */ function Cache_Container_mdb($options) { $this->db = &MDB::Connect($options); if (MDB::isError($this->db)) { return new Cache_Error('MDB::connect failed: ' . $this->db->getMessage(), __FILE__, __LINE__); } else { $this->db->setFetchMode(MDB_FETCHMODE_ASSOC); } $this->setOptions($options, array_merge($this->allowed_options, array('dsn', 'cache_table'))); } /** * Fetch in the db the data that matches input parameters * * @param string dataset ID * @param string cache group * @return mixed dataset value or null/Cache_Error on failure * @access public */ function fetch($id, $group) { $query = 'SELECT cachedata FROM ' . $this->cache_table .' WHERE id=' . $this->db->getTextValue($id) .' AND cachegroup=' . $this->db->getTextValue($group); if ($res = $this->db->query($query)) { if ($this->db->endOfResult($res)) { //no rows returned $data = array(null, null, null); } else { $clob = $this->db->fetchClob($res,0,'cachedata'); if (!MDB::isError($clob)) { $cached_data = ''; while(!$this->db->endOfLOB($clob)) { if (MDB::isError($error = $this->db->readLob($clob,$data,8000)<0)) { return new Cache_Error('MDB::query failed: ' . $error->getMessage(), __FILE__, __LINE__); } $cached_data .= $data; } unset($data); $this->db->destroyLob($clob); $this->db->freeResult($res); //finished fetching LOB, now fetch other fields... $query = 'SELECT userdata, expires FROM ' . $this->cache_table .' WHERE id=' . $this->db->getTextValue($id) .' AND cachegroup=' . $this->db->getTextValue($group); if ($res = $this->db->query($query)) { $row = $this->db->fetchInto($res); if (is_array($row)) { $data = array( $row['expires'], $this->decode($cached_data), $row['userdata'] ); } else { $data = array(null, null, null); } } else { $data = array(null, null, null); } } else { return new Cache_Error('MDB::query failed: ' . $clob->getMessage(), __FILE__, __LINE__); } } $this->db->freeResult($res); } else { //return new Cache_Error('MDB::query failed: ' // . $result->getMessage(), __FILE__, __LINE__); $data = array(null, null, null); } // last used required by the garbage collection $query = 'UPDATE ' . $this->cache_table .' SET changed=' . time() .' WHERE id=' . $this->db->getTextValue($id) .' AND cachegroup=' . $this->db->getTextValue($group); $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } return $data; } /** * Stores a dataset in the database * * If dataset_ID already exists, overwrite it with new data, * else insert data in a new record. * * @param string dataset ID * @param mixed data to be cached * @param integer expiration time * @param string cache group * @param string userdata * @access public */ function save($id, $data, $expires, $group, $userdata) { global $db; $this->flushPreload($id, $group); $fields = array( 'id' => array( 'Type' => 'text', 'Value' => $id, 'Key' => true ), 'userdata' => array( 'Type' => 'integer', 'Value' => $userdata, 'null' => ($userdata ? false : true) ), 'expires' => array( 'Type' => 'integer', 'Value' => $this->getExpiresAbsolute($expires) ), 'cachegroup' => array( 'Type' => 'text', 'Value' => $group ) ); $result = $this->db->replace($this->cache_table, $fields); if (MDB::isError($result)) { //Var_Dump::display($result); return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($result), __FILE__, __LINE__); } unset($fields); //end first part of query $query2 = 'UPDATE ' . $this->cache_table .' SET cachedata=?' .' WHERE id='. $this->db->getTextValue($id); if (($prepared_query = $this->db->prepareQuery($query2))) { $char_lob = array( 'Error' => '', 'Type' => 'data', 'Data' => $this->encode($data) ); if (!MDB::isError($clob = $this->db->createLob($char_lob))) { $this->db->setParamClob($prepared_query,1,$clob,'cachedata'); if(MDB::isError($error=$this->db->executeQuery($prepared_query))) { return new Cache_Error('MDB::query failed: ' . $error->getMessage() , __FILE__, __LINE__); } $this->db->destroyLob($clob); } else { // creation of the handler object failed return new Cache_Error('MDB::query failed: ' . $clob->getMessage() , __FILE__, __LINE__); } $this->db->freePreparedQuery($prepared_query); } else { //prepared query failed return new Cache_Error('MDB::query failed: ' . $prepared_query->getMessage() , __FILE__, __LINE__); } } /** * Removes a dataset from the database * * @param string dataset ID * @param string cache group */ function remove($id, $group) { $this->flushPreload($id, $group); $query = 'DELETE FROM ' . $this->cache_table .' WHERE id=' . $this->db->getTextValue($id) .' AND cachegroup=' . $this->db->getTextValue($group); $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } } /** * Remove all cached data for a certain group, or empty * the cache table if no group is specified. * * @param string cache group */ function flush($group = '') { $this->flushPreload(); if ($group) { $query = 'DELETE FROM ' . $this->cache_table .' WHERE cachegroup=' . $this->db->getTextValue($group); } else { $query = 'DELETE FROM ' . $this->cache_table; } $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } } /** * Check if a dataset ID/group exists. * * @param string dataset ID * @param string cache group * @return boolean */ function idExists($id, $group) { $query = 'SELECT id FROM ' . $this->cache_table .' WHERE id=' . $this->db->getTextValue($id) .' AND cachegroup=' . $this->db->getTextValue($group); echo $query; $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } $row = $this->db->fetchInto($res); if (is_array($row)) { return true; } return false; } /** * Garbage collector. * * @param int maxlifetime */ function garbageCollection($maxlifetime) { $this->flushPreload(); $query = 'DELETE FROM ' . $this->cache_table .' WHERE (expires <= ' . time() .' AND expires > 0) OR changed <= '. time() - $maxlifetime; $res = $this->db->query($query); $query = 'SELECT sum(length(cachedata)) as CacheSize FROM ' . $this->cache_table; $cachesize = $this->db->getOne($query); if (MDB::isError($cachesize)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($cachesize), __FILE__, __LINE__); } //if cache is to big. if ($cachesize > $this->highwater) { //find the lowwater mark. $query = 'SELECT length(cachedata) as size, changed FROM ' . $this->cache_table .' ORDER BY changed DESC'; $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } $numrows = $this->db->numRows($res); $keep_size = 0; while ($keep_size < $this->lowwater && $numrows--) { $entry = $this->db->fetchInto($res,MDB_FETCHMODE_ASSOC); $keep_size += $entry['size']; } //delete all entries, which were changed before the "lowwater mark" $query = 'DELETE FROM ' . $this->cache_table .' WHERE changed<='.($entry['changed'] ? $entry['changed'] : 0); $res = $this->db->query($query); if (MDB::isError($res)) { return new Cache_Error('MDB::query failed: ' . $this->db->errorMessage($res), __FILE__, __LINE__); } } } } ?>php-cache-1.5.6/Cache-1.5.6/Container/mdb_cache_schema.xml000066400000000000000000000025751166136052000227050ustar00rootroot00000000000000 dbname 1 cache ID text 32 1 cachegroup text 127 1 cachedata clob 1 userdata text 255 expires integer 0 1 changed integer 0 1 id_index 1 id cachegroup expires_index expires
php-cache-1.5.6/Cache-1.5.6/Container/msession.php000066400000000000000000000167321166136052000213270ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: msession.php 178289 2005-01-26 09:47:28Z dufuz $ require_once 'Cache/Container.php'; /** * Stores cache contents in msessions. * * WARNING: experimental, untested * * @author Ulf Wendel * @version $Id: msession.php 178289 2005-01-26 09:47:28Z dufuz $ */ class Cache_Container_msession extends Cache_Container { /** * Length of the Cache-Identifier * * Note that the PEAR-Cache prefixes the ID with an md5() value * of the cache-group. A good value for the id_length * depends on the maximum number of entries per cache group. * * @var int */ var $id_length = 32; /** * Use msession_uniq to create a unique SID. * * @var boolean */ var $uniq = true; /** * Establish a connection to a msession server? * * @var boolean */ var $connect = true; /** * msession host * * @var string */ var $host = null; /** * msession port * * @var string */ var $port = null; /** * mesession server connection * * @var resource msession */ var $ms = null; function Cache_Container_msession($options = '') { if (is_array($options)) { $this->setOptions($options, array_merge($this->allowed_options, array('id_length', 'uniq', 'host', 'port', 'connect'))); } if ($connect) { if ($this->host == null) { new Cache_Error('No host specified.', __FILE__, __LINE__); } if ($this->port == null) { new Cache_Error('No port specified.', __FILE__, __LINE__); } if (!($this->ms = msession_connect($this->host, $this->port))) { new Cache_Error('Can not connect to the sever using host "' . $this->host . '" on port "' . $this->port . '"', __FILE__, __LINE__); } } } // end func contructor function fetch($id, $group) { $id = strtoupper(md5($group)) . $id; $group = msession_get($id, '_pear_cache_data', null); if ($data == null) { return array(null, null, null); } return array($data['expires'], $data['cachedata'], $data['userdata']); } // end func fetch /** * Stores a dataset. * * WARNING: If you supply userdata it must not contain any linebreaks, * otherwise it will break the filestructure. */ function save($id, $cachedata, $expires, $group, $userdata) { $this->flushPreload($id, $group); $cachedata = $this->encode($cachedata); $expires_abs = $this->getExpiresAbsolute($expires); $size = 1 + strlen($cachedata) + strlen($expires_abs) + strlen($userdata) + strlen($group); $size += strlen($size); $data = array( 'cachedata' => $cachedata, 'expires' => $expires_abs, 'userdata' => $userdata ); $id = strtoupper(md5($group)) . $id; msession_lock($id); if (!msession_set($id, '_pear_cache', true)) { msession_unlock($id); return new Cache_Error("Can't write cache data.", __FILE__, __LINE__); } if (!msession_set($id, '_pear_cache_data', $data)) { msession_unlock($id); return new Cache_Error("Can't write cache data.", __FILE__, __LINE__); } if (!msession_set($id, '_pear_cache_group', $group)) { msession_unlock($id); return new Cache_Error("Can't write cache data.", __FILE__, __LINE__); } if (!msession_set($id, '_pear_cache_size', $size)) { msession_unlock($id); return new Cache_Error("Can't write cache data.", __FILE__, __LINE__); } // let msession do some GC as well // note that msession works different from the PEAR Cache. // msession deletes an entry if it has not been used for n-seconds. // PEAR Cache deletes after n-seconds. if ($expires != 0) { msession_timeout($id, $expires); } msession_unlock($id); return true; } // end func save function remove($id, $group) { $this->flushPreload($id, $group); return msession_destroy(strtoupper(md5($group)) . $id); } // end func remove function flush($group) { $this->flushPreload(); $sessions = msession_find('_pear_cache_group', $group); if (empty($sessions)) { return 0; } foreach ($sessions as $k => $id) messsion_destroy($id); return count($sessions); } // end func flush function idExists($id, $group) { return (msession_get(strtoupper(md5($group)) . $id, '_pear_cache_group', null) == null) ? false : true; } // end func idExists /** * Deletes all expired files. * * Note: garbage collection should cause lot's of network traffic. * * @param integer Maximum lifetime in seconds of an no longer used/touched entry * @throws Cache_Error */ function garbageCollection($maxlifetime) { $this->flushPreload(); $sessions = msession_find('_pear_cache', true); if (empty($sessions)) return true; $total = 0; $entries = array(); foreach ($sessions as $k => $id) { $data = msession_get($id, '_pear_cache_data', null); if (null == $data) { continue; } if ($data['expires'] <= time()) { msession_destroy($id); continue; } $size = msession_get($id, '_pear_cache_size', null); $total += $size; $entries[$data['expires']] = array($id, $size); } if ($total > $this->highwater) { krsort($entries); reset($entries); while ($total > $this->lowwater && list($expires, $entry) = each($entries)) { msession_destroy($entry[0]); $total -= $entry[1]; } } return true; } // end func garbageCollection } // end class file ?>php-cache-1.5.6/Cache-1.5.6/Container/phplib.php000066400000000000000000000225551166136052000207450ustar00rootroot00000000000000 | // | Sebastian Bergmann | // +----------------------------------------------------------------------+ // // $Id: phplib.php 174777 2004-12-15 09:09:33Z dufuz $ require_once 'Cache/Container.php'; /** * Stores cache data into a database table using PHPLibs DB abstraction. * * WARNING: Other systems might or might not support certain datatypes of * the tables shown. As far as I know there's no large binary * type in SQL-92 or SQL-99. Postgres seems to lack any * BLOB or TEXT type, for MS-SQL you could use IMAGE, don't know * about other databases. Please add sugestions for other databases to * the inline docs. * * The field 'changed' is used by the garbage collection. Depending on * your databasesystem you might have to subclass fetch() and garbageCollection(). * * For _MySQL_ you need this DB table: * * CREATE TABLE cache ( * id CHAR(32) NOT null DEFAULT '', * cachegroup VARCHAR(127) NOT null DEFAULT '', * cachedata BLOB NOT null DEFAULT '', * userdata VARCHAR(255) NOT null DEFAUL '', * expires INT(9) NOT null DEFAULT 0, * * changed TIMESTAMP(14) NOT null, * * INDEX (expires), * PRIMARY KEY (id, cachegroup) * ) * * * @author Ulf Wendel , Sebastian Bergmann * @version $Id: phplib.php 174777 2004-12-15 09:09:33Z dufuz $ * @package Cache * @see save() */ 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 PHPLib's 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 = ''; /** * Creates an instance of a phplib db class to use it for storage. * * @param mixed If empty the object tries to used the * preconfigured class variables. If given it * must be an array with: * db_class => name of the DB class to use * optional: * db_file => filename of the DB class * db_path => path to the DB class * local_file => kind of local.inc * local_patk => path to the local.inc * see $local_path for some hints.s * @see $local_path */ function Cache_Container_phplib($options = '') { if (is_array($options)) { $this->setOptions($options, array_merge($this->allowed_options, array('db_class', 'db_file', 'db_path', 'local_file', 'local_path'))); } if (!$this->db_class) { return new Cache_Error('No database class specified.', __FILE__, __LINE__); } // include the required files if ($this->db_file) { include_once $this->db_path . $this->db_file; } if ($this->local_file) { include_once $this->local_path . $this->local_file; } // create a db object $this->db = new $this->db_class; } // end constructor function fetch($id, $group) { $query = sprintf("SELECT expires, cachedata, userdata FROM %s WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, $id, $group ); $this->db->query($query); if (!$this->db->Next_Record()) { return array(null, null, null); } // last used required by the garbage collection // WARNING: might be MySQL specific $query = sprintf("UPDATE %s SET changed = (NOW() + 0) WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, $id, $group ); $this->db->query($query); return array($this->db->f('expires'), $this->decode($this->db->f('cachedata')), $this->db->f('userdata')); } // end func fetch /** * Stores a dataset. * * WARNING: we use the SQL command REPLACE INTO this might be * MySQL specific. As MySQL is very popular the method should * work fine for 95% of you. */ function save($id, $data, $expires, $group) { $this->flushPreload($id, $group); $query = sprintf("REPLACE INTO %s (cachedata, expires, id, cachegroup) VALUES ('%s', %d, '%s', '%s')", $this->cache_table, addslashes($this->encode($data)), $this->getExpiresAbsolute($expires) , $id, $group ); $this->db->query($query); return (boolean)$this->db->affected_rows(); } // end func save function remove($id, $group) { $this->flushPreload($id, $group); $this->db->query( sprintf("DELETE FROM %s WHERE id = '%s' AND cachegroup = '%s'", $this->cache_table, $id, $group ) ); return (boolean)$this->db->affected_rows(); } // end func remove function flush($group) { $this->flushPreload(); if ($group) { $this->db->query(sprintf("DELETE FROM %s WHERE cachegroup = '%s'", $this->cache_table, $group)); } else { $this->db->query(sprintf("DELETE FROM %s", $this->cache_table)); } return $this->db->affected_rows(); } // end func flush function idExists($id, $group) { $this->db->query( sprintf("SELECT id FROM %s WHERE ID = '%s' AND cachegroup = '%s'", $this->cache_table, $id, $group ) ); return (boolean)$this->db->nf(); } // end func isExists function garbageCollection($maxlifetime) { $this->flushPreload(); $this->db->query( sprintf("DELETE FROM %s WHERE (expires <= %d AND expires > 0) OR changed <= (NOW() - %d)", $this->cache_table, time(), $maxlifetime ) ); //check for total size of cache $query = sprintf('select sum(length(cachedata)) as CacheSize from %s', $this->cache_table ); $this->db->query($query); $this->db->Next_Record(); $cachesize = $this->db->f('CacheSize'); //if cache is to big. if ($cachesize > $this->highwater) { //find the lowwater mark. $query = sprintf('select length(cachedata) as size, changed from %s order by changed DESC', $this->cache_table ); $this->db->query($query); $keep_size=0; while ($keep_size < $this->lowwater && $this->db->Next_Record()) { $keep_size += $this->db->f('size'); } //delete all entries, which were changed before the "lowwwater mark" $query = sprintf('delete from %s where changed <= '.$this->db->f('changed'), $this->cache_table ); $this->db->query($query); } } // end func garbageCollection } ?>php-cache-1.5.6/Cache-1.5.6/Container/shm.php000066400000000000000000000212701166136052000202470ustar00rootroot00000000000000 | // | Sebastian Bergmann | // +----------------------------------------------------------------------+ // // $Id: shm.php 186977 2005-05-25 10:00:41Z dufuz $ require_once 'Cache/Container.php'; /** * Stores cache data into shared memory. * * Well, this is not a very efficient implementation. Indeed it's much * slower than the file container as far as my tests showed. Files are * cached by most operating systems and it will be hard to write a faster * caching algorithm using PHP. * * @author Ulf Wendel * @version $Id: shm.php 186977 2005-05-25 10:00:41Z dufuz $ * @package Cache */ class Cache_Container_shm extends Cache_Container { /** * Key of the semaphore used to sync the SHM access * * @var int */ var $sem_key = null; /** * Permissions of the semaphore used to sync the SHM access * * @var int */ var $sem_perm = 0644; /** * Semaphore handler * * @var resource */ var $sem_id = null; /** * Key of the shared memory block used to store cache data * * @var int */ var $shm_key = null; /** * Size of the shared memory block used * * Note: the container does only use _one_ shm block no more! * * @var int */ var $shm_size = 131072; /** * Permissions of the shared memory block * * @var int */ var $shm_perm = 0644; /** * Shared memory handler * * @var resource */ var $shm_id = null; /** * Hash of cache entries * * Used by the garbage collection to find old entries. * * @var array */ var $entries = array(); /** * Number of bytes consumed by the cache * * @var int */ var $total_size = 0; /** * Creates a shared memory container * * @param array shm_key, sem_key, shm_size, sem_perm, shm_perm */ function Cache_Container_shm($options = '') { if (is_array($options)) { $this->setOptions($options, array_merge($this->allowed_options, array('shm_key', 'sem_key', 'shm_size', 'sem_perm', 'shm_perm' ) ) ); } // Cache::Container high- and lowwater defaults should be overridden if // not already done by the user if (!isset($options['highwater'])) { $this->highwater = round(0.75 * 131072); } if (!isset($options['lowwater'])) { $this->lowwater = round(0.5 * 131072); } if (!isset($options['shm_size'])) { $this->shm_size = 131072; } //get SHM and Semaphore handles if (!($this->shm_id = shmop_open($this->shm_key, 'c', $this->shm_perm, $this->shm_size))) { new Cache_Error("Can't open SHM segment '{$this->shm_key}', size '{$this->shm_size}'.", __FILE__, __LINE__ ); } if (!($this->sem_id = sem_get($this->sem_key, 1, $this->sem_perm))) { new Cache_Error("Can't get semaphore '{$this->sem_key}' using perms '{$this->sem_perm}'.", __FILE__, __LINE__ ); } } // end constructor function fetch($id, $group) { sem_acquire($this->sem_id); $cachedata = shmop_read($this->shm_id, 0, $this->shm_size); sem_release($this->sem_id); $cachedata = $this->decode($cachedata); if (!isset($cachedata[$group][$id])) { return array(null, null, null); } else { $cachedata = $cachedata[$group][$id]; } return array($cachedata['expire'], $cachedata['cachedata'], $cachedata['userdata'] ); } // end func fetch function save($id, $data, $expire, $group, $userdata) { $this->flushPreload($id, $group); sem_acquire($this->sem_id); $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size)); $cachedata[$group][$id] = array('expire' => $this->getExpiresAbsolute($expire), 'cachedata' => $data, 'userdata' => $userdata, 'changed' => time() ); if (strlen($newdata = $this->encode($cachedata)) > $this->shm_size) { $cachedata = $this->garbageCollection(time(), $cachedata); } shmop_write($this->shm_id, $newdata, 0); sem_release($this->sem_id); return true; } // end func save function remove($id, $group) { $this->flushPreload($id, $group); sem_acquire($this->sem_id); $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size)); unset($cachedata[$group][$id]); shmop_write($this->shm_id, $this->encode($cachedata), 0); sem_release($this->sem_id); } // end func remove function flush($group = '') { $this->flushPreload(); sem_acquire($this->sem_id); shmop_write($this->shm_id, $this->encode(array()), 0); sem_release($this->sem_id); } // end func flush function idExists($id, $group) { sem_acquire($this->sem_id); $cachedata = shm_read($this->shm_id, 0, $this->shm_size); sem_release($this->sem_id); $cachedata = $this->decode($cachedata); return isset($cachedata[$group][$id]); } // end func isExists function garbageCollection($maxlifetime, $cachedata = array()) { if ($lock = empty($cachedata)) { sem_acquire($this->sem_id); $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size)); } $this->doGarbageCollection($maxlifetime, $cachedata); if ($this->total_size > $this->highwater) { krsort($this->entries); reset($this->entries); while ($this->total_size > $this->lowwater && list($size, $entries) = each($this->entries)) { reset($entries); while (list($k, $entry) = each($entries)) { unset($cachedata[$entry['group']][$entry['id']]); $this->total_size -= $size; } } } if ($lock) { sem_release($this->sem_id); } $this->entries = array(); $this->total_size = 0; return $cachedata; } // end func garbageCollection function doGarbageCollection($maxlifetime, &$cachedata) { $changed = time() - $maxlifetime; $removed = 0; reset($cachedata); while (list($group, $groupdata) = each($cachedata)) { reset($groupdata); while (list($id, $data) = each($groupdata)) { if ($data['expire'] < time() || $data['changed'] < $changed) { unset($cachedata[$group][$id]); } } // ugly but simple to implement :/ $size = strlen($this->encode($data)); $this->entries[$size][] = array( 'group' => $group, 'id' => $id ); $this->total_size += $size; } return $removed; } // end func doGarbageCollection } // end class Cache_Container_shm ?> php-cache-1.5.6/Cache-1.5.6/Container/trifile.php000066400000000000000000000115561166136052000211240ustar00rootroot00000000000000 | // | Sebastian Bergmann | // | Ian Eure | // +----------------------------------------------------------------------+ // // $Id: trifile.php 184642 2005-04-18 19:05:01Z dufuz $ require_once 'Cache/Container/file.php'; /** * Tri-file cache. * * This cache container stores files with no special encoding to reduce overhead. * Expiration & user data are stored in seperate files, prefixed with a '.' and * suffixed with '.exp' & '.dat' respectively. * * See http://atomized.org/PEAR/Cache_trifile.html for more information. * * @author Ian Eure * @version 1.0 */ class Cache_Container_trifile extends Cache_Container_file { /** * Fetch cached file. * * @param string $id Cache ID to fetch * @param string $group Group to fetch from * @return array 1-dimensional array in the format: expiration,data,userdata */ function fetch($id, $group) { $file = $this->getFilename($id, $group); if (PEAR::isError($file)) { return $file; } if (!file_exists($file)) { return array(null, null, null); } return array( file_get_contents($this->_getExpFile($file)), file_get_contents($file), file_get_contents($this->_getUDFile($file)) ); } /** * Get the file to store cache data in. * * @return string Cache data file name * @access private */ function _getFile($file) { $dir = dirname($file); $file = basename($file); return $dir.'/.'.$file; } /** * Get the file to store expiration data in. * * @return string Expiration data file name * @access private */ function _getExpFile($file) { return $this->_getFile($file).'.exp'; } /** * Get the file to store user data in. * * @return string User data file name * @access private */ function _getUDFile($file) { return $this->_getFile($file).'.dat'; } /** * Cache file * * @param string $id Cache ID * @param mixed $cachedata Data to cache * @param mixed $expires When the data expires * @param string $group Cache group to store data in * @param mixed $userdata Additional data to store * @return boolean true on success, false otherwise */ function save($id, $cachedata, $expires, $group, $userdata) { $this->flushPreload($id, $group); $file = $this->getFilename($id, $group); if (PEAR::isError($file)) { return $file; } if (PEAR::isError($res = $this->_saveData($file, $cachedata))) { return $res; } $expires = $this->getExpiresAbsolute($expires); if (PEAR::isError($res = $this->_saveData($this->_getExpFile($file), $expires))) { return $res; } if (PEAR::isError($res = $this->_saveData($this->_getUDFile($file), $userdata))) { return $res; } return true; } /** * Save data in a file * * @param string $file File to save data in * @param string $data Data to save * @return mixed true on success, Cache_Error otherwise */ function _saveData($file, $data) { // Save data if (!($fh = @fopen($file, 'wb'))) return new Cache_Error("Can't access '$file' to store cache data. Check access rights and path.", __FILE__, __LINE__); if ($this->fileLocking) { flock($fh, LOCK_EX); } fwrite($fh, $data); if ($this->fileLocking) { flock($fh, LOCK_UN); } fclose($fh); return true; } } ?>php-cache-1.5.6/Cache-1.5.6/Error.php000066400000000000000000000034541166136052000166330ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: Error.php 174777 2004-12-15 09:09:33Z dufuz $ require_once 'PEAR.php'; /** * Cache Error class * * @package Cache */ class Cache_Error extends PEAR_Error { /** * Prefix of all error messages. * * @var string */ var $error_message_prefix = 'Cache-Error: '; /** * Creates an cache error object. * * @param string error message * @param string file where the error occured * @param string linenumber where the error occured */ function Cache_Error($msg, $file = __FILE__, $line = __LINE__) { $this->PEAR_Error(sprintf("%s [%s on line %d].", $msg, $file, $line)); } // end func Cache_Error } // end class Cache_Error ?>php-cache-1.5.6/Cache-1.5.6/Function.php000066400000000000000000000110671166136052000173260ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: Function.php 174777 2004-12-15 09:09:33Z dufuz $ require_once 'Cache.php'; /** * Function_Cache * * Purpose: * * Caching the result and output of functions. * * Example: * * require_once 'Cache/Function.php'; * * class foo { * function bar($test) { * echo "foo::bar($test)
"; * } * } * * class bar { * function foobar($object) { * echo '$'.$object.'->foobar('.$object.')
'; * } * } * * $bar = new bar; * * function foobar() { * echo 'foobar()'; * } * * $cache = new Cache_Function(); * * $cache->call('foo::bar', 'test'); * $cache->call('bar->foobar', 'bar'); * $cache->call('foobar'); * * Note: * * You cannot cache every function. You should only cache * functions that only depend on their arguments and don't use * global or static variables, don't rely on database queries or * files, and so on. * * @author Sebastian Bergmann * @module Function_Cache * @modulegroup Function_Cache * @package Cache * @version $Revision: 174777 $ * @access public */ class Cache_Function extends Cache { var $expires; /** * Constructor * * @param string Name of container class * @param array Array with container class options * @param integer Number of seconds for which to cache */ function Cache_Function($container = 'file', $container_options = array('cache_dir' => '.', 'filename_prefix' => 'cache_' ), $expires = 3600 ) { $this->Cache($container, $container_options); $this->expires = $expires; } /** * PEAR-Deconstructor * Call deconstructor of parent */ function _Cache_Function() { $this->_Cache(); } /** * Calls a cacheable function or method. * * @return mixed $result * @access public */ function call() { // get arguments $arguments = func_get_args(); // generate cache id $id = md5(serialize($arguments)); // query cache $cached_object = $this->get($id, 'function_cache'); if ($cached_object != null) { // cache hit: return cached output and result $output = $cached_object[0]; $result = $cached_object[1]; } else { // cache miss: call function, store output and result in cache ob_start(); $target = array_shift($arguments); // classname::staticMethod if (strstr($target, '::')) { list($class, $method) = explode('::', $target); $result = call_user_func_array(array($class, $method), $arguments); } elseif (strstr($target, '->')) { // object->method list($object, $method) = explode('->', $target); global $$object; $result = call_user_func_array(array($$object, $method), $arguments); } else { // function $result = call_user_func_array($target, $arguments); } $output = ob_get_contents(); ob_end_clean(); $this->save($id, array($output, $result), $this->expires, 'function_cache'); } echo $output; return $result; } } ?> php-cache-1.5.6/Cache-1.5.6/Graphics.php000066400000000000000000000307451166136052000173050ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: Graphics.php 178289 2005-01-26 09:47:28Z dufuz $ require_once 'Cache.php'; /** * Graphics disk cache. * * The usual way to create images is to pass some arguments that describe the image * to a script that dynamically creates an image. For every image of a page * a new PHP interpreter gets started. This is a good way to kill your webserver. * * When dealing with dynamically generated images you should not call another script * to generate the images but generate the images by the script that produces the page * that contains the images. This is a major improvement but it's only half the way. * * There's no need to rerender an image on every request. A simple disk cache can reduce * the computation time dramatically. This is what the class graphics_cache is for. * * Usage: * * // create an instance of the graphics cache * $cache = new graphics_cache; * * $img = ImageCreate(...); * * // compute an ID for your image based on typical parameters * $id = m5d( $size, $colors, $label); * * // check if it's cached * if (!($link = $cache->getImageLink($id, 'gif'))) { * * // hmmm, it's not cached, create it * ... * // cacheImageLink() and cacheImage() make the ImageGIF() call! * // cacheImage() returns the value of ImageGIF() [etc.], cacheImageLink() returns a URL * $link = $cache->cacheImageLink($id, $img, 'gif'); * * } * * // Ok, let's build the ImageLink * $size = getImageSize($link[0]); * printf('', $link[1], $size[3]); * * // for cacheImage(): * // header('Content-type: image/gif'); print $cache->cacheImage($id, $img, 'gif'); * * * The class requires PHP 4.0.2+ [ImageType()]. Note that cacheImage() works with * the output buffer. Modify it if required! * * @author Ulf Wendel * @version $Id: Graphics.php 178289 2005-01-26 09:47:28Z dufuz $ * @package Cache */ class Cache_Graphics extends Cache { /** * Cache URL prefix. * * Make sure that the cache URL prefix points to the $cache_dir, otherwise * your links will be broken. Use setCacheURL to specify the cache_url and * setCacheDir() for the cache_dir. * * @var string * @see setCacheURL(), setCacheDir() */ var $cache_url = ''; /** * Directory where cached files get stored. * s * Make sure that the cache_dir is writable and offers enough space. Check * also if your cache_url points to the directory. Use setCacheDir() to set * the variable. * * @var string * @see setCacheDir(), setCacheURL() */ var $cache_dir = ''; /** * Nameprefix of cached files. * * Per default the prefix "graphics_" gets used. You might use this * for versioning or to ease (manual) clean ups. * * @var string */ var $cache_file_prefix = 'graphics_'; /** * Cache container group. * * @var string */ var $cache_group = 'graphics'; /** * Mapping from supported image type to a ImageType() constant. * * Referr to the PHP manual for more informations on ImageType() * * @var array * @link http://www.php.net/ImageType */ var $imagetypes = array( 'gif' => IMG_GIF, 'jpg' => IMG_JPG, 'png' => IMG_PNG, 'wbmp' => IMG_WBMP ); /** * Instantiates a cache file container. * */ function Cache_Graphics() { $this->Cache('file', array('cache_dir' => $this->cache_dir, 'filename_prefix' => $this->cache_file_prefix)); } // end constructor /** * Returns the content of a cached image file. * * This function can be used to send the image directly to the browser. * Make sure that you send a correspondending header before sending the image itself. * * Always try to get the image from the cache before you compute it. See * the class docs for an example. * * @param string Image-ID * @param string Image type: gif, jpg, png, wbmp * @return string Image file contents if a cached file exists otherwise an empty string * @see cacheImage() */ function getImage($id, $format = 'png') { $id = $this->generateID($id, $format); return $this->get($id, $this->cache_group); } // end func getImage /** * Returns an array with a link to the cached image and the image file path. * * Always try to get the image from the cache before you compute it. See * the class docs for an example. * * @param string Image-ID * @param string Image type: gif, jpg, png, wbmp * @return array [ full path to the image file, image url ] * @throw Cache_Error * @see cacheImageLink() */ function getImageLink($id, $format = 'png') { $id = $this->generateID($id, $format); if (!$this->container->idExists($id, $this->cache_group)) { return array(); } $file = $this->cache_url . $this->cache_file_prefix . $id; return array($this->container->getFilename($id, $this->cache_group), $file); } // end func getImageLink /** * Create an image from the given image handler, cache it and return the file content. * * Always try to retrive the image from the cache before you compute it. * * Warning: this function uses the output buffer. If you expect collisions * modify the code. * * @param string Image-ID. Used as a part of the cache filename. * Use md5() to generate a "unique" ID for your image * based on characteristic values such as the color, size etc. * @param string Image handler to create the image from. * @param string Image type: gif, jpg, png, wbmp. Also used as filename suffix. * If an unsupported type is requested the functions tries to * fallback to a supported type before throwing an exeption. * @return string Image content returned by ImageGIF/... * @throws Cache_Error * @access public * @see getImage() */ function cacheImage($id, $img, $format = 'png') { if (!$id) { return new Cache_Error('You must provide an ID for and image to be cached!', __FILE__, __LINE__); } $id = $this->generateID($id, $format); $types = ImageTypes(); // Check if the requested image type is supported by the GD lib. // If not, try a callback to the first available image type. if (!isset($this->imagetypes[$format]) || !($types & $this->imagetypes[$format])) { foreach ($this->imagetypes as $supported => $bitmask) { if ($types & $bitmask) { new Cache_Error("The build in GD lib does not support the image type $format. Fallback to $supported.", __FILE__, __LINE__); } else { return new Cache_Error("Hmm, is your PHP build with GD support? Can't find any supported types.", __FILE__, __LINE__); } } } if ($image = $this->get($id, $this->cache_group)) { return $image; } // save the image to the output buffer, write it to disk and // return the image. ob_end_clean(); ob_start(); if (strtoupper($format) == 'JPG') { $genFormat = 'JPEG'; } else { $genFormat = strtoupper($format); } // generate the image $func = 'Image' . $genFormat; $func($img); ImageDestroy($img); ob_end(); $image = ob_get_contents(); ob_end_clean(); // save the generated image to disk $this->save($id, $image, 0, $this->cache_group); return $image; } // end func cacheImage /** * Create an image from the given image handler, cache it and return a url and the file path of the image. * * Always try to retrive the image from the cache before you compute it. * * @param string Image-ID. Used as a part of the cache filename. * Use md5() to generate a "unique" ID for your image * based on characteristic values such as the color, size etc. * @param string Image handler to create the image from. * @param string Image type: gif, jpg, png, wbmp. Also used as filename suffix. * If an unsupported type is requested the functions tries to * fallback to a supported type before throwing an exeption. * @return array [ full path to the image file, image url ] * @throws Cache_Error * @access public */ function cacheImageLink($id, &$img, $format = 'png') { if (!$id) { return new Cache_Error ('You must provide an ID for and image to be cached!', __FILE__, __LINE__); } $id = $this->generateID($id, $format); $types = ImageTypes(); // Check if the requested image type is supported by the GD lib. // If not, try a callback to the first available image type. if (!isset($this->imagetypes[$format]) || !($types & $this->imagetypes[$format])) { foreach ($this->imagetypes as $supported => $bitmask) if ($types & $bitmask) { new Cache_Error("The build in GD lib does not support the image type $format. Fallback to $supported.", __FILE__, __LINE__); } else { return new Cache_Error("Hmm, is your PHP build with GD support? Can't find any supported types.", __FILE__, __LINE__); } } $url = $this->cache_url . $this->cache_file_prefix . $id; $ffile = $this->container->getFilename($id, $this->cache_group); if ($this->isCached($id, $this->cache_group) && !isExpired($id, $this->cache_group)) { return array($ffile, $url); } if (strtoupper($format) == 'JPG') { $genFormat = 'JPEG'; } else { $genFormat = strtoupper($format); } $func = 'Image' . $genFormat; $func($img, $ffile); ImageDestroy($img); return array($ffile, $url); } // end func cacheImageLink /** * Sets the URL prefix used when rendering HTML Tags. * * Make sure that the URL matches the cache directory, * otherwise you'll get broken links. * * @param string * @access public * @see setCacheDir() */ function setCacheURL($cache_url) { if ($cache_url && '/' != substr($cache_url, 1)) { $cache_url .= '/'; } $this->cache_url = $cache_url; } // end func setCacheURL /** * Sets the directory where to cache generated Images * * @param string * @access public * @see setCacheURL() */ function setCacheDir($cache_dir) { if ($cache_dir && '/' != substr($cache_dir, 1)) { $cache_dir .= '/'; } $this->cache_dir = $cache_dir; $this->container->cache_dir = $cache_dir; } // end func setCacheDir function generateID($variable, $format = 'png') { return md5(serialize($variable)) . '.' . $format; } // end func generateID } // end class Cache_Graphics ?> php-cache-1.5.6/Cache-1.5.6/HTTP_Request.php000066400000000000000000000233051166136052000200260ustar00rootroot00000000000000 | // +----------------------------------------------------------------------+ // // $Id: HTTP_Request.php 174777 2004-12-15 09:09:33Z dufuz $ require_once 'Cache.php'; require_once 'HTTP/Request.php'; define('CACHE_HTTP_REQUEST_GROUP_NAME', 'cache_http_request'); define('CACHE_HTTP_REQUEST_SUCCESS_RESPONSE_CODE', 200); define('CACHE_HTTP_REQUEST_KEEP_LOCAL_COPY', 1); define('CACHE_HTTP_REQUEST_RETURN_FALSE', 2); define('CACHE_HTTP_REQUEST_RETURN_PEAR_ERROR', 3); /** * HTTP_Request Cache * * The classical example is : * * You want to get news from another site through RSS remote files. But you * don't want to access to to the remote site at every time you display * its news on your site. Because, if the remote site is down or slow... * So you you need a class which makes a local cache copy of the remote file. * Every x hours, the cache is updated. But if the remote site is down, the * local cache copy is keeped (you can also get error messages if you want). * * So you need this class! * * Cache_HTTP_Request inherits from Cache and use HTTP_Request to access to * the remote file. * * Usage example : * * sendRequest(); * $remoteFileBody = $cache->getResponseBody(); * * (...) * ?> * * @author Fabien MARTY * @version $Id: HTTP_Request.php 174777 2004-12-15 09:09:33Z dufuz $ * @package Cache */ class Cache_HTTP_Request extends Cache { // --- Private properties --- /** * Lifetime in seconds (0 endless) * * @var int $_expires */ var $_expires; /** * HTTP Request * * @var object $_request */ var $_request; /** * Cache id for the classic cache file * * @see sendRequest() * @var string $_id */ var $_id; /** * Cache id for the endless cache file * * @see sendRequest() * @var string $_id */ var $_id2; /** * Data to use * * @see getReponseBody(), getReponseHeader(), getReponseCode() * @var array $_data */ var $_data ; // --- Public methods --- /** * Constructor * * @param $url The url to access * @param $params Associative array of parameters which can be: * method - Method to use, GET, POST etc * http - HTTP Version to use, 1.0 or 1.1 * user - Basic Auth username * pass - Basic Auth password * proxy_host - Proxy server host * proxy_port - Proxy server port * proxy_user - Proxy auth username * proxy_pass - Proxy auth password * @param string $container Name of container class * @param array $containerOptions Array with container class options * @param int $mode What to do when the remote server is down : * CACHE_HTTP_REQUEST_KEEP_LOCAL_COPY or * CACHE_HTTP_REQUEST_RETURN_FALSE or * CACHE_HTTP_REQUEST_RETURN_PEAR_ERROR * @param int $expires lifetime of the cached data in seconds - 0 for endless * @see Cache, HTTP_Request * @access public */ function Cache_HTTP_Request($url, $params = null, $container = 'file', $containerOptions = null, $expires = 3600, $mode = CACHE_HTTP_REQUEST_KEEP_LOCAL_COPY) { if (!isset($params)) { $params = array(); } if (!isset($containerOptions)) { $containerOptions = array ( 'cache_dir' => '/tmp/', 'filename_prefix' => 'cache_' ); } $this->Cache($container, $containerOptions); $this->_request = &new HTTP_Request($url, $params); $this->_id = md5($url.serialize($params)); $this->_id2 = md5($this->_id); // we need two keys $this->_mode = $mode; $this->_expires = $expires; } /** * Deconstructor * * @access public */ function _Cache_HTTP_Request() { $this->_Cache(); } /** * Get and return the response body (null if no data available) * * @see sendRequest() * @return mixed response body * @access public */ function getResponseBody() { return $this->_data['body']; } /** * Get and return the response code (null if no data available) * * @see sendRequest() * @return mixed response code * @access public */ function getResponseCode() { return $this->_data['code']; } /** * Get and return the response header (null if no data available) * * @see sendRequest() * @return mixed response header * @access public */ function getResponseHeader() { return $this->_data['header']; } /** * Set a new mode when the server is down * * @param int $newMode What to do when the remote server is down : * CACHE_HTTP_REQUEST_KEEP_LOCAL_COPY or * CACHE_HTTP_REQUEST_RETURN_FALSE or * CACHE_HTTP_REQUEST_RETURN_PEAR_ERROR * @access public */ function setMode($newMode) { $this->_mode = $newMode; } /** * Send the HTTP request or use the cache system * * If there is a cache file for this HTTP request, the request is not re-sent. * Cached response is used. Yet, if the cache is expired, the HTTP request * is re-sent. Then, if the remote server is down, this method will return : * (depending on the selected mode) * - false or * - a PEAR_Error or (better) * - true and the local copy of the latest valid response will be used. * * (technical) * For the last choice, there is a technical tips. * Indeed, there are two cache files. The first one (id key) is a classical one * with the given lifetime. But it can be removed by automatic garbage collection * for example. So to be able to use the latest valid response (when the remote * server is dead), we make a second cache file with no lifetime (id2 key). * * @return mixed true or false or a PEAR_ERROR * @access public */ function sendRequest() { if ($data = $this->get($this->_id, CACHE_HTTP_REQUEST_GROUP_NAME)) { // --- Cache hit --- $this->_data = $data; return true; } else { // --- Cache miss --- if ($this->_sendRequestAndGetResponse()) { // So the remote server is ok... $this->save($this->_id, $this->_data, $this->_expires, CACHE_HTTP_REQUEST_GROUP_NAME); $this->save($this->_id2, $this->_data, 0, CACHE_HTTP_REQUEST_GROUP_NAME); return true; } else { if ($data_sav = $this->get($this->_id2, CACHE_HTTP_REQUEST_GROUP_NAME)) { // Ok, the "recover cache" is available... switch ($this->_mode) { case CACHE_HTTP_REQUEST_KEEP_LOCAL_COPY: // We make a new local copy and keep it until it expires... $this->save($this->_id, $data_sav, $this->_expires, CACHE_HTTP_REQUEST_GROUP_NAME); $this->_data = $data_sav; return true; break; case CACHE_HTTP_REQUEST_RETURN_FALSE: // We return false return false; break; case CACHE_HTTP_REQUEST_RETURN_PEAR_ERROR: // We return a PEAR_Error! return new Cache_Error('Remote file is not available!'); break; } } else { // It's terrible! The remote server is down and definitively no cache available! return new Cache_Error('Remote server down and no cache available!'); } } } } // --- Private Methods --- /** * Send HTTP request and get the response * * @return boolean success or not ? * @see HTTP_Request * @access private */ function _sendRequestAndGetResponse() { $this->_request->sendRequest(); $body = $this->_request->getResponseBody(); $code = $this->_request->getResponseCode(); $header = $this->_request->getResponseHeader(); $this->_data = array( 'body' => $body, 'code' => $code, 'header' => $header ); return (($code==CACHE_HTTP_REQUEST_SUCCESS_RESPONSE_CODE) ? true : false); } } ?> php-cache-1.5.6/Cache-1.5.6/Output.php000066400000000000000000000162301166136052000170360ustar00rootroot00000000000000 | // | Christian Stocker | // | Vinai Kopp | // +----------------------------------------------------------------------+ // // $Id: Output.php 178289 2005-01-26 09:47:28Z dufuz $ require_once 'Cache.php'; /** * Class to cache the output of a script using the output buffering functions * * Simple output cache. Some pages require lots of time to compute. Caching the * output can increase the overall speed dramatically, especially if you use * a Shared Memory storage container. * * As you can see in the example the usage is extemely simple. To cache a script * simple put some few lines of code in front of your script and some at the end. * A preferrable place for this are the auto_prepend and auto_append files (=> php.ini). * * Usage example: * * // place this somewhere in a central config file * define(CACHE_STORAGE_CLASS, 'file'); * // file storage needs a dir to put the cache files * define(CACHE_DIR, '/var/tmp/'); * * // get a cache object * $cache = new Cache_Output(CACHE_STORAGE_CLASS, array('cache_dir' => CACHE_DIR)); * * // compute the unique handle. * // if your script depends on Cookie and HTTP Post data as well * // you should use: * // $cache_handle = array( * // 'file' => $REQUEST_URI, * // 'post' => $HTTP_POST_VARS, * // 'cookie' => $HTTP_COOKIE_VARS * // ); * // But be warned, using all GET or POST Variables as a seed * // can be used for a DOS attack. Calling http://www.example.com/example.php?whatever * // where whatever is a random text might be used to flood your cache. * $cache_handle = $cache->generateID($REQUEST_URI); * * // now the magic happens: if cached call die() * // to end the time consumptiong script script execution and use the cached value! * if ($content = $cache->start($cache_handle)) { * print $content; * print '

Cache hit

'; * die(); * } * * // time consumption script goes here. * * // store the output of the cache into the cache and print the output. * print $cache->end(); * print "

Cache miss, stored using the ID '$id'.

"; * * If you do not want to cache a whole page - no problem: * * if (!($content = $cache->start($cache_handle))) { * // do the computation here * print $cache->end() * } else { * print $content; * } * * If you need an example script check the (auto_)prepend and (auto_)append * files of my homepage: * * http://www.ulf-wendel.de/php/show_source.php?file=prepend * http://www.ulf-wendel.de/php/show_source.php?file=append * * Don't know how to use it or you need profiling informations?` * Ask Christian he was patient with me and he'll be so with your questions ;). * * Have fun! * * @authors Ulf Wendel * @version $ID: $ * @package Cache * @access public */ class Cache_Output extends Cache { /** * ID passed to start() * * @var string * @see start(), end() */ var $output_id = ''; /** * Group passed to start() * * @var string * @see start(), end() */ var $output_group = ''; /** * PEAR-Deconstructor * Call deconstructor of parent */ function _Cache_Output() { $this->_Cache(); } /** * starts the output buffering and returns an empty string or returns the cached output from the cache. * * @param string dataset ID * @param string cache group * @return string * @access public */ function start($id, $group = 'default') { if (!$this->caching) { return ''; } // this is already cached return it from the cache so that the user // can use the cache content and stop script execution if ($content = $this->get($id, $group)) { return $content; } // remember some data to be able to fill the cache on calling end() $this->output_id = $id; $this->output_group = $group; // WARNING: we need the output buffer - possible clashes ob_start(); ob_implicit_flush(false); return ''; } // end func start /* * Stores the content of the output buffer into the cache and returns the content. * * @param mixed lifetime of the cached data in seconds - 0 for endless. More formats available. see Container::getExpiresAbsolute() * @param string additional userdefined data * @return string cached output * @access public * @see endPrint(), endGet(), Container::getExpiresAbsolute() */ function end($expire = 0, $userdata = '') { $content = ob_get_contents(); ob_end_clean(); // store in the cache if ($this->caching) { $this->container->save($this->output_id, $content, $expire, $this->output_group, $userdata); } return $content; } // end func end() /** * Stores the content of the output buffer into the cache and prints the content. * * @brother end() */ function endPrint($expire = 0, $userdata = '') { $this->printContent($this->end($expire, $userdata)); } // end func endPrint /** * Sends the data to the user. * This is for compatibility with OutputCompression * * @param string * @access public */ function printContent($content = '') { if ($content == '') { $content = &$this->container->cachedata; } print $content; } /** * Returns the content of the output buffer but does not store it into the cache. * * Use this method if the content of your script is markup (XML) * that has to be parsed/converted (XSLT) before you can output * and store it into the cache using save(). * * @return string * @access public * @see endPrint(), end() */ function endGet() { $content = ob_get_contents(); ob_end_clean(); $this->output_id = ''; $this->output_group = ''; return $content; } // end func endGet } // end class output ?> php-cache-1.5.6/Cache-1.5.6/OutputCompression.php000066400000000000000000000215051166136052000212610ustar00rootroot00000000000000 | // | Christian Stocker | // +----------------------------------------------------------------------+ require_once 'Cache/Output.php'; /** * Cache using Output Buffering and contnet (gz) compression. ** Usage example: * * // place this somewhere in a central config file * define(CACHE_STORAGE_CLASS, 'file'); * // file storage needs a dir to put the cache files * define(CACHE_DIR, '/var/tmp/'); * * // get a cache object * $cache = new Cache_Output(CACHE_STORAGE_CLASS, array('cache_dir' => CACHE_DIR)); * * if (!($content = $cache->start($cache->generateID($REQUEST_URI)))) { * print "hello world"; * $cache->endPrint(+1000); * } * else { * $cache->printContent(); * } * * OR * * if (($content = $cache->start($cache->generateID($REQUEST_URI)))) { * $cache->printContent(); * die(); * } * print "hello world"; * $cache->endPrint(+1000); * * * Based upon a case study from Christian Stocker and inspired by jpcache. * * @version $Id: OutputCompression.php 178289 2005-01-26 09:47:28Z dufuz $ * @author Ulf Wendel , Christian Stocker * @access public * @package Cache */ class Cache_OutputCompression extends Cache_Output { /** * Encoding, what the user (its browser) of your website accepts * * "auto" stands for test using $_SERVER['HTTP_ACCEPT_ENCODING']($HTTP_ACCEPT_ENCODING). * * @var string * @see Cache_OutputCompression(), setEncoding() */ var $encoding = 'auto'; /** * Method used for compression * * @var string * @see isCompressed() */ var $compression = ''; /** * Sets the storage details and the content encoding used (if not autodetection) * * @param string Name of container class * @param array Array with container class options * @param string content encoding mode - auto => test which encoding the user accepts */ function Cache_OutputCompression($container, $container_options = '', $encoding = 'auto') { $this->setEncoding($encoding); $this->Cache($container, $container_options); } // end constructor /** * Call parent deconstructor. */ function _Cache_OutputCompression() { $this->_Cache(); } // end deconstructor function generateID($variable) { $this->compression = $this->getEncoding(); return md5(serialize($variable) . serialize($this->compression)); } // end generateID function get($id, $group) { $this->content = ''; if (!$this->caching) { return ''; } if ($this->isCached($id, $group) && !$this->isExpired($id, $group)) { $this->content = $this->load($id, $group); } return $this->content; } // end func get /** * Stops the output buffering, saves it to the cache and returns the _compressed_ content. * * If you need the uncompressed content for further procession before * it's saved in the cache use endGet(). endGet() does _not compress_. */ function end($expire = 0, $userdata = '') { $content = ob_get_contents(); ob_end_clean(); // store in the cache if ($this->caching) { $this->extSave($this->output_id, $content, $userdata, $expire, $this->output_group); return $this->content; } return $content; } // end func end() function endPrint($expire = 0, $userdata = '') { $this->printContent($this->end($expire, $userdata)); } // end func endPrint /** * Saves the given data to the cache. * */ function extSave($id, $cachedata, $userdata, $expires = 0, $group = 'default') { if (!$this->caching) { return true; } if ($this->compression) { $len = strlen($cachedata); $crc = crc32($cachedata); $cachedata = gzcompress($cachedata, 9); $this->content = substr($cachedata, 0, strlen($cachedata) - 4) . pack('V', $crc) . pack('V', $len); } else { $this->content = $cachedata; } return $this->container->save($id, $this->content, $expires, $group, $userdata); } // end func extSave /** * Sends the compressed data to the user. * * @param string * @access public */ function printContent($content = '') { $server = &$this->_importGlobalVariable("server"); if ($content == '') { $content = &$this->container->cachedata; } if ($this->compression && $this->caching) { $etag = '"PEAR-Cache-' . md5(substr($content, -40)) .'"'; header("ETag: $etag"); if (isset($server['HTTP_IF_NONE_MATCH']) && strstr(stripslashes($server['HTTP_IF_NONE_MATCH']), $etag)) { // not modified header('HTTP/1.0 304'); return; } else { // client acceppts some encoding - send headers & data header("Content-Encoding: {$this->compression}"); header('Vary: Accept-Encoding'); print "\x1f\x8b\x08\x00\x00\x00\x00\x00"; } } die($content); } // end func printContent /** * Returns the encoding method of the current dataset. * * @access public * @return string Empty string (which evaluates to false) means no compression */ function isCompressed() { return $this->compression; } // end func isCompressed /** * Sets the encoding to be used. * * @param string "auto" means autodetect for every client * @access public * @see $encoding */ function setEncoding($encoding = 'auto') { $this->encoding = $encoding; } // end func setEncoding /** * Returns the encoding to be used for the data transmission to the client. * * @see setEncoding() */ function getEncoding() { $server = &$this->_importGlobalVariable("server"); // encoding set by user if ('auto' != $this->encoding) { return $this->encoding; } // check what the client accepts if (false !== strpos($server['HTTP_ACCEPT_ENCODING'], 'x-gzip')) { return 'x-gzip'; } if (false !== strpos($server['HTTP_ACCEPT_ENCODING'], 'gzip')) { return 'gzip'; } // no compression return ''; } // end func getEncoding // {{{ _importGlobalVariable() /** * Import variables from special namespaces. * * @access private * @param string Type of variable (server, session, post) * @return array */ function &_importGlobalVariable($variable) { $var = null; switch (strtolower($variable)) { case 'server': if (isset($_SERVER)) { $var = &$_SERVER; } else { $var = &$GLOBALS['HTTP_SERVER_VARS']; } break; case 'session': if (isset($_SESSION)) { $var = &$_SESSION; } else { $var = &$GLOBALS['HTTP_SESSION_VARS']; } break; case 'post': if (isset($_POST)) { $var = &$_POST; } else { $var = &$GLOBALS['HTTP_POST_VARS']; } break; default: break; } return $var; } // }} } // end class OutputCompression ?> php-cache-1.5.6/package.xml000066400000000000000000000146741166136052000155040ustar00rootroot00000000000000 Cache pear.php.net Framework for caching of arbitrary data. With the PEAR Cache you can cache the result of certain function calls, as well as the output of a whole script run or share data between applications. Christian Stocker chregu chregu@php.net no Helgi Þormar dufuz dufuz@php.net yes Ulf Wendel uw ulf.wendel@phpdoc.de no 2010-10-25 1.5.6 1.5.5 stable stable PHP License Automatically built QA release Bug #17020 PHP-Error - doconnor 4.3.0 1.7.0 PEAR pear.php.net 1.7.0 HTTP_Request pear.php.net 1.5.5RC4 1.5.5RC4 beta beta PHP License - Fixed Bug #4449 XML errors during installation 1.5.4 1.5.4 stable stable 2004-04-01 PHP License - Removed Cache_DB as it apparently never really worked. - Added trifile container. See http://atomized.org/PEAR/Cache_trifile.html for more information. (By Ian Eure) 1.5.5RC1 1.5.5RC1 beta beta 2005-04-29 PHP License - Bug #1999 typo fix by Ian Eure, prevented the saving of $userdata in Trifile container - PHP Bug #25134 / PEAR bug #2955, typo fix by Greg in msession container, disallowed id_length - Bug #2749, flush() done 2x in a row gave error about none existing directory. - ETag made RFC compailant in OutputCompression (by mike) - Bug #3515 typo fix in file container, spotted by Girish dot Nair1 at cognizant dot com - CS fixes 1.5.5RC2 1.5.5RC2 beta beta 2005-05-18 PHP License - package.xml was giving errors when installed because of new line at the end. 1.5.5RC3 1.5.5RC3 beta beta 2005-05-25 PHP License - Fixed bug #4429 Call-time pass-by-reference has been deprecated 1.5.6 1.5.5 stable stable 2010-10-25 PHP License Automatically built QA release Bug #17020 PHP-Error - doconnor