Line 3 | Line 3 |
---|
* * @package acm * @version $Id$
|
* * @package acm * @version $Id$
|
* @copyright (c) 2005 phpBB Group
| * @copyright (c) 2005, 2009 phpBB Group
|
* @license http://opensource.org/licenses/gpl-license.php GNU Public License * */
| * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */
|
Line 44 | Line 44 |
---|
*/ function load() {
|
*/ function load() {
|
global $phpEx; if (file_exists($this->cache_dir . 'data_global.' . $phpEx)) { @include($this->cache_dir . 'data_global.' . $phpEx); } else { return false; }
return true;
| return $this->_read('data_global');
|
}
/**
| }
/**
|
Line 86 | Line 76 |
---|
global $phpEx;
|
global $phpEx;
|
if ($fp = @fopen($this->cache_dir . 'data_global.' . $phpEx, 'wb'))
| if (!$this->_write('data_global'))
|
{
|
{
|
@flock($fp, LOCK_EX); fwrite($fp, "<?php\n\$this->vars = " . var_export($this->vars, true) . ";\n\n\$this->var_expires = " . var_export($this->var_expires, true) . "\n?>"); @flock($fp, LOCK_UN); fclose($fp);
| if (!function_exists('phpbb_is_writable')) { global $phpbb_root_path; include($phpbb_root_path . 'includes/functions.' . $phpEx); }
|
|
|
phpbb_chmod($this->cache_dir . 'data_global.' . $phpEx, CHMOD_WRITE); } else {
| |
// Now, this occurred how often? ... phew, just tell the user then...
|
// Now, this occurred how often? ... phew, just tell the user then...
|
if (!@is_writable($this->cache_dir))
| if (!phpbb_is_writable($this->cache_dir))
|
{
|
{
|
trigger_error($this->cache_dir . ' is NOT writable.', E_USER_ERROR);
| // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload()) die('Fatal: ' . $this->cache_dir . ' is NOT writable.'); exit;
|
}
|
}
|
trigger_error('Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx, E_USER_ERROR);
| die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx); exit;
|
}
$this->is_modified = false;
| }
$this->is_modified = false;
|
Line 122 | Line 112 |
---|
{ return; }
|
{ return; }
|
| $time = time();
|
while (($entry = readdir($dir)) !== false) {
| while (($entry = readdir($dir)) !== false) {
|
Line 130 | Line 122 |
---|
continue; }
|
continue; }
|
$expired = true; @include($this->cache_dir . $entry); if ($expired)
| if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) { continue; }
// Skip the PHP header fgets($handle);
// Skip expiration $expires = (int) fgets($handle);
fclose($handle);
if ($time >= $expires)
|
{ $this->remove_file($this->cache_dir . $entry); }
| { $this->remove_file($this->cache_dir . $entry); }
|
Line 148 | Line 151 |
---|
foreach ($this->var_expires as $var_name => $expires) {
|
foreach ($this->var_expires as $var_name => $expires) {
|
if (time() > $expires)
| if ($time >= $expires)
|
{ $this->destroy($var_name); }
| { $this->destroy($var_name); }
|
Line 172 | Line 175 |
---|
return false; }
|
return false; }
|
@include($this->cache_dir . "data{$var_name}.$phpEx"); return (isset($data)) ? $data : false;
| return $this->_read('data' . $var_name);
|
} else {
| } else {
|
Line 188 | Line 190 |
---|
{ if ($var_name[0] == '_') {
|
{ if ($var_name[0] == '_') {
|
global $phpEx;
if ($fp = @fopen($this->cache_dir . "data{$var_name}.$phpEx", 'wb')) { @flock($fp, LOCK_EX); fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$data = unserialize(" . var_export(serialize($var), true) . ");\n\n?>"); @flock($fp, LOCK_UN); fclose($fp);
phpbb_chmod($this->cache_dir . "data{$var_name}.$phpEx", CHMOD_WRITE); }
| $this->_write('data' . $var_name, $var, time() + $ttl);
|
} else {
| } else {
|
Line 273 | Line 265 |
---|
continue; }
|
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))
| if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
|
{ continue; }
|
{ continue; }
|
// Now get the contents between /* and */ $check_line = substr($check_line, strpos($check_line, '/* ') + 3, strpos($check_line, ' */') - strpos($check_line, '/* ') - 3);
| // Skip the PHP header fgets($handle);
// Skip expiration fgets($handle);
// Grab the query, remove the LF $query = substr(fgets($handle), 0, -1);
fclose($handle);
|
|
|
$found = false;
| |
foreach ($table as $check_table) { // Better catch partial table names than no table names. ;)
|
foreach ($table as $check_table) { // Better catch partial table names than no table names. ;)
|
if (strpos($check_line, $check_table) !== false)
| if (strpos($query, $check_table) !== false)
|
{
|
{
|
$found = true;
| $this->remove_file($this->cache_dir . $entry);
|
break; }
|
break; }
|
}
if ($found) { $this->remove_file($this->cache_dir . $entry);
| |
} } closedir($dir);
| } } closedir($dir);
|
Line 356 | Line 347 |
---|
*/ function sql_load($query) {
|
*/ function sql_load($query) {
|
global $phpEx;
| |
// Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
// 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) . ".$phpEx"))
| if (($rowset = $this->_read('sql_' . md5($query))) === false)
|
{ return false; }
|
{ return false; }
|
@include($this->cache_dir . 'sql_' . md5($query) . ".$phpEx");
if (!isset($expired)) { return false; } else if ($expired) { $this->remove_file($this->cache_dir . 'sql_' . md5($query) . ".$phpEx", true); return false; }
| $query_id = sizeof($this->sql_rowset); $this->sql_rowset[$query_id] = $rowset;
|
$this->sql_row_pointer[$query_id] = 0;
return $query_id;
| $this->sql_row_pointer[$query_id] = 0;
return $query_id;
|
Line 389 | Line 367 |
---|
*/ function sql_save($query, &$query_result, $ttl) {
|
*/ function sql_save($query, &$query_result, $ttl) {
|
global $db, $phpEx;
| global $db;
|
// Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
// Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
$filename = $this->cache_dir . 'sql_' . md5($query) . '.' . $phpEx;
if ($fp = @fopen($filename, 'wb')) { @flock($fp, LOCK_EX);
| |
$query_id = sizeof($this->sql_rowset); $this->sql_rowset[$query_id] = array();
| $query_id = sizeof($this->sql_rowset); $this->sql_rowset[$query_id] = array();
|
Line 409 | Line 382 |
---|
} $db->sql_freeresult($query_result);
|
} $db->sql_freeresult($query_result);
|
$file = "<?php\n\n/* " . str_replace('*/', '*\/', $query) . " */\n"; $file .= "\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n";
fwrite($fp, $file . "\n\$this->sql_rowset[\$query_id] = unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");\n\n?>"); @flock($fp, LOCK_UN); fclose($fp);
phpbb_chmod($filename, CHMOD_WRITE);
| if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query)) {
|
$query_result = $query_id; } }
| $query_result = $query_id; } }
|
Line 450 | Line 416 |
---|
{ if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) {
|
{ if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) {
|
return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field] : false;
| return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false;
|
}
return false;
| }
return false;
|
Line 484 | Line 450 |
---|
unset($this->sql_row_pointer[$query_id]);
return true;
|
unset($this->sql_row_pointer[$query_id]);
return true;
|
| }
/** * Read cached data from a specified file * * @access private * @param string $filename Filename to write * @return mixed False if an error was encountered, otherwise the data type of the cached data */ function _read($filename) { global $phpEx;
$file = "{$this->cache_dir}$filename.$phpEx";
$type = substr($filename, 0, strpos($filename, '_'));
if (!file_exists($file)) { return false; }
if (!($handle = @fopen($file, 'rb'))) { return false; }
// Skip the PHP header fgets($handle);
if ($filename == 'data_global') { $this->vars = $this->var_expires = array();
$time = time();
while (($expires = (int) fgets($handle)) && !feof($handle)) { // Number of bytes of data $bytes = substr(fgets($handle), 0, -1);
if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0) { // We cannot process the file without a valid number of bytes // so we discard it fclose($handle);
$this->vars = $this->var_expires = array(); $this->is_modified = false;
$this->remove_file($file);
return false; }
if ($time >= $expires) { fseek($handle, $bytes, SEEK_CUR);
continue; }
$var_name = substr(fgets($handle), 0, -1);
// Read the length of bytes that consists of data. $data = fread($handle, $bytes - strlen($var_name)); $data = @unserialize($data);
// Don't use the data if it was invalid if ($data !== false) { $this->vars[$var_name] = $data; $this->var_expires[$var_name] = $expires; }
// Absorb the LF fgets($handle); }
fclose($handle);
$this->is_modified = false;
return true; } else { $data = false; $line = 0;
while (($buffer = fgets($handle)) && !feof($handle)) { $buffer = substr($buffer, 0, -1); // Remove the LF
// $buffer is only used to read integers // if it is non numeric we have an invalid // cache file, which we will now remove. if (!is_numeric($buffer)) { break; }
if ($line == 0) { $expires = (int) $buffer;
if (time() >= $expires) { break; }
if ($type == 'sql') { // Skip the query fgets($handle); } } else if ($line == 1) { $bytes = (int) $buffer;
// Never should have 0 bytes if (!$bytes) { break; }
// Grab the serialized data $data = fread($handle, $bytes);
// Read 1 byte, to trigger EOF fread($handle, 1);
if (!feof($handle)) { // Somebody tampered with our data $data = false; } break; } else { // Something went wrong break; } $line++; } fclose($handle);
// unserialize if we got some data $data = ($data !== false) ? @unserialize($data) : $data;
if ($data === false) { $this->remove_file($file); return false; }
return $data; } }
/** * Write cache data to a specified file * * 'data_global' is a special case and the generated format is different for this file: * <code> * <?php exit; ?> * (expiration) * (length of var and serialised data) * (var) * (serialised data) * ... (repeat) * </code> * * The other files have a similar format: * <code> * <?php exit; ?> * (expiration) * (query) [SQL files only] * (length of serialised data) * (serialised data) * </code> * * @access private * @param string $filename Filename to write * @param mixed $data Data to store * @param int $expires Timestamp when the data expires * @param string $query Query when caching SQL queries * @return bool True if the file was successfully created, otherwise false */ function _write($filename, $data = null, $expires = 0, $query = '') { global $phpEx;
$file = "{$this->cache_dir}$filename.$phpEx";
if ($handle = @fopen($file, 'wb')) { @flock($handle, LOCK_EX);
// File header fwrite($handle, '<' . '?php exit; ?' . '>');
if ($filename == 'data_global') { // Global data is a different format foreach ($this->vars as $var => $data) { if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) { // CR/LF would cause fgets() to read the cache file incorrectly // do not cache test entries, they probably won't be read back // the cache keys should really be alphanumeric with a few symbols. continue; } $data = serialize($data);
// Write out the expiration time fwrite($handle, "\n" . $this->var_expires[$var] . "\n");
// Length of the remaining data for this var (ignoring two LF's) fwrite($handle, strlen($data . $var) . "\n"); fwrite($handle, $var . "\n"); fwrite($handle, $data); } } else { fwrite($handle, "\n" . $expires . "\n");
if (strpos($filename, 'sql_') === 0) { fwrite($handle, $query . "\n"); } $data = serialize($data);
fwrite($handle, strlen($data) . "\n"); fwrite($handle, $data); }
@flock($handle, LOCK_UN); fclose($handle);
if (!function_exists('phpbb_chmod')) { global $phpbb_root_path; include($phpbb_root_path . 'includes/functions.' . $phpEx); }
phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE);
return true; }
return false;
|
}
/**
| }
/**
|
Line 491 | Line 713 |
---|
*/ function remove_file($filename, $check = false) {
|
*/ function remove_file($filename, $check = false) {
|
if ($check && !@is_writable($this->cache_dir))
| if (!function_exists('phpbb_is_writable')) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/functions.' . $phpEx); }
if ($check && !phpbb_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);
| { // 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);
|