Location: PHPKode > scripts > Generalized CachedTemplate class > CachedTemplate.txt
CachedTemplate: A generalized template caching class

Document: http://www.scripps.edu/~jesusmc/cachedtpl/CachedTemplate.html

Version: 1.4, Copyright © 2000-2001 Jesus M. Castagnetto
(hide@address.com), License: GPL

  ------------------------------------------------------------------------

New: (1.4) Added support for reading into a variable the contents of a
cached file, which can be used for partial caching of page contents. An
example (partial_caching.php) is included to illustrate the use of the
method.

New: (1.3, unreleased) Added a locking mechanism to avoid race conditions
while updating a cached file

(1.2) Added a general way of using user's variables for
writing/reading/validating cached information. Added support for external
data validation.

NOTE: For questions about these classes contact me at:
hide@address.com, any e-mail related to these classes going to any of
my other e-mail addresses will go unanswered.

  ------------------------------------------------------------------------

Table of contents

   * Introduction
   * Class TemplateAdaptor
   * Class CachedTemplate
   * History
   * Known Bugs
   * License
   * Download
        o everything
        o documentation
   * Acknowledgements

Introduction

Sometime ago I made an extension to CDI's FastTemplate class (the
CachedFastTemplate class), with the idea of creating a file caching
mechanism that saves parsed documents to avoid processing of templates each
time it is called. This simple file caching would reduce the load on the PHP
interpreter by several orders of magnitude if you have a complex template.
Returning a pre-parsed file is always faster than parsing it anew.

But, as always happens more template classes were created each one with
interesting characteristics of their own. So, I decided to reuse the code
and kludge together a more general way of extending those template classes
by using an intermediate TemplateAdapter class, which extends the
appropriate template class, and is itself extended by the CachedTemplate
class.

Below is an (ugly) ASCII diagram, showing the way the template adaptor and
the caching class work with an original template class.

    +----------+      +----------+      +----------+
    | original |      | template |      |  cached  |
    | template +----->+  adaptor +----->+ template +=====> object instance
    |  class   |      |   class  |      |  class   |
    +----------+      +-+--------+      +----------+
                        |
                        +-- init()
                        +-- getTemplatesList()
                        +-- getParsedDoc()
                        +-- [accessory methods]
                        +-- [overriding methods]

The Template Adaptor class must implement the methods needed by the Cached
Template class: init, getTemplatesList and getParsedDoc. To do this the
Template Adaptor may need to generate accessory methods or override one or
more of the original methods of the parent template class. (see
documentation below for more information)

This package contains adapter classes and examples for 5 different template
packages:

   * CDI's FastTemplate class
   * Barnabás Debrenceni's XTemplate class
   * Stefan Bocskai's QuickTemplate class
   * Herman Veluwenkamp's HTML Template class
   * Richard Heyes's Template class
   * PHPLIB's Template class

Basically I picked all the templates classes from PHPClasses (as of June
2000), and included CDI's and PHPLIB's too.

TOC

Class TemplateAdaptor

Description:

An class that extends the appropriate template class, and implements the
methods needed by the CachedTemplate class: init(), getTemplatesList() and
getParsedDoc(). It may need to override methods from the parent class, for
examples on how to do this, look at the classes in the files:
class.HTMLTemplateAdaptor.php, class.RHTemplateAdaptor.php and
class.XTemplateAdaptor.php.

You can easily construct your own TemplateAdaptor class by using one of the
included ones as a starting point. Basically, you need to know how to call
the constructor (if any) of the template class being extended, how to list
the names of the template files, and how to get the parsed document as a
string (so you can assign that to a variable). For example, after reading
the code and documentation for PHPLIB's Template class, it was simple of
create an adaptor class for it based on the existing one for the
FastTemplate class.

Example of definition:

Below is the adaptor class for FastTemplate (class.FastTemplateAdaptor.php):

<?php

/*
 * Class TemplateAdaptor (FastTemplate version)
 * by Jesus M. Castagnetto (hide@address.com)
 * (c) 2000. Version 1.0
 *
 * Description:
 * This class extends CDI's (hide@address.com) FastTemplate class,
 * implementing methods and attributes needed for the CachedTemplate class.
 *
 * The adaptor class needs to implement the getTemplatesList() method that
 * returns an array with the names of the templates loaded, and the init()
 * method used to initialize the constructor of the parent template class
 *
 * Changes:
 * 2000/06/10 - Initial release.
 */

class TemplateAdaptor extends FastTemplate {

        var $TEMPLATES = array();

        /*
         * This method is used to initialize the parent class
         */

        function init($pathToTemplates="") {
                $this->FastTemplate($pathToTemplates);
        }

        /*
         * method to return the list of template names
         */

        function getTemplatesList() {
                if (count($this->FILELIST) > 0 ) {
                        while (list($tag, $fn) = each($this->FILELIST))
                                $this->TEMPLATES[] = $this->ROOT.$fn;
                }
                return $this->TEMPLATES;
        }

        /*
         * method to return the parsed document
         */

        function getParsedDoc($sect="") {
                return $this->fetch($sect);
        }

} // end of class definition
?>

Public Methods:

init

Prototype:
     void init ([mixed $par1 [, mixed $par2, ...]])
Definition:
     This method is a wrapper to initialize variables and call the
     constructor method (if any) of the parent template class. As such is
     very dependent on template class being extended, so the number and type
     of parameters passed is not always the same.

getTemplatesList

Prototype:
     array getTemplatesList (void)
Definition:
     This method returns an array with the names of the templates (if any)
     that the main template script is using.

getParsedDoc

Prototype:
     string getParsedDoc (void)
Definition:
     This method returns a string containing the parsed template file, in a
     form suitable to output back to the browser or save into a file.

TOC

Class CachedTemplate

Description:

A generalized template caching class, extends the appropriate
TemplateAdaptor class. In a few words, it allows the caching of the output
from parsing a template into a file, so the next time the script is
requested it can just send back that file and avoid the processing overhead
of re-parsing the template.

This class can be used also when caching blocks of content from a page (or
pages), by allowing the selective reading of cached information into a
variable (see: get_from_cache()).

To avoid problems when several processes attempt to read or update a cached
file (race condition), a locking mechanism has been implemented, which when
active, is used automatically by all the reading/writing methods of the
class (see: read_from_cache(), get_from_cache() and write_to_cache())

Locking explained

The logic used is the following:

  1. when reading a cache file
        o if a lock file is found, wait for $WAITLOCK microseconds and check
          again
        o if after trying $MAXWAITLOCKCYCLES times the lock is still there
          this may be due to an error somewhere, emit an error and return
          false (read_from_cache()) or the empty string (get_from_cache())
        o when the lock goes away (if there was one) read the cached info
  2. when writing a cache file
        o if there is a lock, some other instance of the same script must be
          updating the info, so do nothing a return

There are also methods that allow to turn on/off lock file usage, which
should speed things very little in general use, and which could be useful
when regenerating pages using a cron job.

Usage:

Modified from the sample file: fasttemplate_example.php

        require "./class.FastTemplate.php3";
        require "./class.FastTemplateAdaptor.php";
        require "./class.CachedTemplate.php";

        // Instantiate a CachedTemplate object with a
        // lifetime of maximum 6 hours
        $ftpl = new CachedTemplate("./mycache",6,"hours");

        // Initialize the parent template class
        $ftpl->init("./templates");

        // Define which templates will be used
        // this needs to be done here so the validity of the
        // cached file can be correctly ascertained
        $ftpl->define(
                array(
                        1main    => "main.tpl",
                        table   => "table.tpl",
                        row     => "row.tpl"
                )
        );

        // Check if we can send the cached file
        if ($ftpl->valid_cache_file()) {
                $ftpl->read_from_cache();
                $end = $ftpl->utime();
                $runtime = ($end - $start) * 1000;
                echo "Completed in $runtime milliseconds<BR>\n";
                exit;
        }

        // Otherwise process the page

(...)

Attributes:

This class has the following attributes (member properties):

$CACHEDIR
     Directory to save cached files, default "./cache"
$CACHELENGTH
     Length of caching, default: 30 units
$TIMEUNIT
     Time unit for caching, default: "day"
$TIMEUNITSARR
     An associative array of valid time units and the corresponding factors
     (divisors) to use when calculating time differences, defined as: array
     ("sec"=>1, "min"=>60, "hour"=>3600, "day"=>86400)
$USEVARS
     a flag variable to indicate that the cache validation, reading and
     writing methods will need to also use the contents of the $VARSVAL
     variable.
     Valid values:
        o "in_name" - appends the output of rawurlencode on the $VARSVAL
          variable to the names of cached and control files
        o "store" - store the contents of $VARSVAL into a *.vars file, and
          use that file for cache validation
$VARSVAL
     If the flag $USEVARS is set, then this variable will contain the
     variable name and value pairs encoded as an URL query string. If the
     method use_get is used, this variable will contain the global variable
     $QUERY_STRING.
$USELOCK
     If the flag $USELOCK is set, then a lock will be used when reading from
     or writing to a cache file. Default true. Use the methods
     set_use_lock() and unset_use_lock() to change the status of this
     variable.
$WAITLOCK
     How many microseconds (default 100,000 microseconds = 100 milliseconds)
     to wait until trying to read from, or write to, a locked cache file.
$MAXWAITLOCKCYCLES
     How many times to attempt reading from a locked cache file. Default is
     20 times. This is used to limit the number of retries before returning
     an error condition.

Public Methods:

set_cache_dir

Prototype:
     void set_cache_dir (string $dir)
Description:
     Sets the directory to be used for caching parsed documents
Example:

             // Set the caching directory to "../mycachedir"
             $obj = new CachedTemplate();
             $obj->set_cache_dir("../mycachedir");


set_cache_length

Prototype:
     void set_cache_length (int $length)
Description:
     Sets the maximum length (in time units) to keep cached documents
Example:

             // Set the caching length to 12 hours
             $obj->set_cache_length(12);
             $obj->set_time_unit("hour");


set_time_unit

Prototype:
     void set_time_unit (string $tunit)
Description:
     Sets the time unit to be used for calculating the lifetime of a cached
     document. Valid units are: "sec", "min", "hour", "day"; if and invalid
     unit is used, it defaults to "day".

use_get

Prototype:
     void use_get ([string $how])
Description:
     Calls the method use_vars to use the contents of the $QUERY_STRING
     global variable for cache writing, reading and validation. The default
     value of the the parameter is "in_name", i.e. use the $QUERY_STRING
     when generating a unique name for the cache file. See the examples in
     the files get_example1.php and get_example2.php for more information.
     Note: This method has to be used before the validation methods.
Example:
     Assuming that the script mypage.php was called using the URL:
     http://www.mysite.com/path/to/mypage.php?somevar=simple, we can use the
     query string as part of the name of the cached file, so if we pass
     other values, e.g. somevar=notsimple, a cached file will be created for
     each instance.

             $tpl = new CachedTemplate();
             $tpl->init();

             // use the query string for generating the names of the cache files
             // which is the default behavior, and equivalent to using
             // $tpl->use_get("in_name");
             $tpl->use_get();
             ...


     In case you prefer not to append the GET query string to the name of
     the cached file, then you can store it for comparison purposes:

             ...
             $tpl->use_get("store");
             ...


use_vars

Prototype:
     void use_vars ([mixed $vars, string $how])
Description:
     Sets the variable flag $USEVARS and sets the appropriate value for the
     $VARSVAL variable. This method accepts as a first parameter either the
     string "QUERY_STRING" (when using the variables passed in a GET query
     string), or an array of variable names and values to be used in the
     writing, reading and validation of the cached files. The default values
     for the parameters are "QUERY_STRING" and "in_name" respectively. Valid
     values for $how are: "in_name" (default) and "store".
     Note: This method has to be used before the validation methods.
Example:
     We will want to use some important values to generate unique cache
     filenames:

             $tpl = new CachedTemplate();
             $tpl->init();

             $important_vars = array(
                             "theme" => "simple",
                             "fgcolor" => "black",
                             "bgcolor" => "white"
             );

             $tpl->use_vars($important_vars, "in_name");
             ...


     If you are using PHP4, you can use the compact function to generate the
     array needed. In the example below, we also decide to store the
     variables into a *.vars file, which will be used during validation:

             ...
             // assuming $theme, $fgcolor and $bgcolor have been defined
             $important_vars = compact($theme, $fgcolor, $bgcolor);

             $tpl->use_vars($important_vars, "store");
             ...


write_to_cache

Prototype:
     void write_to_cache (string $data [, string $datacheck, string
     $filename])
Description:
     Writes the parsed data to a cache file, and generates an associated
     control file containing a creation timestamp, the length of time to
     cache the information, and the unit of time used. If the second
     parameter is present, it will included in the control file to be used
     for external data validation (see: is_data_valid). If the third
     parameter is present, this will be the name used for the cache and
     control files, otherwise the method will use the filename stored in
     $PHP_SELF, replacing all "/" characters with "_".
Example:

             // write parsed document to files "coolfile.parsed.cntrl"
             // and "coolfile.parsed.cache", using today's timestamp
             // as data validation parameter
             $data = $obj->getParsedDoc();
             $obj->write_to_cache($data, time(), "coolfile.parsed");


read_from_cache

Prototype:
     boolean read_from_cache ([string $filename])
Description:
     Reads the cached file from the cache directory and sends it to the
     standard output, returns true on success, false otherwise. If a
     parameter is passed, it will be used as the name for the cached file.
Example:

             // read the current document from cache
             $obj->read_from_cache();


get_from_cache

Prototype:
     string get_from_cache ([string $filename])
Description:
     Reads the cached file from the cache directory and returns it as a
     string if succesful, an empty string otherwise. If a parameter is
     passed, it will be used as the name for the cached file.
Example:

             // get a cached block in this document
             $header = $obj->get_from_cache("header_".$PHP_SELF);


is_cached

Prototype:
     boolean is_cached (string $filename)
Description:
     Returns true if the file $filename is cached, false otherwise.
Example:

             if ($obj->is_cached("coolfile.parsed")) {
                     // do something
             }


valid_cache_file

Prototype:
     boolean valid_cache_file ([string $filename])
Description:
     Returns true if it finds a valid cache file, false otherwise. If the
     parameter $filename is omitted, then the variable $PHP_SELF with the
     "/"s replaced by "_"s will be used.

     The algorithm to decide whether a cached file is valid is:
       1. If a cached file exists (uses method is_cached) go to the next
          step, otherwise return false and exit method.
       2. Is the variable $USEVARS set?
             + No - then go to the next step
             + Yes - then check how do we have to use it, if the value of
               $USEVARS is:
                  + "in_name" - apply URL encoding to $VARSVAL and append it
                    to the filename for the cache and control files, then go
                    to the next step (this is done by calling the method
                    _gen_filename)
                  + "store" - read the stored $VARSVAL from the *.vars file
                    and compare with the current one, return false if they
                    are different, otherwise go to the next step
       3. Get the creation timestamp, time length and time unit from the
          control file. If it is an invalid time unit return false,
          otherwise go to the next step.
       4. Get the list (if any) of templates included in the document. Loop
          through the list and return false if any of the templates does not
          exist, or has been changed since the cached file was created (use
          the the creation timestamp obtained in the previous step),
          otherwise go to the next step.
       5. Finally, compare the creation timestamp with the current one, and
          determine if the cached file content have expired (return false)
          or not (return true).
Example:

             if ($obj->valid_cache_file()) {
                     echo $obj->read_from_cache();
             } else {
                     // parse the document and save into cache
             }


is_data_valid

Prototype:
     boolean is_data_valid (string $datacheck[, string $type, string
     $filename]
Description:
     Used to determine if the data from an external source has changed since
     the cache file was last created. It expects the first parameter to be
     either a unix timestamp or an md5 hash of the data. The second
     parameter should be either "timestamp" or "md5", it defaults to
     "timestamp". The third parameter (if present), should be the name used
     to generate the cached files.

     The idea behind using this method is, to allow for cached data
     regeneration when the data contained there changes in the original
     source, i.e. if you are pulling the body of a page from a database, and
     the information in the database changes, you can use the timestamp of
     the changed row to decide if the page needs to be reparsed. Similar
     approach can be done using an md5 hash of the data, which should also
     detect changes in it, this is for cases in which a timestamp is not
     feasible.
Example
     In the following example, we extract information from a database of
     news articles, so we need to check if the cached information is up to
     date, we use the field ts which contains a MySQL timestamp, and we ask
     for the corresponding unix timestamp:

             ...
             $link = mysql_pconnect();
             mysql_select_db("documents");
             $query = "select UNIX_TIMESTAMP(ts) from news where topic='science' ";
             $query .= "and subtopic='compchem' order by ts DESC limit 1";
             $res = mysql_query($query, $link);
             list($datats) = mysql_fetch_row($res);

             $tpl = new CachedTemplate();
             if ($tpl->valid_cache_file() && $tpl->is_data_valid($datats, "timestamp")) {
                     // cached info valid, send it to the user
             } else {
                     // parse the document
             }
             ...


     A similar approach can be done with data coming from files, etc. See
     also the files datavalid_example1.php and datavalid_example2.php.

set_use_lock()

Prototype:
     void set_use_lock (void)
Description:
     Activates the use of locking while reading/writing cache files
Example:

             // use locking while processing cache files
             $obj->set_use_lock();


unset_use_lock()

Prototype:
     void unset_use_lock (void)
Description:
     Deactivates the use of locking while reading/writing cache files
Example:

             // do not use locking while processing cache files
             $obj->unset_use_lock();


is_locked()

Prototype:
     boolean is_locked (string 4filename)
Description:
     Returns true if file lock exists, false otherwise
Example:

             if ($obj->is_locked("mycachefilename")) {
                     // then do something;
             } else {
                     // proceed as always
             }


mk_lock()

Prototype:
     boolean mk_locked (string 4filename)
Description:
     Creates a lock file if one does not already exists, returning true if
     succesful, false otherwise
Example:

             if ($obj->mk_lock("mycachefilename"))
                     // then we can manipulate the cache file
             } else {
                     // other process is locking the cache file, we need to wait
             }


rm_lock()

Prototype:
     boolean rm_locked (string 4filename)
Description:
     Removes a lock file if one already exists, returning true if succesful,
     false otherwise
Example:

             // clean old lock files
             if ($obj->is_locked("mycachefilename"))
                     $obj->rm_lock("mycachedfilename");
             }


utime

Prototype:
     int utime (void)
Description:
     Returns timestamp including microseconds. Shamelessly *borrowed* from
     CDI's FastTemplate class
Example:

             $start = utime();
             // after some code
             $end = utime();
             echo "Processing took: ".($end - $start) * 1000." milliseconds\n";


Private Methods:

_gen_var_val

Prototype:
     _gen_var_val (array $vars)
Description:
     Converts an associative array of $vars[name] = value into a url query
     string of the form: name1=val1&name2=val2&...

_gen_filename

Prototype:
     string _gen_filename (void)
Description:
     Generates a unique filename based on the name of the file being cached.
     First it replaces all slashes (/) by underlines (_), and then if the
     $USEVARS variable is set to "in_name", appends the rawurlencode'd
     contents of $VARSVAL to the filename.

_key_in_array

Prototype:
     boolean _key_in_array (string $key, array $arr)
Description:
     Returns true if the key is in the array, false otherwise.

_is_valid_time_unit

Prototype:
     boolean _is_valid_time_unit (string $timeunit)
Description:
     Returns true if a the parameter passed is a valid time unit, false
     otherwise.

_mktimestamp

Prototype:
     int _mktimestamp (void)
Description:
     Returns a timestamp in seconds. Wrapper for time().

_diff_time

Prototype:
     int _diff_time (int $end, int $start[, string $timeunit])
Description:
     Returns the difference between the $end and $start timestamps, in the
     units indicated by $timeunit. If the third parameter is omitted, it
     defaults to "day".
Example:

             // return the number of whole days between the 2 timestamps
             echo $obj->_diff_time($end, $start);

             // return the number of whole minutes between the 2 timestamps
             echo $obj->_diff_time($end, $start, "minute");


TOC

History

   * 2000-06-10: Initial release of code
   * 2000-07-12: I finally wrote the documentation
   * 2000-07-16: Added support for PHPLIB's template class. Added support
     for use of the GET query string to generate various cached files from
     the same script (method use_get). Changed my e-mail in the code.
     Updated the documentation
   * 2000-07-18: Added support for external data validation (version not
     released)
   * 2000-07-30: Reorganization of the code to use a general method for
     filename generation (_gen_filename), modified the external data
     validation method, and modified the use of user variables when
     writing/reading/validating cache to be more general, added the methods
     use_vars and _gen_var_val, eliminated the internal variable $USEGET in
     favor of 2 new variables $USEVARS and VARSVAL.
   * 2000-07-31: Added an example on how to use use_vars, modified the
     examples of is_data_valid, some minor code cleaning and updated the
     documentation. Renamed the example files get_example[12].php to
     use_get_example[12].php. New release: version 1.2
   * 2000-08-02: Found a typo that was causing errors in the read_from_cache
     method. Only happened in some cases when using the "in_name" option of
     use_get or use_vars
   * 2000-09-05: Fixed mispelt "$release" var in code and the 13 typos in
     the previous documentation
   * 2000-10-07: Added locking mechanism to the class (version 1.3,
     unreleased)
   * 2001-02-06: Merged (modified) contributed code from Matthieu Casanova,
     which allows reading from cached files into a variable. This can be
     used to cache blocks of content in a page (or pages). New release:
     version 1.4

TOC

Known bugs

Bugs? this code is prefect :-)

If you do find a bug, contact me at the address: hide@address.com
(indicate "CachedTemplate BUG" in the subject)

TOC

License

(from the GPL license)

     This program is free software; you can redistribute it 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 more details.

     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
     02111-1307, USA.

[Go to the URL: http://www.fsf.org/copyleft/gpl.html for the full text of
the GPL License]

TOC

Download

   * Get Everything
     The CachedTemplate class, the TemplateAdapter classes, and the examples
     as a .zip or a .tar.gz archive (documentation included, ZIP created
     using GNU infozip).

     Below is the list of files included in the distribution:
       1. CachedTemplate.html - this document
       2. class.CachedTemplate.php - the CachedTemplate class
       3. Files related to CDI's Fastemplate class
             + class.FastTemplate.php3 - the template class
             + class.FastTemplateAdaptor.php - the adaptor class
             + fasttemplate_example.php - example
             + templates/main.tpl - template used in the example
             + templates/table.tpl - template used in the example
             + templates/row.tpl - template used in the example
             + use_get_example1.php - example using use_get ("in_name"
               option)
             + use_vars_example.php - example using use_vars ("store"
               option)
             + datavalid_example1.php - example using external data
               validation ("timestamp")
             + partial_caching.php - example using get_from_cache to show
               how caching of sections of a page can be implemented
       4. Files related to Herman's HTML Template class
             + herman_template.inc - the template class
             + class.HTMLTemplateAdaptor.php - the adaptor class
             + herman_example.php - example
             + herman_template.html - template used in the example
       5. Files related to Stefan's QuickTemplate class
             + class.QuickTemplate.php3 - the template class
             + class.QuickTemplateAdaptor.php - the adaptor class
             + quicktemplate_ex.php - example
             + first_example.tpl - template used in the example
       6. Files related to Richard's Template class
             + class.template.inc - the template class
             + class.RHTemplateAdaptor.php - the adaptor class
             + richard_example.php - example
             + header-template.html - template used in the example
             + main-template.html - template used in the example
             + footer-template.html - template used in the example
       7. Files related to Barnabás' XTemplate class
             + xtpl.php - the template class
             + class.XTemplateAdaptor.php - the adaptor class
             + xtemplate_ex5.php - example
             + ex5.xtpl - template used in the example
       8. Files related to PHPLIB's Template class
             + phplib_template.inc - the template class
             + class.PHPLIBTemplateAdaptor.php - the adaptor class
             + phplibtemplate_example.php - example
             + ptpl_box.ihtml - template used in the example
             + ptpl_page.ihtml - template used in the example
             + get_example2.php - example using use_get ("store" option)
             + datavalid_example2.php - example using external data
               validation ("md5")
       9. Miscellaneous files
             + COPYING - the GPL license version
             + LICENSE - the copyright and license notice for this package
             + rows.dat - data used in the datavalid_example[12].php files

   * Get the documentation
     The document you are reading now in text, Postscript or PDF formats.

TOC

Acknowledgements

Thanks to the people who sent suggestions, requests and bug reports: (email
addresses mangled in HTML code, to prevent spambot harvesting)

   * Jackson Tsai (hide@address.com) - GET query string use (feature
     request)
   * DK Kim (hide@address.com) - typo in class.XTemplateAdaptor.php
   * Skirando C. Philipona (hide@address.com) - PHPLIB's
     Template support (feature request)
   * Brad Atkins (hide@address.com) - Idea/request that lead to
     adding the data validation methods
   * Toby Champion (hide@address.com) - for finding the mispelt "$release"
     var name in the class code, and for considering that 13 typos in the
     documentation consists sloppy typing, that will make me use ispell more
     often
   * Andreas Mock (hide@address.com) - for realizing that there could be a
     race condition when updating a cached file, which prompted the creation
     of the locking methods
   * Matthieu Casanova (hide@address.com) - for contributing a method
     to read cached files into variables, allowing for partial caching of
     content in pages

TOC

  ------------------------------------------------------------------------
Last mangled on: Tue Feb 6, 2001
Return current item: Generalized CachedTemplate class