<?php
//
// copyright ?2000-2001, roland roberts <roland@astrofoto.org>
// 2001 alister bulman <alister@minotaur.nu> re-port multi template-roots + more
// php3 port: copyright ?1999 cdi <cdi@thewebmasters.net>, all rights reserved.
// perl version: copyright ?1998 jason moore <jmoore@sober.com>, all rights reserved.
//
// rcs revision
// @(#) $id: class.rfasttemplate.php,v 1.22 2001/10/18 21:36:53 roland exp $
// $source: /home/cvs/projects/php/tools/class.rfasttemplate.php,v $
//
// copyright notice
//
// 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, or (at your option)
// any later version.
//
// class.rfasttemplate.php 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.
//
// comments
//
// i would like to thank cdi <cdi@thewebmasters.net> for pointing out the
// copyright notice attached to his php3 port which i had blindly missed
// in my first release of this code.
//
// this work is derived from class.fasttemplate.php3 version 1.1.0 as
// available from http://www.thewebmasters.net/. that work makes
// reference to the "gnu general artistic license". in correspondence
// with the author, the intent was to use the gnu general public license;
// this work does the same.
//
// authors
//
// roland roberts <roland@astrofoto.org>
// alister bulman <alister@minotaur.nu> (multi template-roots)
// michal rybarik <michal@rybarik.sk> (define_raw())
// cdi <cdi@thewebmasters.net>, php3 port
// jason moore <jmoore@sober.com>, original perl version
//
// synopsis
//
// require ("path-to-template-code/class.template.php");
// $t = new template("path-to-template-directory");
// $t->define (array(main => "diary.html"));
// $t->setkey (var1, "some text");
// $t->subst (inner, "inner")
// $t->setkey (var1, "some more text");
// $t->subst (inner, ".inner")
// $t->setkey (var2, "var2 text");
// $t->subst (content, "main");
// $t->print (content);
//
// description
//
// this is a class.fasttemplate.php3 replacement that provides most of the
// same interface but has the ability to do nested dynamic templates. the
// default is to do dynamic template expansion and no special action is
// required for this to happen.
//
// class.fasttemplate.php3 methods not implemented
//
// clear_parse
// same as clear. in fact, it was the same as clear in fasttemplate.
// clear_all
// if you really think you need this, try
// unset $t;
// $t = new template ($path);
// which gives the same effect.
// clear_tpl
// use unload instead. this has the side effect of unloading all parent
// and sibling templates which may be more drastic than you expect and
// is different from class.fasttemplate.php3. this difference is
// necessary since the only way we can force the reload of an embedded
// template is to force the reload of the parent and sibling templates.
//
// class.fasttemplate.php3 methods by another name
//
// the existence of these functions is a historical artifact. i
// originally had in mind to write a functional equivalent from scratch.
// then i came my senses and just grabbed class.fasttemplate.php3 and
// started hacking it. so, you can use the names on the right, but the
// ones on the left are equivalent and are the names used in the original
// class.fasttemplate.php3.
//
// parse –> subst
// get_assiged –> getkey
// assign –> setkey
// clear_href –> unsetkey
// clear_assign –> unsetkey
// fastprint –> xprint
//
class rfasttemplate {
// file name to be used for debugging output. needs to be set prior to
// calling anything other than option setting commands (debug, debugall,
// strict, dynamic) because once the file has been opened, this is ignored.
var $debugfile = /tmp/class.rfasttemplate.php.dbg;
// file descriptor for debugging output.
var $debugfd = -1;
// array for individual member functions. you can turn on debugging for a
// particular member function by calling $this->debug(function_name)
var $debug = array ();
// turn this on to turn on debugging in all member functions via
// $this->debugall(). turn if off via $this->debugall(false);
var $debugall = false;
// names of actual templates. each element will be an array with template
// information including is originating file, file load status, parent
// template, variable list, and actual template contents.
var $template = array();
// holds paths-to-templates (see: set_root and findtemplate)
var $root = array();
// holds the handle to the last template parsed by parse()
var $last = ;
// strict template checking. unresolved variables in templates will generate a
// warning.
var $strict = true;
// if true, this suppresses the warning generated by $strict=true.
var $quiet = false;
// holds handles assigned by a call to parse().
var $handle = array();
// holds all assigned variable names and values.
var $var = array();
// set to true is this is a win32 server. this was part of the
// class.fasttemplate.php3 implementation and the only real place it kicks
// in is in setting the terminating character on the value of $root, the
// path where all the templates live.
var $win32 = false;
// automatically scan template for dynamic templates and assign new values
// to template based on whatever names the html comments use. this can be
// changed up until the time the first parse() is called. well, you can
// change it anytime, but it will have no effect on already loaded
// templates. also, if you have dynamic templates, the first call to parse
// will load all of your templates, so changing it after that point will
// have no effect on any defined templates.
var $dynamic = true;
// grrr. dont try to break these extra long regular expressions into
// multiple lines for readability. php 4.03pl1 chokes on them if you do.
// im guessing the reason is something obscure with the parenthesis
// matching, the same sort of thing tcl might have, but im not sure.
// regular expression which matches the beginning of a dynamic/inferior
// template. the critical bit is that we need two parts: (1) the entire
// match, and (2) the name of the dynamic template. the first part is
// required because will do a strstr() to split the buffer into two
// pieces: everything before the dynamic template declaration and
// everything after. the second is needed because after finding a begin
// we will search for an end and they both have to have the same name of
// we consider the template malformed and throw and error.
// both of these are written with pcre (perl-compatible regular
// expressions) because we need the non-greedy operators to insure that
// we dont read past the end of the html comment marker in the case that
// the begin/end block have trailing comments after the tag name.
var $regex_dynbeg = /(<!–\s*begin\s+dynamic\s+block:\s*([a-za-z][-_a-za-z0-9.]+)(\s*|\s+.*?)–>)/;
// regular expression which matches the end of a dynamic/inferior
// template; see the comment about on the begin match.
var $regex_dynend = /(<!–\s*end\s+dynamic\s+block:\s*([a-za-z][-_a-za-z0-9.]+)(\s*|\s+.*?)–>)/;
// regular expression which matches a variable in the template.
var $regex_var = /\{[a-za-z][-_a-za-z0-9]*\}/;
//
// description
// constructor.
//
function rfasttemplate ($pathtotemplates = ) {
// $pathtotemplates can also be an array of template roots, handled in set_root
global $php_errormsg;
if (!empty($pathtotemplates)) {
$this->set_root ($pathtotemplates);
}
$this->debug = array (subst => false,
parse_internal => false,
parse_internal_1 => false,
parsed => false,
clear => false,
clear_dynamic => false,
load => false);
return $this;
}
//
// description
// set the name to be used for debugging output. if another file has
// already been opened, close it so the next call to logwrite will
// reopen under this name.
//
function debugfile ($name) {
$this->debugfile = $name;
}
//
// description
// turn on/off debugging output of an individual member function.
//
function debug ($what, $on = true) {
$this->debug[$what] = $on;
}
//
// description
// turn on/off debugging output of all member functions.
//
function debugall ($on = true) {
$this->debugall = $on;
}
//
// description
// turn on/off automatic dynamic template expansion. note that a
// template with an inferior dynamic template embedded will still
// parse but only as if it were part of the main template. when this
// is turned on, it will be parsed out as as if it were a full-blown
// template and can thus be both parsed and appended to as a separate
// entity.
//
function dynamic ($on = true) {
$this->dynamic = $on;
}
//
// description
// turn on/off strict template checking. when on, all template tags
// must be assigned or we throw an error (but stilll parse the
// template).
//
function strict ($on = true) {
$this->strict = $on;
}
function quiet ($on = true) {
$this->quiet = true;
}
//
// description
// for compatibility with class.fasttemplate.php3.
//
function no_strict () {
$this->strict = false;
}
//
// description
// utility function for debugging.
//
function logwrite ($msg) {
if ($this->debugfd < 0) {
$this->debugfd = fopen ($this->debugfile, a);
}
fputs ($this->debugfd,
strftime (%y/%m/%d %h:%m:%s ) . $msg . "\n");
}
//
// description
// this was lifted as-is from class.fasttemplate.php3. based on what
// platform is in use, it makes sure the path specification ends with
// the proper path separator; i.e., a slash on unix systems and a
// back-slash on win32 systems. when we can run on mac or vms i guess
// well worry about other characters….
//
// $root can now be an array of template roots which will be searched to
// find the first matching name.
function set_root ($root) {
if (!is_array($root)) {
$trailer = substr ($root, -1);
if ($trailer != ($this->win32 ? \\ : /))
$root .= ($this->win32 ? \\ : /);
if (!is_dir($root)) {
$this->error ("specified root dir [$root] is not a directory", true);
return false;
}
$this->root[] = $root;
} else {
reset($root);
while(list($k, $v) = each($root)) {
if (is_dir($v)) {
$trailer = substr ($v,-1);
if ($trailer != ($this->win32 ? \\ : /))
$v .= ($this->win32 ? \\ : /);
$this->root[] = $v;
} else
$this->error ("specified root dir [$v] is not a directory", true);
}
}
}
//
// description
// associate files with a template names.
//
// sigh. at least with the cvs version of php, $dynamic = false sets it
// to true.
//
function define ($filelist, $dynamic = 0) {
reset ($filelist);
while (list ($tpl, $file) = each ($filelist)) {
$this->template[$tpl] = array (file => $file, dynamic => $dynamic);
}
return true;
}
function define_dynamic ($tpllist, $parent=) {
if (is_array($tpllist)) {
reset ($tpllist);
while (list ($tpl, $parent) = each ($tpllist)) {
$this->template[$tpl][parent] = $parent;
$this->template[$tpl][dynamic] = true;
}
} else {
// $tpllist is not an array, but a single child/parent pair.
$this->template[$tpllist][parent] = $parent;
$this->template[$tpllist][dynamic] = true;
}
}
//
// description
// defines a template from a string (not a file). this function has
// not been ported from original perl module to cdis
// class.fasttemplate.php3, and it comebacks in rfasttemplate
// class. you can find it useful if you want to use templates, stored
// in database or shared memory.
//
function define_raw ($stringlist, $dynamic = 0) {
reset ($stringlist);
while (list ($tpl, $string) = each ($stringlist)) {
$this->template[$tpl] = array (string => $string, dynamic => $dynamic, loaded => 1);
}
return true;
}
//
// description
// try each directory in our list of possible roots in turn until we
// find a matching template
//
function findtemplate ($file) {
// first try for a template in the current directory short path for
// absolute filenames
if (substr($file, 0, 1) == /) {
if (file_exists($file)) {
return $file;
}
}
// search path for a matching file
reset($this->root);
while(list($k, $v) = each($this->root)) {
$f = $v . $file;
if (file_exists($f)) {
return $f;
}
}
$this->error ("findtemplate: file $file does not exist anywhere in " . implode( , $this->root), true);
return false;
}
//
// description
// load a template into memory from the underlying file.
//
function &load ($file) {
$debug = $this->debugall || $this->debug[load];
if (! count($this->root)) {
if ($debug)
$this->logwrite ("load: cannot open template $file, template base directory not set");
$this->error ("cannot open template $file, template base directory not set", true);
return false;
} else {
$contents = ;
$filename = $this->findtemplate ($file);
if ($filename)
$contents = implode (, (@file($filename)));
if (!($contents) or (empty($contents)) or (! $filename)) {
if ($debug)
$this->logwrite ("load: failed to load $file, $php_errormsg");
$this->error ("load($file) failure: $php_errormsg", true);
} else {
if ($debug)
$this->logwrite ("load: found $filename");
return $contents;
}
}
}
// 未完待续 呵呵 ——————by 孤狼
