phpBB

Code Changes

File: includes/acm/acm_file.php

  Unmodified   Added   Modified   Removed
Line 3Line 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 44Line 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 86Line 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);
}





			@chmod($this->cache_dir . 'data_global.' . $phpEx, 0666);
}
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 122Line 112
		{
return;
}

		{
return;
}

 

$time = time();


while (($entry = readdir($dir)) !== false)
{


while (($entry = readdir($dir)) !== false)
{

Line 130Line 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 148Line 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 172Line 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 188Line 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 = " . var_export($var, true) . ";\n?>");
@flock($fp, LOCK_UN);
fclose($fp);

@chmod($this->cache_dir . "data{$var_name}.$phpEx", 0666);
}

			$this->_write('data' . $var_name, $var, time() + $ttl);











		}
else
{

		}
else
{

Line 273Line 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 356Line 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 389Line 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 409Line 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] = " . var_export($this->sql_rowset[$query_id], true) . ";\n?>");
@flock($fp, LOCK_UN);
fclose($fp);

@chmod($filename, 0666);


		if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query))
{








			$query_result = $query_id;
}
}

			$query_result = $query_id;
}
}

Line 450Line 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 484Line 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 491Line 713
	*/
function remove_file($filename, $check = false)
{

	*/
function remove_file($filename, $check = false)
{

		if ($check && !@is_writeable($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);