?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. 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*BEGINs+DYNAMICs+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*ENDs+DYNAMICs+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_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 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; } } } // // Description // Recursive internal parse routine. This will recursively parse a // template containing dynamic inferior templates. Each of these // inferior templates gets their own entry in the TEMPLATE array. // function &parse_internal_1 ($tag, $rest = '') { $debug = $this-DEBUGALL || $this-DEBUG['parse_internal_1']; if (empty($tag)) { $this-error ("parse_internal_1: empty tag invalid", true); } if ($debug) $this-logwrite ("parse_internal_1 (tag=$tag, rest=$rest)"); while (!empty($rest)) { if ($debug) $this-logwrite ('parse_internal_1: REGEX_DYNBEG search: rest = ' . $rest); if (preg_match ($this-REGEX_DYNBEG, $rest, $dynbeg)) { // Found match, now split into two pieces and search the second // half for the matching END. The string which goes into the // next element includes the HTML comment which forms the BEGIN // block. if ($debug) $this-logwrite ('parse_internal_1: match beg = ' . $dynbeg[1]); $pos = strpos ($rest, $dynbeg[1]); // See if the text on either side of the BEGIN comment is only // whitespace. If so, we delete the entire line. $okay = false; for ($offbeg = $pos - 1; $offbeg = 0; $offbeg--) { $c = $rest{$offbeg}; if ($c == "n") { $okay = true; $offbeg++; break; } if (($c != ' ') && ($c != "t")) { $offbeg = $pos; break; } } if (! $okay) { $offend = $pos + strlen($dynbeg[1]); } else { $l = strlen ($rest); for ($offend = $pos + strlen($dynbeg[1]); $offend $l; $offend++) { $c = $rest{$offend}; if ($c == "n") { $offend++; break; } if (($c != ' ') && ($c != "t")) { $offend = $pos + strlen($dynbeg[1]); break; } } } // This includes the contents of the REGEX_DYNBEG in the output // $part[] = substr ($rest, 0, $pos); // This preserves whitespace on the END block line(s). // $part[] = substr ($rest, 0, $pos+strlen($dynbeg[1])); // $rest = substr ($rest, $pos+strlen($dynbeg[1])); // Catch case where BEGIN block is at position 0. if ($offbeg 0) $part[] = substr ($rest, 0, $offbeg); $rest = substr ($rest, $offend); $sub = ''; if ($debug) $this-logwrite ("parse_internal_1: found at pos = $pos"); // Okay, here we are actually NOT interested in just the next // END block. We are only interested in the next END block that // matches this BEGIN block. This is not the most efficient // because we really could do this in one pass through the // string just marking BEGIN and END blocks. But the recursion // makes for a simple algorithm (if there was a reverse // preg...). $found = false; while (preg_match ($this-REGEX_DYNEND, $rest, $dynend)) { if ($debug) $this-logwrite ('parse_internal_1: REGEX_DYNEND search: rest = ' . $rest); if ($debug) $this-logwrite ('parse_internal_1: match beg = ' . $dynend[1]); $pos = strpos ($rest, $dynend[1]); if ($dynbeg[2] == $dynend[2]) { $found = true; // See if the text on either side of the END comment is // only whitespace. If so, we delete the entire line. $okay = false; for ($offbeg = $pos - 1; $offbeg = 0; $offbeg--) { $c = $rest{$offbeg}; if ($c == "n") { $offbeg++; $okay = true; break; } if (($c != ' ') && ($c != "t")) { $offbeg = $pos; break; } } if (! $okay) { $offend = $pos + strlen($dynend[1]); } else { $l = strlen ($rest);(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)