动网论坛,站长建站首选,国内使用量最多的论坛软件 动网论坛官方技术讨论区 站长工具 申请属于您自己的免费论坛
首页 | 新闻资讯 | 网站运营 | 网络编程 | 数据库 | 服务器 | 网页设计 | 图像媒体 | 网络应用 | 搜索优化 | 资源下载 | 动网主机 | DVBOX
    本站内  互联网 ASP论坛  ASP.Net论坛  PHP论坛
  
   PHP → 阅读文章

 class.rFastTemplate.php

作者来源: 
阅读 数 660 人次 , 2006-3-29 4:08:00 


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

 
 收藏本文  打印本文  论坛讨论  关闭窗口
· 上一篇:class.rFastTemplate.php
· 下一篇:一个目录类
· 用PHP函数解决SQL injection
· 把mysql数据库的程序改为基于sysbase出错
· MySQL数据库函数详解(1)
· 用Socket发送电子邮件(利用需要验证的SMTP服务器)
· Shell Script方式的PHP


关于本站 | 联系我们 | 业务合作 | 客户案例 | 诚聘英才 | 广告合作 | 收藏本站
海口动网先锋网络科技有限公司版权所有
Copyright © 2000 - 2006 Cndw.Com
中华人民共和国电信与信息服务业务经营许可证编号 琼 ICP 020077