Current File : //opt/RZphp56/includes/HTML/Template/Xipe/Cache.php |
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Wolfram Kriesing <wolfram@kriesing.de> |
// +----------------------------------------------------------------------+
// $Id: Cache.php,v 1.8 2003/03/04 18:52:33 cain Exp $
//
require_once 'HTML/Template/Xipe/XMLConfig.php';
/**
* this class does the caching of final pages in pure html (or anything you use it for)
* ok first an apology to the PEAR::Cache-team :-) i tried to
* use the PEAR::Cache and it worked fine (was easy to implement) until i got to the
* point that i wanted to include the cached content,
* since the philosophy of this template engine is still based
* on including either the template or the cached output.
* the PEAR::Cache has a wonderful Cache implementation but
* what i need here is the final file and there are 2 things that
* make it impossible (or would need a change in the concept of this template engine) to
* use the PEAR::Cache
* 1. PEAR::Cache saves the file encoded and adds extra stuff in the file not only
* the actual result, the html page in the normal case
* it always has the expiration data and extra user data saved in the
* cached file, and additionally the real data are encoded either bbase64
* or serialized, which means a simple include of the cached file is not possible
* i would have to decode it first etc.
* 2. PEAR::Cache doesnt provide a method to give back the full path and filename of the
* cached file, it does always only return the content of it
* which of course is right for the way PEAR::Cache works, since the
* data have to be decoded
* so i have to implement the caching my self :-/
*
* to use the cache u have to set the option 'enable-Cache' to true
* when making an instance of the template engine
* and in the file that shall be cached do the following
* (assuming $tpl is an instance of the template engine with the cache option on):
*
* // before calling '$tpl->isCached()' be sure that all the variables
* // that the cache-file depends on (see your xml config) are set to the proper values
* // so the cahe methods can properly determine if the file is already cached
* // BE WARNED: letting a cache-file depend on i.e. $_REQUEST makes it possible to
* // run a DOS-attack, since a new cache file has to be created everytime any
* // request parameter changes, i.e. http://your.site.com/index.php?whatever
* // this might flood your webservers diskspace
* $myTplFile = 'your/template/file.tpl';
* if( !$tpl->isCached( $myTplFile ) )
* {
* do all the stuff needed to be done to build a cacheable page
* all the time consuming stuff, like db-requests, or getting data
* using a webservice (which was my actual need for caching)
* }
* // simply include the file as usual
* $tpl->compile( $myTplFile );
* include( $tpl->getCompiledTemplate() );
*
*
* @package HTML_Template_Xipe
* @author Wolfram Kriesing <wolfram@kriesing.de>
*/
class HTML_Template_Xipe_Cache extends HTML_Template_Xipe_XMLConfig
{
/**
* @var string the complete filename including path to the cached file
*/
var $_cachedFile = '';
/**
* @var string the global object reference name
*/
var $_cacheObjReference = '';
/**
* this can be set to true using forceRecache()
* and it will rebuild the cached file, no matter if it is already cached
* @see forceRecache()
*/
var $_forceRecache = false;
/**
* checks if the file is cached
*
* @access public
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return boolean returns true if the output is cached, false otherwise
*/
function isCached()
{
if ($this->getOption('cache','time')===false) {
return false;
}
// lets make sure that we define the object reference globally, which is called
// from within the template
// if we wouldnt do this here we would have a problem if a compiled template
// would be included but the reference to $this is not defined, which is needed to call _cacheEnd()
// at the end of the template
$this->_createCacheObjRef();
// check the forceRecache after creating the cacheObjRef, so the
// template can access it
if ($this->_forceRecache) { // if _forceRecache is true we say the file is not cached
return false;
}
$cacheFile = $this->_getCacheFileName();
if (!file_exists($cacheFile)) { // if the cached file doesnt exist
$this->_log('CACHE: cached file doenst exist: '.$cacheFile);
return false;
}
// has the cached file expired?
// the filetime is the time when it expires, this way we dont have to save the
// caching time anywhere
if (time()>filemtime($cacheFile)) {
// if the caching time is 0 it shall be cached forever, so set the expire time to one year ahead
// again
if ($this->getOption('cache','time')===0) {
touch( $cacheFile , time()+60*60*24*365 );
return true;
}
$this->_log('CACHE: cached file has expired: '.$cacheFile);
return false;
}
// if the template needs a recompile we dont cache
if ($this->_needsRecompile()) {
$this->_log('CACHE: template needs recompile');
// remove the cached file so we know that we will recreate it
// i am doing this because getCompiledTemplate() would return the old cached filename
// also if the tpl was recompiled, because after compilation, needsRecompile is false and the cached file
// does also exists, only that the expiration time might have changed, which getCompileTemplate, which calls
// isCached, has no chance to notice
@unlink($cacheFile);
return false;
}
return true;
}
/**
* tell the engine to rebuild the cached file
*
* @access public
* @version 03/03/04
* @author Wolfram Kriesing <wolfram@kriesing.de>
*/
function forceRecache()
{
$this->_forceRecache = true;
}
/**
* get the filename of the destination file
*
* @access public
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return string returns the complete filename
*/
function _getCacheFileName()
{
if ($this->_cachedFile) {
return $this->_cachedFile;
}
// add the hash which is calculated over the dependency data, like $_REQUEST, to have a unique filename
// for the different dependency data
$extension = '';
if (($depends = $this->getOption('cache','depends'))) {
//print $depends;
$depends = explode(' ',$depends);
// init $vars with the names that shall be cached, to be sure that if the values dont change but the names
// we have to create a new name
$vars = $depends;
foreach ($depends as $aDepend) {
// if the variable name is like $var['varName'] do only globalize '$var'
// even though things like _REQUEST,_SESSION, etc. dont need to be globalized - but it does no harm either
// and if it is a $class-> globalize only $class
$globalize = preg_replace('/\[.*\]/','',$aDepend);
$globalize = preg_replace('/->.*/','',$globalize);
// serilaize the var since it might also be an array or object, or whatever
//print("global $globalize;\$var = serialize($aDepend);<br>");
eval("global $globalize;\$var = serialize($aDepend);");
//print("$aDepend = $var<br>");
//print $this->_templateFile." ... $var<br>";
$vars = md5("$vars:$var");
}
$extension = md5($vars).'.';
}
//print "extension=$extension<br>depends = ";print_r($depends);
$cacheFileName = $this->_compiledFilePrefix.$extension.$this->getOption('cacheFileExtension');
$this->_cachedFile = $cacheFileName;
return $this->_cachedFile;
}
/**
* this is called from within the template to write the content that shall be cached
*
* @access public
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
*/
function _cacheEnd()
{
$content = ob_get_contents();
// get the destination filename
$file = $this->_getCacheFileName();
//print '_cacheEnd write into: '.$file.' <br><br>';
if (file_exists($file)) {
unlink($file);
}
if (($cfp = fopen( $file , 'w' ))) {
if ($this->getOption('debug')>0) {
fwrite($cfp,'CACHED CONTENT<br>'.$content);
} else {
fwrite($cfp,$content);
}
fclose($cfp);
chmod($file,0777);
}
// set file modification time to the time when it expires,
// this saves us the checking of the config data, either in options array or the xml file
$expires = time()+$this->getOption('cache','time');
if ($this->getOption('cache','time')===0) { // if the caching time is 0 set it to one year ahead
$expires = time()+60*60*24*365;
}
touch($file,$expires);
$this->_log('CACHE: caching file for '.$this->getOption('cache','time').' seconds (0 means forever), until: '.
date( 'd.m.Y H:i:s' , $expires ));
ob_end_flush();
}
/**
* this adds the calls to the template needed for caching this file
* it is used as a filter by the parse method
*
* @see parse()
* @access private
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @param string the actual file content
* @return string the modified file content
*/
function _makeCacheable( $input )
{
$input = sprintf( '<'.'?php ob_start() ?'.'>%s<'.'?php $%s->_cacheEnd() ?'.'>' ,
$input ,
$this->_createCacheObjRef() );
return $input;
}
/**
*
*
* @access private
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return string the name of the global object ref
*/
function _createCacheObjRef()
{
if ($this->_cacheObjReference) {
return $this->_cacheObjReference;
}
// create global (!) object which can be called from within the template file
// to call the cacheStart/cacheEnd-methods
$this->_cacheObjReference = '_'.md5($this->_templateFile.'cache'); // has to start with a valid character for a varibale name, '_'
// its a reference to this instance, so we can simply call the cache methods
// we need to do it like this since we dont know the instance name of the template
// engine and of this special instance neither, that's the easiest way to do it
$GLOBALS[$this->_cacheObjReference] = &$this;
//print "_createCacheObjRef = {$this->_cacheObjReference} for {$this->_templateFile}<br>";
return $this->_cacheObjReference;
}
//
// overwritten methods
//
/**
* return the cached file name if it is set, and it is only
* set if the file is cached and valid, that means not expired etc.
*
* @access public
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return string the filename used to include
*/
function getCompiledTemplate()
{
if ($this->isCached()) {
return $this->_cachedFile;
}
return parent::getCompiledTemplate();
}
/**
* do only really compile if the file is not cached
*
* @access public
* @version 02/05/26
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return boolean actually always true
*/
function compile()
{
if ($this->isCached()) {
return true;
}
return parent::compile();
}
}
?>