Public feed
#722268
<?php
// $Id: cache.inc,v 1.5 2006/11/10 07:26:27 drumm Exp $
/**
* Return data from the persistent cache.
*
* @param $key
* The cache ID of the data to retrieve.
* @param $table
* The table $table to store the data in. Valid core values are 'cache_filter',
* 'cache_menu', 'cache_page', or 'cache' for the default cache.
*/
function cache_get($key, $table = 'cache') {
global $user;
// Garbage collection necessary when enforcing a minimum cache lifetime
$cache_flush = variable_get('cache_flush', 0);
if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= time())) {
// Time to flush old cache data
db_query("DELETE FROM {%s} WHERE expire != %d AND expire <= %d", $table, CACHE_PERMANENT, $cache_flush);
variable_set('cache_flush', 0);
}
$cache = db_fetch_object(db_query("SELECT data, created, headers, expire FROM {%s} WHERE cid = '%s'", $table, $key));
if (isset($cache->data)) {
// If the data is permanent or we're not enforcing a minimum cache lifetime
// always return the cached data.
if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) {
$cache->data = db_decode_blob($cache->data);
}
// If enforcing a minimum cache lifetime, validate that the data is
// currently valid for this user before we return it by making sure the
// cache entry was created before the timestamp in the current session's
// cache timer. The cache variable is loaded into the $user object by
// sess_read() in session.inc.
else {
if ($user->cache > $cache->created) {
// This cache data is too old and thus not valid for us, ignore it.
return 0;
}
else {
$cache->data = db_decode_blob($cache->data);
}
}
return $cache;
}
return 0;
}
/**
* Store data in the persistent cache.
*
* The persistent cache is split up into four database
* tables. Contributed modules can add additional tables.
*
* 'cache_page': This table stores generated pages for anonymous
* users. This is the only table affected by the page cache setting on
* the administrator panel.
*
* 'cache_menu': Stores the cachable part of the users' menus.
*
* 'cache_filter': Stores filtered pieces of content. This table is
* periodically cleared of stale entries by cron.
*
* 'cache': Generic cache storage table.
*
* The reasons for having several tables are as follows:
*
* - smaller tables allow for faster selects and inserts
* - we try to put fast changing cache items and rather static
* ones into different tables. The effect is that only the fast
* changing tables will need a lot of writes to disk. The more
* static tables will also be better cachable with MySQL's query cache
*
* @param $cid
* The cache ID of the data to store.
* @param $table
* The table $table to store the data in. Valid core values are 'cache_filter',
* 'cache_menu', 'cache_page', or 'cache'.
* @param $data
* The data to store in the cache. Complex data types must be serialized first.
* @param $expire
* One of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
* general cache wipe.
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like CACHE_TEMPORARY.
* @param $headers
* A string containing HTTP header information for cached pages.
*/
function cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $headers = NULL) {
db_lock_table($table);
db_query("UPDATE {%s} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $table, $data, time(), $expire, $headers, $cid);
if (!db_affected_rows()) {
@db_query("INSERT INTO {%s} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $table, $cid, $data, time(), $expire, $headers);
}
db_unlock_tables();
}
/**
*
* Expire data from the cache. If called without arguments, expirable
* entries will be cleared from the cache_page table.
*
* @param $cid
* If set, the cache ID to delete. Otherwise, all cache entries that can
* expire are deleted.
*
* @param $table
* If set, the table $table to delete from. Mandatory
* argument if $cid is set.
*
* @param $wildcard
* If set to TRUE, the $cid is treated as a substring
* to match rather than a complete ID. The match is a right hand
* match. If '*' is given as $cid, the table $table will be emptied.
*/
function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) {
global $user;
if (!isset($cid) && !isset($table)) {
cache_clear_all(NULL, 'cache_page');
return;
}
if (empty($cid)) {
if (variable_get('cache_lifetime', 0)) {
// We store the time in the current user's $user->cache variable which
// will be saved into the sessions table by sess_write(). We then
// simulate that the cache was flushed for this user by not returning
// cached data that was cached before the timestamp.
$user->cache = time();
$cache_flush = variable_get('cache_flush', 0);
if ($cache_flush == 0) {
// This is the first request to clear the cache, start a timer.
variable_set('cache_flush', time());
}
else if (time() > ($cache_flush + variable_get('cache_lifetime', 0))) {
// Clear the cache for everyone, cache_flush_delay seconds have
// passed since the first request to clear the cache.
db_query("DELETE FROM {%s} WHERE expire != %d AND expire < %d", $table, CACHE_PERMANENT, time());
variable_set('cache_flush', 0);
}
}
else {
// No minimum cache lifetime, flush all temporary cache entries now.
db_query("DELETE FROM {%s} WHERE expire != %d AND expire < %d", $table, CACHE_PERMANENT, time());
}
}
else {
if ($wildcard) {
if ($cid == '*') {
db_query("TRUNCATE TABLE {%s}", $table);
}
else {
db_query("DELETE FROM {%s} WHERE cid LIKE '%s%%'", $table, $cid);
}
}
else {
db_query("DELETE FROM {%s} WHERE cid = '%s'", $table, $cid);
}
}
}
======================
<?php
// +----------------------------------------------------------------------+
// | PEAR :: Cache |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Ulf Wendel <ulf.wendel@phpdoc.de> |
// | Sebastian Bergmann <sb@sebastian-bergmann.de> |
// | Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: db.php,v 1.8 2005/01/26 09:42:30 dufuz Exp $
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 <sb@sebastian-bergmann.de>
* @version $Id: db.php,v 1.8 2005/01/26 09:42:30 dufuz Exp $
* @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
/* jpcache_db_connect()
*
* Makes connection to the database
*/
function jpcache_db_connect()
{
$GLOBALS["sql_link"] = @mysql_connect($GLOBALS["JPCACHE_DB_HOST"],
$GLOBALS["JPCACHE_DB_USERNAME"],
$GLOBALS["JPCACHE_DB_PASSWORD"]);
}
/* jpcache_db_disconnect()
*
* Closes connection to the database
*/
function jpcache_db_disconnect()
{
mysql_close($GLOBALS["sql_link"]);
}
/* jpcache_db_query($query)
*
* Executes a given query
*/
function jpcache_db_query($query)
{
// jpcache_debug("Executing SQL-query $query");
$ret = @mysql_db_query($GLOBALS["JPCACHE_DB_DATABASE"],
$query,
$GLOBALS["sql_link"]);
return $ret;
}
/* jpcache_restore()
*
* Will try to restore the cachedata from the db.
*/
function jpcache_restore()
{
$res = jpcache_db_query("select GZDATA, DATASIZE, DATACRC from ".
$GLOBALS["JPCACHE_DB_TABLE"].
" where CACHEKEY='".
addslashes($GLOBALS["jpcache_key"]).
"' and (CACHEEXPIRATION>".
time().
" or CACHEEXPIRATION=0)"
);
if ($res && mysql_num_rows($res))
{
if ($row = mysql_fetch_array($res))
{
// restore data into global scope from found row
$GLOBALS["jpcachedata_gzdata"] = $row["GZDATA"];
$GLOBALS["jpcachedata_datasize"] = $row["DATASIZE"];
$GLOBALS["jpcachedata_datacrc"] = $row["DATACRC"];
return true;
}
}
return false;
}
/* jpcache_write()
*
* Will (try to) write out the cachedata to the db
*/
function jpcache_write($gzdata, $datasize, $datacrc)
{
$dbtable = $GLOBALS["JPCACHE_DB_TABLE"];
// XXX: Later on, maybe implement locking mechanism inhere.
// Check if it already exists
$res = jpcache_db_query("select CACHEEXPIRATION from $dbtable".
" where CACHEKEY='".
addslashes($GLOBALS["jpcache_key"]).
"'"
);
if (!$res || mysql_num_rows($res) < 1)
{
// Key not found, so insert
$res = jpcache_db_query("insert into $dbtable".
" (CACHEKEY, CACHEEXPIRATION, GZDATA,".
" DATASIZE, DATACRC) values ('".
addslashes($GLOBALS["jpcache_key"]).
"',".
(($GLOBALS["JPCACHE_TIME"] != 0) ?
(time()+$GLOBALS["JPCACHE_TIME"]) : 0).
",'".
addslashes($gzdata).
"', $datasize, $datacrc)"
);
// This fails with unique-key violation when another thread has just
// inserted the same key. Just continue, as the result is (almost)
// the same.
}
else
{
// Key found, so update
$res = jpcache_db_query("update $dbtable set CACHEEXPIRATION=".
(($GLOBALS["JPCACHE_TIME"] != 0) ?
(time()+$GLOBALS["JPCACHE_TIME"]) : 0).
", GZDATA='".
addslashes($gzdata).
"', DATASIZE=$datasize, DATACRC=$datacrc where".
" CACHEKEY='".
addslashes($GLOBALS["jpcache_key"]).
"'"
);
// This might be an update too much, but it shouldn't matter
}
}
/* jpcache_do_gc()
*
* Performs the actual garbagecollection
*/
function jpcache_do_gc()
{
jpcache_db_query("delete from ".
$GLOBALS["JPCACHE_DB_TABLE"].
" where CACHEEXPIRATION<=".
time().
" and CACHEEXPIRATION!=0"
);
// Are we allowed to do an optimize table-call?
// As noted, first check if this works on your mysql-installation!
if ($GLOBALS["JPCACHE_OPTIMIZE"])
{
jpcache_db_query("OPTIMIZE TABLE ".$GLOBALS["JPCACHE_DB_TABLE"]);
}
}
/* jpcache_do_start()
*
* Additional code that is executed before main jpcache-code kicks in.
*/
function jpcache_do_start()
{
// Connect to db
jpcache_db_connect();
}
/* jpcache_do_end()
*
* Additional code that is executed after caching has been performed,
* but just before output is returned. No new output can be added!
*/
function jpcache_do_end()
{
// Disconnect from db
jpcache_db_disconnect();
}
?>
# phpMyAdmin MySQL-Dump
# http://www.htmlwizard.net/phpMyAdmin/
#
# Host: localhost:3300 Database : jpcache
# --------------------------------------------------------
#
# Table structure for table 'CACHEDATA'
#
CREATE TABLE CACHEDATA (
CACHEKEY varchar(255) NOT NULL,
CACHEEXPIRATION int(11) NOT NULL,
GZDATA blob,
DATASIZE int(11),
DATACRC int(11),
PRIMARY KEY (CACHEKEY)
);