文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>class.rFastTemplate.php

class.rFastTemplate.php

时间:2007-02-17  来源:PHP爱好者

<?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*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);


php爱好者站 http://www.phpfans.net dreamweaver|flash|fireworks|photoshop.
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载