diff options
Diffstat (limited to 'phpBB/includes/acm')
-rw-r--r-- | phpBB/includes/acm/acm_file.php | 493 |
1 files changed, 189 insertions, 304 deletions
diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index 23183d1865..e05977d158 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -17,67 +17,155 @@ if (!defined('IN_PHPBB')) } /** -* ACM File Based Caching +* Define file-based cache. * @package acm */ -class acm +class phpbb_acm_file extends phpbb_acm_abstract { - private $vars = array(); - private $var_expires = array(); - private $is_modified = false; - - public $sql_rowset = array(); + /** + * @var string The cache directory to use + */ public $cache_dir = ''; /** - * Set cache path + * @var array|bool The cache types this class supports. True indicates support for all types. + */ + public $supported = true; + + /** + * Set cache directory + * + * @param string $cache_prefix The cache prefix the instance is responsible for + * @access public */ - function __construct() + public function __construct($cache_prefix) { $this->cache_dir = PHPBB_ROOT_PATH . 'cache/'; + $this->cache_prefix = $cache_prefix; } /** - * Load global cache + * {@link phpbb_acm_abstract::get() get()} */ - private function load() + public function get($var_name) { - // grab the global cache - if (file_exists($this->cache_dir . 'data_global.' . PHP_EXT)) + if ($var_name[0] === '#') { - @include($this->cache_dir . 'data_global.' . PHP_EXT); - return true; + $var_name = substr($var_name, 1); + return $this->get_global($var_name); } - return false; + if (!$this->exists($var_name)) + { + return false; + } + + @include($this->cache_dir . $this->cache_prefix . '_' . $var_name . '.' . PHP_EXT); + + // If no data there, then the file expired... + if ($expired) + { + // Destroy + $this->destroy($var_name); + return false; + } + + return $data; } /** - * Unload cache object + * {@link phpbb_acm_abstract::put() put()} */ - public function unload() + public function put($var_name, $data, $ttl = 31536000) + { + if ($var_name[0] === '#') + { + $var_name = substr($var_name, 1); + return $this->put_global($var_name, $data, $ttl); + } + + $filename = $this->cache_dir . $this->cache_prefix . '_' . $var_name . '.' . PHP_EXT; + + if ($fp = @fopen($filename, 'wb')) + { + @flock($fp, LOCK_EX); + fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\$data = " . (sizeof($data) ? "unserialize(" . var_export(serialize($data), true) . ");" : 'array();')); + @flock($fp, LOCK_UN); + fclose($fp); + + if (!function_exists('phpbb_chmod')) + { + include(PHPBB_ROOT_PATH . 'includes/functions.' . PHP_EXT); + } + + phpbb_chmod($filename, phpbb::CHMOD_WRITE); + } + + return $data; + } + + + /** + * {@link phpbb_acm_abstract::exists() exists()} + */ + public function exists($var_name) + { + if ($var_name[0] === '#') + { + $var_name = substr($var_name, 1); + return $this->exists_global($var_name); + } + + return file_exists($this->cache_dir . $this->cache_prefix . '_' . $var_name . '.' . PHP_EXT); + } + + /** + * {@link phpbb_acm_abstract::destroy() destroy()} + */ + public function destroy($var_name) + { + if ($var_name[0] === '#') + { + $var_name = substr($var_name, 1); + $this->destroy_global($var_name); + } + + if (!$this->exists($var_name)) + { + return false; + } + + $this->remove_file($this->cache_dir . $this->cache_prefix . '_' . $var_name . '.' . PHP_EXT, true); + } + + /** + * {@link phpbb_acm_abstract::load() load()} + */ + public function load() { - $this->save(); - unset($this->vars); - unset($this->var_expires); - unset($this->sql_rowset); - - $this->vars = array(); - $this->var_expires = array(); - $this->sql_rowset = array(); + // grab the global cache + if (file_exists($this->cache_dir . $this->cache_prefix . '_global.' . PHP_EXT)) + { + @include($this->cache_dir . $this->cache_prefix . '_global.' . PHP_EXT); + return true; + } + + return false; } /** - * Save modified objects + * {@link phpbb_acm_abstract::unload() unload()} */ - private function save() + public function unload() { if (!$this->is_modified) { return; } - if ($fp = @fopen($this->cache_dir . 'data_global.' . PHP_EXT, 'wb')) + $filename = $this->cache_dir . $this->cache_prefix . '_global.' . PHP_EXT; + + if ($fp = @fopen($filename, 'wb')) { @flock($fp, LOCK_EX); fwrite($fp, "<?php\n\$this->vars = unserialize(" . var_export(serialize($this->vars), true) . ");\n\$this->var_expires = unserialize(" . var_export(serialize($this->var_expires), true) . ");"); @@ -89,7 +177,7 @@ class acm include(PHPBB_ROOT_PATH . 'includes/functions.' . PHP_EXT); } - phpbb_chmod($this->cache_dir . 'data_global.' . PHP_EXT, phpbb::CHMOD_WRITE); + phpbb_chmod($filename, phpbb::CHMOD_WRITE); } else { @@ -99,16 +187,20 @@ class acm trigger_error($this->cache_dir . ' is NOT writable.', E_USER_ERROR); } - trigger_error('Not able to open ' . $this->cache_dir . 'data_global.' . PHP_EXT, E_USER_ERROR); + trigger_error('Not able to open ' . $filename, E_USER_ERROR); } $this->is_modified = false; + + // To reset the global vars + $this->vars = $this->var_expires = array(); } /** - * Tidy cache + * Tidy local cache data. Also see {@link phpbb_acm_abstract::tidy() tidy()} + * @access protected */ - public function tidy() + protected function tidy_local() { $dir = @opendir($this->cache_dir); @@ -119,96 +211,28 @@ class acm while (($entry = readdir($dir)) !== false) { - if (!preg_match('/^(sql_|data_(?!global))/', $entry)) + if (strpos($entry, $this->cache_prefix . '_') !== 0 || strpos($entry, $this->cache_prefix . '_global') === 0) { continue; } $expired = true; @include($this->cache_dir . $entry); + if ($expired) { $this->remove_file($this->cache_dir . $entry); } } closedir($dir); - - if (file_exists($this->cache_dir . 'data_global.' . PHP_EXT)) - { - if (!sizeof($this->vars)) - { - $this->load(); - } - - foreach ($this->var_expires as $var_name => $expires) - { - if (time() > $expires) - { - $this->destroy($var_name); - } - } - } - - set_config('cache_last_gc', time(), true); - } - - /** - * Get saved cache object - */ - public function get($var_name) - { - if ($var_name[0] === '_') - { - if (!$this->_exists($var_name)) - { - return false; - } - - @include($this->cache_dir . "data{$var_name}." . PHP_EXT); - return (isset($data)) ? $data : false; - } - else - { - return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; - } } /** - * Put data into cache + * Purge local cache data. Also see {@link phpbb_acm_abstract::purge() purge()} + * @access protected */ - function put($var_name, $var, $ttl = 31536000) + protected function purge_local() { - if ($var_name[0] === '_') - { - if ($fp = @fopen($this->cache_dir . "data{$var_name}." . PHP_EXT, 'wb')) - { - @flock($fp, LOCK_EX); - fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\$data = " . (sizeof($var) ? "unserialize(" . var_export(serialize($var), true) . ");" : 'array();')); - @flock($fp, LOCK_UN); - fclose($fp); - - if (!function_exists('phpbb_chmod')) - { - include(PHPBB_ROOT_PATH . 'includes/functions.' . PHP_EXT); - } - - phpbb_chmod($this->cache_dir . "data{$var_name}." . PHP_EXT, phpbb::CHMOD_WRITE); - } - } - else - { - $this->vars[$var_name] = $var; - $this->var_expires[$var_name] = time() + $ttl; - $this->is_modified = true; - } - } - - /** - * Purge cache data - */ - public function purge() - { - // Purge all phpbb cache files $dir = @opendir($this->cache_dir); if (!$dir) @@ -218,7 +242,7 @@ class acm while (($entry = readdir($dir)) !== false) { - if (strpos($entry, 'sql_') !== 0 && strpos($entry, 'data_') !== 0 && strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0) + if (strpos($entry, $this->cache_prefix . '_') !== 0 || strpos($entry, $this->cache_prefix . '_global') === 0) { continue; } @@ -226,240 +250,101 @@ class acm $this->remove_file($this->cache_dir . $entry); } closedir($dir); - - unset($this->vars); - unset($this->var_expires); - unset($this->sql_rowset); - - $this->vars = array(); - $this->var_expires = array(); - $this->sql_rowset = array(); - - $this->is_modified = false; } /** - * Destroy cache data + * Get modified date for cache entry + * + * @param string $var_name The cache variable name + * @access public */ - public function destroy($var_name, $table = '') + public function get_modified_date($var_name) { - if ($var_name === 'sql' && !empty($table)) - { - if (!is_array($table)) - { - $table = array($table); - } - - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'sql_') !== 0) - { - continue; - } - - // The following method is more failproof than simply assuming the query is on line 3 (which it should be) - $check_line = @file_get_contents($this->cache_dir . $entry); - - if (empty($check_line)) - { - continue; - } - - // Now get the contents between /* and */ - $check_line = substr($check_line, strpos($check_line, '/* ') + 3, strpos($check_line, ' */') - strpos($check_line, '/* ') - 3); - - $found = false; - foreach ($table as $check_table) - { - // Better catch partial table names than no table names. ;) - if (strpos($check_line, $check_table) !== false) - { - $found = true; - break; - } - } - - if ($found) - { - $this->remove_file($this->cache_dir . $entry); - } - } - closedir($dir); - - return; - } - - if (!$this->_exists($var_name)) - { - return; - } - - if ($var_name[0] === '_') - { - $this->remove_file($this->cache_dir . 'data' . $var_name . '.' . PHP_EXT, true); - } - else if (isset($this->vars[$var_name])) - { - $this->is_modified = true; - unset($this->vars[$var_name]); - unset($this->var_expires[$var_name]); - - // We save here to let the following cache hits succeed - $this->save(); - } + return @filemtime($this->cache_dir . $this->cache_prefix . '_' . $var_name . '.' . PHP_EXT); } /** - * Check if a given cache entry exist + * Removes/unlinks file + * + * @param string $filename The filename to remove + * @param bool $check If true the cache directory is checked for correct directory permissions. + * @access protected */ - private function _exists($var_name) + protected function remove_file($filename, $check = false) { - if ($var_name[0] === '_') + if ($check && !@is_writable($this->cache_dir)) { - return file_exists($this->cache_dir . 'data' . $var_name . '.' . PHP_EXT); + // 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); } - else - { - if (!sizeof($this->vars)) - { - $this->load(); - } - - if (!isset($this->var_expires[$var_name])) - { - return false; - } - return (time() > $this->var_expires[$var_name]) ? false : isset($this->vars[$var_name]); - } + return @unlink($filename); } +} +/** +* Special implementation for cache type 'sql' +* @package acm +*/ +class phpbb_acm_file_sql extends phpbb_acm_file +{ /** - * Load cached sql query + * {@link phpbb_acm_abstract::destroy() destroy()} */ - public function sql_load($query) + public function destroy($var_name) { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $query_id = sizeof($this->sql_rowset); - - if (!file_exists($this->cache_dir . 'sql_' . md5($query) . '.' . PHP_EXT)) + if ($var_name[0] === '#') { - return false; + $var_name = substr($var_name, 1); + $this->destroy_global($var_name); } - @include($this->cache_dir . 'sql_' . md5($query) . '.' . PHP_EXT); + $table = (!is_array($var_name)) ? array($var_name) : $var_name; + $dir = @opendir($this->cache_dir); - if (!isset($expired)) - { - return false; - } - else if ($expired) + if (!$dir) { - $this->remove_file($this->cache_dir . 'sql_' . md5($query) . '.' . PHP_EXT, true); - return false; + return; } - - return $query_id; - } - - /** - * Save sql query - */ - public function sql_save($query, &$query_result, $ttl) - { - global $db; - - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $filename = $this->cache_dir . 'sql_' . md5($query) . '.' . PHP_EXT; - - if ($fp = @fopen($filename, 'wb')) + while (($entry = readdir($dir)) !== false) { - @flock($fp, LOCK_EX); - - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = array(); - - while ($row = $db->sql_fetchrow($query_result)) + if (strpos($entry, $this->cache_prefix . '_') !== 0) { - $this->sql_rowset[$query_id][] = $row; + continue; } - $db->sql_freeresult($query_result); - $file = "<?php\n/* " . str_replace('*/', '*\/', $query) . " */"; - $file .= "\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n"; - - fwrite($fp, $file . "\$this->sql_rowset[\$query_id] = " . (sizeof($this->sql_rowset[$query_id]) ? "unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");" : 'array();')); - @flock($fp, LOCK_UN); - fclose($fp); + // The following method is more failproof than simply assuming the query is on line 3 (which it should be) + @include($this->cache_dir . $entry); - if (!function_exists('phpbb_chmod')) + if (empty($data)) { - include(PHPBB_ROOT_PATH . 'includes/functions.' . PHP_EXT); + $this->remove_file($this->cache_dir . $entry); + continue; } - phpbb_chmod($filename, phpbb::CHMOD_WRITE); - - $query_result = $query_id; - } - } - - /** - * Fetch row from cache (database) - */ - public function sql_fetchrow($query_id) - { - list(, $row) = each($this->sql_rowset[$query_id]); - - return ($row !== NULL) ? $row : false; - } - - /** - * Fetch a field from the current row of a cached database result (database) - */ - public function sql_fetchfield($query_id, $field) - { - $row = current($this->sql_rowset[$query_id]); - - return ($row !== false && isset($row[$field])) ? $row[$field] : false; - } - - /** - * Free memory used for a cached database result (database) - */ - public function sql_freeresult($query_id) - { - if (!isset($this->sql_rowset[$query_id])) - { - return false; - } + // Get the query + $data = $data['query']; - unset($this->sql_rowset[$query_id]); - - return true; - } + $found = false; + foreach ($table as $check_table) + { + // Better catch partial table names than no table names. ;) + if (strpos($data, $check_table) !== false) + { + $found = true; + break; + } + } - /** - * Removes/unlinks file - */ - private 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); + if ($found) + { + $this->remove_file($this->cache_dir . $entry); + } } + closedir($dir); - return @unlink($filename); + return; } } |