<?php // // copyright ?2000-2001, roland roberts <[email protected]> // 2001 alister bulman <[email protected]> re-port multi template-roots + more // php3 port: copyright ?1999 cdi <[email protected]>, all rights reserved. // perl version: copyright ?1998 jason moore <[email protected]>, 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 <[email protected]> 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 <[email protected]> // alister bulman <[email protected]> (multi template-roots) // michal rybarik <[email protected]> (define_raw()) // cdi <[email protected]>, php3 port // jason moore <[email protected]>, 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. don't try to break these extra long regular expressions into // multiple lines for readability. php 4.03pl1 chokes on them if you do. // i'm guessing the reason is something obscure with the parenthesis // matching, the same sort of thing tcl might have, but i'm 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 don't 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 // we'll 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_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 cdi's // 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; } } }