Here's my simple caching class for the forum software i'm writing. No comments yet - i'll add those tomorrow morning.
I'll add auto serialization/unserialization of arrays then too.
<?
// Class to cache data/queries etc.
class Cache
{
var $cache_folder = "resources/caches/";
var $validate_cache_data = true;
var $cache_add_buffer = array();
var $cache_count = 0;
var $cache_file_handle = false;
function begin()
{
$this->cache_add_buffer = array();
$this->cache_count = 0;
$this->cache_file_handle = false;
}
function get($id)
{
$cache_file = $this->path($id);
if(!file_exists($cache_file)) {
return false;
}
$this->open($cache_file, "r");
flock($this->cache_handle, LOCK_SH);
$cache_file_contents = fread($this->cache_handle, filesize($cache_file));
flock($this->cache_handle, LOCK_UN);
fclose($this->cache_handle);
eval($cache_file_contents);
if($cachedata['expirytime'] <= time()) {
$this->remove($id);
return false;
}
return $cachedata;
}
function path($id)
{
return $this->cache_folder . $id . ".cache.php";
}
function remove($id)
{
$path_to_file = $this->path($id);
if(unlink($path_to_file) === TRUE) {
return true;
} else {
$this->cacheerror($path_to_file);
}
}
function open($path, $mode)
{
$attempt_count = 0;
while($this->cache_handle === FALSE || $attempt_count == 0) {
if($attempt_count != 0) {
sleep(1);
}
if($attempt_count == 6) {
if($mode == "w") {
$this->cacheerror("WRITE", $file_to_write);
} elseif($mode == "r") {
$this->cacheerror("READ", $file_to_write);
}
die("Unknown cache error");
break;
} else {
$this->cache_handle = fopen($path, $mode);
$attempt_count++;
}
}
}
function do_save($life, $id)
{
$file_to_write = $this->path($id);
if(!is_writable($this->cache_folder)) {
$this->cacheError("WRITE", $this->cache_folder);
return 0;
}
else {
$this->open($file_to_write, "w");
flock($this->cache_handle, LOCK_EX);
$cache_file_expirytime = time() + $life;
$cache_file_data = $this->constructphp($this->cache_add_buffer, $cache_file_expirytime);
if(fwrite($this->cache_handle, $cache_file_data) === FALSE) {
$this->cacheError("WRITE", $file_to_write);
return 0;
}
flock($this->cache_handle, LOCK_UN);
fclose($this->cache_handle);
return $cache_file_data;
}
}
function save($life, $id)
{
$hash = $this->do_save($life, $id);
if($this->validate_cache_data == true) {
while($this->comparehash($id, $hash) === FALSE && $retry_count < 6) {
sleep(1);
$hash = $this->do_save($life, $id);
$retry_count++;
if($retry_count == 6) {
$this->cacheerror("HASH", $this->path($id));
}
}
}
}
function comparehash($id, $compareto)
{
$hash_written = $this->get_file_md5($id);
$hash_intended = md5($compareto);
if($hash_written == $hash_intended) {
return true;
}
else {
return false;
}
}
function get_file_md5($id)
{
$file_path = $this->path($id);
if(!file_exists($file_path)) {
return false;
}
$file_buffer = implode("", file($file_path));
return md5($file_buffer);
}
function setoption($option, $value)
{
if($option == "cachefolder") {
$this->cache_folder = $value;
} elseif($option == "validate") {
$this->validate_cache_data = $value;
}
}
function assign($data, $varname)
{
for($i = 0; $i < $this->cache_count; $i++) {
if($this->cache_add_buffer[$i]['variable_name'] == $varname) {
return false;
}
}
$this->cache_add_buffer[$this->cache_count]['variable_name'] = $varname;
$this->cache_add_buffer[$this->cache_count]['cache_data'] = $data;
$this->cache_count++;
return $this->cache_count;
}
function constructphp($contents_array, $expirytime)
{
$file_data = "\$cachedata['expirytime'] = \"" . $expirytime . "\";\n";
for($i = 0; $i < $this->cache_count; $i++) {
$file_data .= "\$cachedata['" .$contents_array[$i]['variable_name']. "'] = \"" .$contents_array[$i]['cache_data']. "\";\n";
}
return $file_data;
}
function cacheerror($error, $optionalinfo = null)
{
echo "<center>";
echo "<br /><b><u>Cache Error</u></b><br /><br />";
if($error == "WRITE") {
echo "Could not write to <i>" . $optionalinfo . "</i>. ";
} elseif($error == "READ") {
echo "Could not read from <i>" . $optionalinfo . "</i>. ";
} elseif($error == "HASH") {
echo "Data verification failed for <i>" .$optionalinfo ."</i>. ";
}
echo "The script will now quit.";
echo "</center>";
die();
}
}
?>
You use it like:
<?
require('resources/classes/cache.class');
$mycache = new Cache;
// Grab the variables for sample_cache_session. Returns false if this session has expired/doesn't exist.
//Returns an associative array with [var_name] if it does.
if($cache_data = $mycache->get("sample_cache_session")) {
$mystring = $cache_data['my_cached_string'];
} else {
$data_to_cache = $somedb->query("for data"); // Sample query (or anything you want)
$mycache->begin();
$mycache->assign($data_to_cache, "my_cached_string"); // You can assign as many as your server load/disk space can cope with!
$mycache->save(30, "sample_cache_session"); // Write the data to disk
//\ use sample_cache_session to identify our group of assigned variables (or in this case, one). Make the cache expire in 30 seconds.
$mystring = $data_to_cache;
}
echo "Data: " .$mystring;
?>
Designed to be small, efficient and easy to use.
Anybody got any suggestions?