includes/cache.php
author Dan Fuhry <dan@enanocms.org>
Mon, 28 Jun 2010 10:43:04 -0400
changeset 1253 13f8d373da67
parent 1227 bdac73ed481e
child 1365 a52cac1b190d
permissions -rw-r--r--
SECURITY: Multiple XSS in Special:ChangeStyle. Reported by Mesut Timur of Mavituna Security - thanks! Also removed my stand-in for ucfirst().

<?php

/*
 * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
 * Copyright (C) 2006-2009 Dan Fuhry
 *
 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
 */
 
/**
 * Framework for caching arbitrary data around the site.
 * @package Enano
 * @subpackage Core
 * @author Dan Fuhry <dan@enanocms.org>
 * @license GNU General Public License
 */

class CacheManager
{
	/**
 	* Fetch a cached piece of data.
 	* @param string Cache ID. The timestamp is checked automatically.
 	*/
	
	public function fetch($cache_id)
	{
		if ( !preg_match('/^[a-z0-9_]+$/', $cache_id) )
		{
			throw new Exception('Cache ID must be letters, numbers, and underscores.');
		}
		$cache_file = ENANO_ROOT . "/cache/cache_$cache_id.php";
		if ( file_exists($cache_file) )
		{
			require($cache_file);
			if ( isset($_cache_data) && isset($_cache_ttl) && isset($_cache_timestamp) )
			{
				$cache_expire = $_cache_timestamp + ( 60 * $_cache_ttl);
				if ( $cache_expire >= time() || $_cache_ttl === -1 )
				{
					return $_cache_data;
				}
			}
		}
		return false;
	}
	
	/**
 	* Stores an array by var_export()ing it and saving it to disk.
 	* @param string Cache ID - human readable name for this store (letters, numbers, underscores)
 	* @param array Data to store
 	* @param int TTL for the cached array, in minutes. Defaults to 20. If set to -1, caches indefinitely.
 	* @return bool True on success, false on failure
 	*/
	
	public function store($cache_id, $data, $ttl = 20)
	{
		if ( getConfig('cache_thumbs') != '1' )
		{
			// caching disabled
			return false;
		}
		if ( !preg_match('/^[a-z0-9_]+$/', $cache_id) )
		{
			throw new Exception('Cache ID must be letters, numbers, and underscores.');
		}
		if ( !is_int($ttl) )
		{
			throw new Exception('TTL must be an integer');
		}
		
		$cache_file = ENANO_ROOT . "/cache/cache_$cache_id.php";
		if ( file_exists($cache_file) )
		{
			@unlink($cache_file);
		}
		$fh = @fopen($cache_file, 'w');
		if ( !$fh )
		{
			throw new Exception('Failed to open file for writing.');
		}
		$exported = Language::var_export_string($data);
		$now = time();
		$content = <<<EOF
<?php
/**
 * Automatically generated cache file.
 * Do not edit this file as it will expire and be overwritten $ttl minutes from its creation.
 */

\$_cache_ttl = $ttl;
\$_cache_timestamp = $now;
\$_cache_data = $exported;

EOF;
		fwrite($fh, $content);
		fclose($fh);
		
		return true;
	}
	
	/**
 	* Deletes a cached item.
 	* @param string Cache ID.
 	* @return bool true on success or if item doesn't exist, false on failure
 	*/
	
	public function purge($cache_id)
	{
		if ( !preg_match('/^[a-z0-9_]+$/', $cache_id) )
		{
			throw new Exception('Cache ID must be letters, numbers, and underscores.');
		}
		
		$cache_file = ENANO_ROOT . "/cache/cache_$cache_id.php";
		if ( file_exists($cache_file) )
		{
			if ( unlink($cache_file) )
			{
				return true;
			}
			return false;
		}
		return true;
	}
}