Skip to content

Instantly share code, notes, and snippets.

@cs278
Created June 4, 2009 21:42
Show Gist options
  • Save cs278/123869 to your computer and use it in GitHub Desktop.
Save cs278/123869 to your computer and use it in GitHub Desktop.
<?php
/**
*
* @package acm
* @version $Id$
* @copyright (c) 2005, 2009 phpBB Group
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
define('CACHE_TABLE', $table_prefix . 'cache');
define('PHPBB_ACM_DB_EXISTS', 1);
define('PHPBB_ACM_DB_STALE', 2);
define('PHPBB_ACM_DB_READY', 4);
/*
DROP TABLE IF EXISTS phpbb_cache;
CREATE TABLE phpbb_cache (
var_name VARCHAR(255) NOT NULL,
var_data MEDIUMTEXT NOT NULL,
var_expires int(11) NOT NULL,
var_global tinyint(1) NOT NULL,
PRIMARY KEY (var_name),
KEY var_expires (var_expires),
KEY var_global (var_global)
) CHARACTER SET utf8 COLLATE utf8_bin;
*/
/**
* ACM for caching in the database
* @package acm
*/
class acm
{
var $cache_dir;
var $vars;
var $states;
var $ttls;
function acm()
{
global $phpbb_root_path;
$this->cache_dir = $phpbb_root_path . 'cache/';
}
function load($var_name = '')
{
global $db;
$this->vars = $this->states = $this->ttls = array();
$sql_extra = ($var_name) ? " OR var_name = '" . $db->sql_escape($var_name) . "'" : '';
$sql = 'SELECT var_name, var_data
FROM ' . CACHE_TABLE . '
WHERE var_expires > ' . time() . "
AND (var_global = 1$sql_extra)";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$this->vars[$row['var_name']] = $row['var_data'];
$this->states[$row['var_name']] = PHPBB_ACM_DB_EXISTS;
}
$db->sql_freeresult($result);
}
function unload()
{
$this->save();
unset($this->vars);
}
function purge()
{
global $db;
// Purge all phpbb cache files
$dir = @opendir($this->cache_dir);
if (!$dir)
{
return;
}
while (($entry = readdir($dir)) !== false)
{
if (strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0)
{
continue;
}
$this->remove_file($this->cache_dir . $entry);
}
closedir($dir);
// Quicker than truncate on small tables
$sql = 'DELETE FROM ' . CACHE_TABLE;
$db->sql_query($sql);
foreach ($this->states as $var_name => $void)
{
$this->states[$var_name] = 0;
}
$this->vars = $this->ttls = array();
}
function save()
{
global $db;
$delete = $insert = $update = array();
$time = time();
foreach ($this->states as $var_name => $state)
{
if (!($state & PHPBB_ACM_DB_STALE))
{
// Skip anything that is not stale
continue;
}
if (!($state & PHPBB_ACM_DB_READY))
{
// If the var is not ready to use and is stale
// it must have been deleted.
$delete[] = $var_name;
}
else
{
if ($state & PHPBB_ACM_DB_EXISTS)
{
// Ready, existing, and stale must need updating
$array = 'update';
}
else
{
$array = 'insert';
}
${$array}[$var_name] = array(
'var_name' => $var_name,
'var_data' => serialize($this->vars[$var_name]),
'var_expires' => $this->ttls[$var_name] + $time,
'var_global' => ($var_name[0] == '_' ? false : true),
);
}
}
if (empty($delete) && empty($update) && empty($insert))
{
return;
}
if (!empty($delete) || !empty($update))
{
$sql = 'DELETE FROM ' . CACHE_TABLE . '
WHERE ' . $db->sql_in_set('var_name', array_merge($delete, array_keys($update)));
// We only want to update the entries we really want to delete
if (function_exists('array_combine'))
{
$this->states = array_merge($this->states, array_combine($delete, array_fill(0, sizeof($delete), 0)));
}
else
{
foreach ($delete as $var_name)
{
$this->states[$var_name] = 0;
}
}
unset($delete);
}
if (!empty($insert) || !empty($update))
{
$insert = array_merge($insert, $update);
$db->sql_multi_insert(CACHE_TABLE, array_values($insert));
if (function_exists('array_combine'))
{
$this->states = array_merge($this->states, array_combine(array_keys($insert), array_fill(0, sizeof($insert), PHPBB_ACM_DB_READY | PHPBB_ACM_DB_EXISTS)));
}
else
{
foreach (array_keys($insert) as $var_name)
{
$this->states[$var_name] = PHPBB_ACM_DB_READY | PHPBB_ACM_DB_EXISTS;
}
}
unset($insert, $update);
}
}
function tidy()
{
global $db;
$sql = 'DELETE FROM ' . CACHE_TABLE . '
WHERE var_expires < ' . time();
$db->sql_query($sql);
set_config('cache_last_gc', time(), true);
}
function get($var_name)
{
if (!is_array($this->vars))
{
if ($var_name[0] == '_')
{
$this->load($var_name);
}
else
{
$this->load();
}
}
if ($var_name[0] == '_' && !isset($this->states[$var_name]))
{
// Local, not known request it
global $db;
$sql = 'SELECT var_data
FROM ' . CACHE_TABLE . "
WHERE var_name = '" . $db->sql_escape($var_name) . "'
AND var_expires > " . time();
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
$this->vars[$var_name] = $row['var_data'];
$this->states[$var_name] = PHPBB_ACM_DB_EXISTS;
}
else
{
$this->states[$var_name] = 0;
}
$db->sql_freeresult($result);
}
if ($this->_exists($var_name))
{
if (!($this->states[$var_name] & PHPBB_ACM_DB_READY))
{
$this->vars[$var_name] = unserialize($this->vars[$var_name]);
$this->states[$var_name] |= PHPBB_ACM_DB_READY;
}
return $this->vars[$var_name];
}
else
{
return false;
}
}
function put($var_name, $var_data, $ttl = 31536000)
{
if (!is_array($this->vars))
{
$this->load();
}
if (!isset($this->states[$var_name]))
{
$this->states[$var_name] = 0;
}
$this->vars[$var_name] = $var_data;
$this->states[$var_name] |= PHPBB_ACM_DB_READY | PHPBB_ACM_DB_STALE;
$this->ttls[$var_name] = $ttl;
}
function destroy($var_name)
{
if ($var_name == 'sql')
{
// We don't support SQL caching
return;
}
if (!is_array($this->vars))
{
$this->load();
}
unset($this->vars[$var_name]);
$this->states[$var_name] = ($this->states[$var_name] ^ PHPBB_ACM_DB_READY) | PHPBB_ACM_DB_STALE;
}
function _exists($var_name)
{
return (isset($this->vars[$var_name])) ? true : false;
}
/**
* Removes/unlinks file
*/
function remove_file($filename, $check = false)
{
if ($check && !@is_writable($this->cache_dir))
{
// E_USER_ERROR - not using language entry - intended.
trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR);
}
return @unlink($filename);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment