PHP Classes

File: class.CachedTemplate.php

Recommend this page to a friend!
  Classes of Jesus M. Castagnetto   Generalized CachedTemplate class   class.CachedTemplate.php   Download  
File: class.CachedTemplate.php
Role: ???
Content type: text/plain
Description: The CachedTemplate class (version 1.4)
Class: Generalized CachedTemplate class
General Template Caching class
Author: By
Last change:
Date: 23 years ago
Size: 12,573 bytes
 

Contents

Class file image Download
<?php /* * Class CachedTemplate * by Jesus M. Castagnetto (jmcastagnetto@zkey.com) * (c) 2000-2001. Version 1.4 * License: GPL - http://www.fsf.org/copyleft/gpl.txt * * $Id: class.CachedTemplate.php,v 1.20 2001/02/07 01:27:21 jesus Exp $ * * Description: * This general class implements methods to cache the output to a file. * This would be useful for cases in which a template is used for both, * the static pages in a web site, and pages created from PHP scripts. * In this way we will avoid processing pages that do not change too often. * * This class extends the TemplateAdaptor class which is the one implementing * the interface between the original template class and this class. * * This class assumes that the adaptor class implements the getTemplatesList() * and the init() methods. * * Changes: * 2000/06/10 - Initial release. * 2000/07/17 - Documentation, added support for GET query strings, new release. * 2000/07/18 - Added support for external data validation using timestamp or * md5 hash signatures - not released. * 2000/07/30 - Finally got time to implement a general use of variables and * values when generating cache filenames, GET string support is * a case. * 2000/08/04 - Minor typo in $release var name in _key_in_array() method * 2000/10/06 - Added lock file support to avoid run conditions while * generating a cache file. * 2000/02/06 - Added method to read from a cached file into a variable, to * allow for partial caching of content in a page (or pages) * */ class CachedTemplate extends TemplateAdaptor { var $CACHEDIR = "./cache"; // directory to save cached files var $CACHELENGTH = 30; // length of caching, 30 units. var $TIMEUNIT = "day"; // time unit var $TIMEUNITSARR = array ("sec"=>1, "min"=>60, "hour"=>3600, "day"=>86400); var $USEVARS = false; var $VARSVAL = false; var $USELOCK = true; var $WAITLOCK = 100000; // 100,000 microseconds = 100 ms var $MAXWAITLOCKCYCLES = 20; /******************/ /* public methods */ /******************/ /* the constructor */ function CachedTemplate($cachedir="", $cachelen="", $timeunit="") { if (!empty($cachedir)) $this->set_cache_dir($cachedir); if (!empty($cachelen)) $this->set_cache_length($cachelen); if (!empty($timeunit)) $this->set_time_unit($timeunit); } /* sets the cache directory */ function set_cache_dir($dir) { if (substr($dir,(strlen($dir) - 1), 1) == "/") { $dir = substr($dir,0,-1); } $this->CACHEDIR = $dir; } /* sets the cache time length */ function set_cache_length($length) { $this->CACHELENGTH = $length; } /* sets the unit for measuring the lifetime of the cached file */ function set_time_unit($str) { $this->TIMEUNIT = $this->_is_valid_time_unit($str) ? $str : "day"; } function use_get ($how = "in_name") { $this->use_vars("QUERY_STRING",$how); } /* use var/val pairs when generating caching data */ function use_vars ($vars = "QUERY_STRING", $how = "in_name") { $this->USEVARS = $how; if ($vars == "QUERY_STRING") { $vars = $GLOBALS["QUERY_STRING"]; $this->VARSVAL = $vars; } elseif (is_array($vars)) { $this->VARSVAL = $this->_gen_var_val($vars); } else { $this->VARSVAL = $vars; } } /* write file to cache */ function write_to_cache($content, $datacheck="", $filename="") { if (empty($filename)) $filename = $this->_gen_filename(); // check if we need to store the var/val string in a file if ($this->USEVARS == "store" && !empty($this->VARSVAL)) { $fp = fopen($this->CACHEDIR."/".$filename.".vars", "w"); fwrite($fp,$this->VARSVAL); fclose($fp); } // if there is a lock, some other instance is updating this // file, so there is no need for updating it again if (!$this->mk_lock($filename)) { return true; } // write the contents $fp = fopen($this->CACHEDIR."/".$filename.".cache", "w"); fwrite($fp,$content); fclose($fp); // write the cache control file $timestamp = $this->_mktimestamp(); if (empty($datacheck)) $datacheck = $timestamp; $fp = fopen($this->CACHEDIR."/".$filename.".cntrl", "w"); fwrite($fp, $timestamp.":".$this->CACHELENGTH.":".$this->TIMEUNIT.":".$datacheck); fclose($fp); $this->rm_lock($filename); } /* read cached file */ function read_from_cache($filename="") { if (empty($filename)) $filename = $this->_gen_filename(); if ($this->USELOCK) { $wait_lock_cycles = 0; $max_wait = ($this->MAXWAITLOCKCYCLES * $this->WAITLOCK)/1000; $lockfile = $this->CACHEDIR."/".$filename.".lock"; } if ($this->is_cached($filename)) { // if it is locked, sleep for $WAITLOCK microseconds and try again // and if after $MAXWAITLOCKCYCLES the lock has not been released // produce and error while ($this->is_locked($filename)) { usleep($this->WAITLOCK); $wait_lock_cycles++; if ($wait_lock_cycles > $this->MAXWAITLOCKCYCLES) { $err = "<b>*FATAL ERROR* Cannot read cached file, "; $err .= "lock exists and has not been cleared "; $err .= "after ".$max_wait." milliseconds</b> "; $err .= "(lock file: ".$lockfile.")"; echo $err; return false; } } readfile($this->CACHEDIR."/".$filename.".cache"); return true; } else { return false; } } /* modified from code contributed by M. Casanova */ /* get the contents of the cached file into a variable*/ function get_from_cache($filename="") { if (empty($filename)) $filename = $this->_gen_filename(); if ($this->USELOCK) { $wait_lock_cycles = 0; $max_wait = ($this->MAXWAITLOCKCYCLES * $this->WAITLOCK)/1000; $lockfile = $this->CACHEDIR."/".$filename.".lock"; } // if it is locked, sleep for $WAITLOCK microseconds and try again // and if after $MAXWAITLOCKCYCLES the lock has not been released // produce and error while ($this->is_locked($filename)) { usleep($this->WAITLOCK); $wait_lock_cycles++; if ($wait_lock_cycles > $this->MAXWAITLOCKCYCLES) { $err = "<b>*FATAL ERROR* Cannot read cached file, "; $err .= "lock exists and has not been cleared "; $err .= "after ".$max_wait." milliseconds</b> "; $err .= "(lock file: ".$lockfile.")"; echo $err; return ""; } } if ($this->is_cached($filename)) { return implode('',file($this->CACHEDIR."/".$filename.".cache")); } else { return ""; } } /* if a file is in cache */ function is_cached($filename) { $files_exist = is_file($this->CACHEDIR."/".$filename.".cache") && is_file($this->CACHEDIR."/".$filename.".cntrl"); if ($this->USEVARS == "store" && !empty($this->VARSVAL)) $files_exist = $files_exist && is_file($this->CACHEDIR."/".$filename.".vars"); return $files_exist; } /* if a cached file is a valid one */ function valid_cache_file($filename="") { if (empty($filename)) $filename = $this->_gen_filename(); // if we are using variables stored as a url query string, compare them if ($this->USEVARS == "store" && is_file($this->CACHEDIR."/".$filename.".vars") ) { $stored_qstr = implode("", file($this->CACHEDIR."/".$filename.".vars")); if ($this->VARSVAL != $stored_qstr) return false; } // look at the included template files if ($this->is_cached($filename)) { $info = file($this->CACHEDIR."/".$filename.".cntrl"); //$val array: 0 = timestamp, 1 = cache length, 2 = time unit $val = explode(":", $info[0]); // check if we got a valid time unit if (!$this->_is_valid_time_unit($val[2])) return false; // check fileHandles time vs. control time if (filemtime($GLOBALS["PATH_TRANSLATED"]) >= $val[0]) return false; // the TemplateAdaptor class needs to implement the method below $tpls = $this->getTemplatesList(); if (count($tpls) > 0 ) { while (list($index, $fn) = each($tpls)) { if ( is_file($fn) && (filemtime($fn) >= $val[0]) ) return false; } } // end check fileHandles $today = $this->_mktimestamp(); return ( $this->_diff_time($today, $val[0], $val[2]) <= $val[1]); } else { return false; } } /* to check if the data is stale */ function is_data_valid ($datacheck, $type="timestamp", $filename="") { if (empty($filename)) $filename = $this->_gen_filename(); $fpath = $this->CACHEDIR."/".$filename; if (!is_file($fpath.".cntrl")) return false; $info = file($fpath.".cntrl"); // Description // $val array: 0 = timestamp, 1 = cache length, // 2 = time unit, 3 = data check value list($ts, $cl, $tu, $cached_dcheck) = explode(":", $info[0]); if ($type == "timestamp") { return ($datacheck <= $cached_dcheck); } elseif ($type == "md5") { return ($datacheck == $cached_dcheck); } else { return false; } } /* methods to handle cache file locking */ /* set or unset the locking mechanism */ function set_use_lock () { $this->USELOCK = true; } function unset_use_lock () { $this->USELOCK = false; } /* check is lock file exists */ function is_locked ($filename) { $lockfile = $this->CACHEDIR."/".$filename.".lock"; return ($this->USELOCK && file_exists($lockfile) && is_file($lockfile) ); } /* create a lock file */ function mk_lock ($filename) { if ($this->is_locked($filename)) { return false; } else { $lockfile = $this->CACHEDIR."/".$filename.".lock"; return touch($lockfile); } } /* remove the lock file */ function rm_lock ($filename) { if ($this->is_locked($filename)) { $lockfile = $this->CACHEDIR."/".$filename.".lock"; return unlink($lockfile); } else { return false; } } /* for benchmarking, idea ripped off shamelessly from CDI's FastTemplate */ function utime () { list($usec, $sec) = explode( " ", microtime()); return (double)$sec + (double)$usec; } /*******************/ /* private methods */ /*******************/ /* generate var/val pairs in QUERY_STRING form */ function _gen_var_val ($vars) { while (list($k,$v) = each($vars)) $out[] = $k."=".rawurlencode($v); return implode("&",$out); } /* generates a unique filename based on the file to be cached */ function _gen_filename () { $filename = str_replace("/", "_", $GLOBALS["PHP_SELF"]); if ($this->USEVARS == "in_name" && !empty($this->VARSVAL)) $filename .= rawurlencode($this->VARSVAL); return $filename; } // To support old PHP3 versions ( older than 3.0.12 ) function _key_in_array($element, $arr) { // figure out version list($major, $minor, $release) = explode(".", phpversion()); if (($major == 3 && $minor == 0 && $release >= 12) || $major == 4) { return in_array($element, array_keys($arr)); } else { // assumes that we want to compare element value while (list($key, $val) = each($arr)) { if ($key == $element) return true; } return false; } } function _is_valid_time_unit($str) { return $this->_key_in_array($str, $this->TIMEUNITSARR); } function _mktimestamp() { return time(); } function _diff_time($end, $start, $timeunit="day") { $factor = $this->TIMEUNITSARR[$timeunit]; return intval(($end - $start)/$factor); } } // end of class definition ?>