0byt3m1n1
Path:
/
data
/
applications
/
aps
/
geeklog
/
1.8.0-0
/
standard
/
htdocs
/
system
/
classes
/
[
Home
]
File: template.class.php
<?php /* Reminder: always indent with 4 spaces (no tabs). */ // +---------------------------------------------------------------------------+ // | Geeklog 1.8 | // +---------------------------------------------------------------------------+ // | template.class.php | // | | // | Template library. | // +---------------------------------------------------------------------------+ // | (C) Copyright 1999-2000 NetUSE GmbH, Kristian Koehntopp | // | | // | Originally written as part of PHPLIB, <http://sf.net/projects/phplib/>, | // | with contributions from Richard Archer, Marc Tardif, Layne Weathers, | // | NickM, Brian, and others. See the PHPLIB site for a complete list. | // | | // | Since this library found its way into the Geeklog code base, it has been | // | modified for the requirements of Geeklog and may no longer be compatible | // | with the PHPLIB version. | // | | // | (C) Copyright 2001-2010 of this version by the following authors: | // | | // | Authors: Tony Bibbs - tony AT tonybibbs DOT com | // | Dirk Haun - dirk AT haun-online DOT de | // | Oliver Spiesshofer - oliver AT spiesshofer DOT com | // | Blaine Lang - blaine AT portalparts DOT com | // | Kenji ITO - geeklog AT mystral-kk DOT net | // | dengen - taharaxp AT gmail DOT com | // | Tom Homer - websitemaster AT cogeco DOT net | // | Joe Mucchiello - joe AT throwingdice DOT com | // +---------------------------------------------------------------------------+ // | | // | This library is free software; you can redistribute it and/or | // | modify it under the terms of the GNU Library General Public | // | License as published by the Free Software Foundation; either | // | version 2 of the License, or (at your option) any later version. | // | | // | This library 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 | // | Library General Public License for more details: | // | http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html | // | | // +---------------------------------------------------------------------------+ /** * The template class allows you to keep your HTML code in some external files * which are completely free of PHP code, but contain replacement fields. * The class provides you with functions which can fill in the replacement fields * with arbitrary strings. These strings can become very large, e.g. entire tables. * * Note: If you think that this is like FastTemplates, read carefully. It isn't. * */ interface ITemplate { function set_file($varname, $filename = ''); function set_block($parent, $varname, $name = ''); function set_var($varname, $value = '', $append = false); function clear_var($varname); function unset_var($varname); function get_var($varname); function parse($target, $varname, $append = false); function finish($str); } class Template implements ITemplate { /** * Serialization helper, the name of this class. * * @var string * @access public */ var $classname = 'Template'; /** * Determines how much debugging output Template will produce. * This is a bitwise mask of available debug levels: * 0 = no debugging * 1 = debug variable assignments * 2 = debug calls to get variable * 4 = debug internals (outputs all function calls with parameters). * * Note: setting $this->debug = true will enable debugging of variable * assignments only which is the same behaviour as versions up to release 7.2d. * * @var int * @access public */ var $debug = false; /** * The base directory from which template files are loaded. * * @var string * @access private * @see set_root */ var $root = '.'; /** * A hash of strings forming a translation table which translates variable names * into names of files containing the variable content. * $file[varname] = "filename"; * * @var array * @access private * @see set_file */ var $file = array(); /** * A hash of strings forming a translation table which translates variable names * into values for their respective varkeys. * $varvals[varname] = "value" * * @var array * @access private * @see set_var */ var $varvals = array(); /** * Determines how to output variable tags with no assigned value in templates. * * @var string * @access private * @see set_unknowns */ var $unknowns = 'remove'; /** * Determines how Template handles error conditions. * "yes" = the error is reported, then execution is halted * "report" = the error is reported, then execution continues by returning "false" * "no" = errors are silently ignored, and execution resumes reporting "false" * * @var string * @access public * @see halt */ var $halt_on_error = 'yes'; /** * The last error message is retained in this variable. * * @var string * @access public * @see halt */ var $last_error = ''; /** * The name of a function is retained in this variable and is used to do any pre processing work. * * @var string * @access public * @see _preprocess */ var $preprocess_fn = ''; /** * The name of a function is retained in this variable and is used to do any post processing work. * * @var string * @access public * @see _postprocess */ var $postprocess_fn = ''; /** * Pre Process * * Perform any post processing work by calling the function held in $preprocess_fn * * @param string $str * @access private */ function _preprocess($str) { $function = $this->preprocess_fn; if (function_exists($function)) { $str = $function($str); } return $str; } /** * Post Process * * Perform any post processing work by calling the function held in $postprocess_fn * * @param string $str * @access private */ function _postprocess($str) { $function = $this->postprocess_fn; if (function_exists($function)) { $str = $function($str); } return $str; } /****************************************************************************** * Class constructor. May be called with two optional parameters. * The first parameter sets the template directory the second parameter * sets the policy regarding handling of unknown variables. * * usage: Template([string $root = "."], [string $unknowns = "remove"]) * * @param $root path to template directory * @param $string what to do with undefined variables * @see set_root * @see set_unknowns * @access public * @return void */ function Template($root = '.', $unknowns = 'remove') { if ($this->debug & 4) { echo "<p><b>Template:</b> root = $root, unknowns = $unknowns</p>\n"; } $this->set_root($root); $this->set_unknowns($unknowns); } /****************************************************************************** * Checks that $root is a valid directory and if so sets this directory as the * base directory from which templates are loaded by storing the value in * $this->root. Relative filenames are prepended with the path in $this->root. * * Returns true on success, false on error. * * usage: set_root(string $root) * * @param $root string containing new template directory * @see root * @access public * @return boolean */ function set_root($root) { if ($this->debug & 4) { echo "<p><b>set_root:</b> root = $root</p>\n"; } if (substr ($root, -1) == '/') { $root = substr ($root, 0, -1); } if (!is_dir($root)) { $this->halt("set_root: $root is not a directory."); return false; } $this->root = $root; return true; } /****************************************************************************** * Sets the policy for dealing with unresolved variable names. * * unknowns defines what to do with undefined template variables * "remove" = remove undefined variables * "comment" = replace undefined variables with comments * "keep" = keep undefined variables * * Note: "comment" can cause unexpected results when the variable tag is embedded * inside an HTML tag, for example a tag which is expected to be replaced with a URL. * * usage: set_unknowns(string $unknowns) * * @param $unknowns new value for unknowns * @see unknowns * @access public * @return void */ function set_unknowns($unknowns = 'remove') { if ($this->debug & 4) { echo "<p><b>unknowns:</b> unknowns = $unknowns</p>\n"; } $this->unknowns = $unknowns; } /****************************************************************************** * Defines a filename for the initial value of a variable. * * It may be passed either a varname and a file name as two strings or * a hash of strings with the key being the varname and the value * being the file name. * * The new mappings are stored in the array $this->file. * The files are not loaded yet, but only when needed. * * Returns true on success, false on error. * * usage: set_file(array $filelist = (string $varname => string $filename)) * or * usage: set_file(string $varname, string $filename) * * @param $varname either a string containing a varname or a hash of varname/file name pairs. * @param $filename if varname is a string this is the filename otherwise filename is not required * @access public * @return boolean */ function set_file($varname, $filename = '') { if (!is_array($varname)) { if ($this->debug & 4) { echo "<p><b>set_file:</b> (with scalar) varname = $varname, filename = $filename</p>\n"; } if ($filename == '') { $this->halt("set_file: For varname $varname filename is empty."); return false; } $this->file[$varname] = $this->filename($filename); } else { foreach ($varname as $v => $f) { if ($this->debug & 4) { echo "<p><b>set_file:</b> (with array) varname = $v, filename = $f</p>\n"; } if ($f == '') { $this->halt("set_file: For varname $v filename is empty."); return false; } $this->file[$v] = $this->filename($f); } } return true; } /****************************************************************************** * A variable $parent may contain a variable block defined by: * <!-- BEGIN $varname --> content <!-- END $varname -->. This function removes * that block from $parent and replaces it with a variable reference named $name. * The block is inserted into the varvals hashes. If $name is * omitted, it is assumed to be the same as $varname. * * Blocks may be nested but care must be taken to extract the blocks in order * from the innermost block to the outermost block. * * Returns true on success, false on error. * * usage: set_block(string $parent, string $varname, [string $name = ""]) * * @param $parent a string containing the name of the parent variable * @param $varname a string containing the name of the block to be extracted * @param $name the name of the variable in which to store the block * @access public * @return boolean */ function set_block($parent, $varname, $name = '') { if ($this->debug & 4) { echo "<p><b>set_block:</b> parent = $parent, varname = $varname, name = $name</p>\n"; } if (!$this->loadfile($parent)) { $this->halt("set_block: unable to load $parent."); return false; } if ($name == '') { $name = $varname; } $str = $this->get_var($parent); $reg = "/[ \t]*<!--\s+BEGIN $varname\s+-->\s*?\n?(\s*.*?\n?)\s*<!--\s+END $varname\s+-->\s*?\n?/sm"; $matches = preg_match($reg, $str, $m); if (($matches === false) || ($matches == 0)) { return false; } $str = str_replace($m[0], '{' . $name . '}', $str); $this->set_var($varname, $m[1]); $this->set_var($parent, $str); return true; } /****************************************************************************** * This functions sets the value of a variable. * * It may be called with either a varname and a value as two strings or an * an associative array with the key being the varname and the value being * the new variable value. * * The function inserts the new value of the variable into the $varvals hashes. * It is not necessary for a variable to exist in these hashes before calling * this function. * * An optional third parameter allows the value for each varname to be appended * to the existing variable instead of replacing it. The default is to replace. * This feature was introduced after the 7.2d release. * * * usage: set_var(string $varname, [string $value = ""], [boolean $append = false]) * or * usage: set_var(array $varname = (string $varname => string $value), [mixed $dummy_var], [boolean $append = false]) * * @param $varname either a string containing a varname or a hash of varname/value pairs. * @param $value if $varname is a string this contains the new value for the variable otherwise this parameter is ignored * @param $append if true, the value is appended to the variable's existing value * @access public * @return void */ function set_var($varname, $value = '', $append = false) { if (!is_array($varname)) { if (!empty($varname)) { if ($this->debug & 1) { printf("<b>set_var:</b> (with scalar) <b>%s</b> = '%s'<br" . XHTML . ">\n", $varname, htmlentities($value)); } if ($append && isset($this->varvals[$varname])) { $this->varvals[$varname] .= $value; } else { $this->varvals[$varname] = $value; } } } else { foreach ($varname as $k => $v) { if (!empty($k)) { if ($this->debug & 1) { printf("<b>set_var:</b> (with array) <b>%s</b> = '%s'<br" . XHTML . ">\n", $k, htmlentities($v)); } if ($append && isset($this->varvals[$k])) { $this->varvals[$k] .= $v; } else { $this->varvals[$k] = $v; } } } } } /****************************************************************************** * This functions clears the value of a variable. * * It may be called with either a varname as a string or an array with the * values being the varnames to be cleared. * * The function sets the value of the variable in the $varvals hashes to "". * It is not necessary for a variable to exist in these hashes before calling * this function. * * * usage: clear_var(string $varname) * or * usage: clear_var(array $varname = (string $varname)) * * @param $varname either a string containing a varname or an array of varnames. * @access public * @return void */ function clear_var($varname) { if (!is_array($varname)) { if (!empty($varname)) { if ($this->debug & 1) { printf("<b>clear_var:</b> (with scalar) <b>%s</b><br" . XHTML . ">\n", $varname); } $this->set_var($varname, ''); } } else { foreach ($varname as $v) { if (!empty($v)) { if ($this->debug & 1) { printf("<b>clear_var:</b> (with array) <b>%s</b><br" . XHTML . ">\n", $v); } $this->set_var($v, ''); } } } } /****************************************************************************** * This functions unsets a variable completely. * * It may be called with either a varname as a string or an array with the * values being the varnames to be cleared. * * The function removes the variable from the $varkeys and $varvals hashes. * It is not necessary for a variable to exist in these hashes before calling * this function. * * * usage: unset_var(string $varname) * or * usage: unset_var(array $varname = (string $varname)) * * @param $varname either a string containing a varname or an array of varnames. * @access public * @return void */ function unset_var($varname) { if (!is_array($varname)) { if (!empty($varname)) { if ($this->debug & 1) { printf("<b>unset_var:</b> (with scalar) <b>%s</b><br" . XHTML . ">\n", $varname); } unset($this->varvals[$varname]); } } else { foreach ($varname as $v) { if (!empty($v)) { if ($this->debug & 1) { printf("<b>unset_var:</b> (with array) <b>%s</b><br" . XHTML . ">\n", $v); } unset($this->varvals[$v]); } } } } /****************************************************************************** * This function fills in all the variables contained within the variable named * $varname. The resulting value is returned as the function result and the * original value of the variable varname is not changed. The resulting string * is not "finished", that is, the unresolved variable name policy has not been * applied yet. * * Returns: the value of the variable $varname with all variables substituted. * * usage: subst(string $varname) * * @param $varname the name of the variable within which variables are to be substituted * @access public * @return string */ function subst($varname) { if ($this->debug & 4) { echo "<p><b>subst:</b> varname = $varname</p>\n"; } if (!$this->loadfile($varname)) { $this->halt("subst: unable to load $varname."); return false; } $varkeys = array_map( create_function('$a', 'return "{" . $a . "}";'), array_keys($this->varvals) ); $str = $this->get_var($varname); $str = str_replace($varkeys, array_values($this->varvals), $str); return $str; } /****************************************************************************** * This is shorthand for print $this->subst($varname). See subst for further * details. * * Returns: always returns false. * * usage: psubst(string $varname) * * @param $varname the name of the variable within which variables are to be substituted * @access public * @return false * @see subst */ function psubst($varname) { if ($this->debug & 4) { echo "<p><b>psubst:</b> varname = $varname</p>\n"; } print $this->subst($varname); return false; } /****************************************************************************** * The function substitutes the values of all defined variables in the variable * named $varname and stores or appends the result in the variable named $target. * * It may be called with either a target and a varname as two strings or a * target as a string and an array of variable names in varname. * * The function inserts the new value of the variable into the $varvals hashes. * It is not necessary for a variable to exist in these hashes before calling * this function. * * An optional third parameter allows the value for each varname to be appended * to the existing target variable instead of replacing it. The default is to * replace. * * If $target and $varname are both strings, the substituted value of the * variable $varname is inserted into or appended to $target. * * If $handle is an array of variable names the variables named by $handle are * sequentially substituted and the result of each substitution step is * inserted into or appended to in $target. The resulting substitution is * available in the variable named by $target, as is each intermediate step * for the next $varname in sequence. Note that while it is possible, it * is only rarely desirable to call this function with an array of varnames * and with $append = true. This append feature was introduced after the 7.2d * release. * * Returns: the last value assigned to $target. * * usage: parse(string $target, string $varname, [boolean $append]) * or * usage: parse(string $target, array $varname = (string $varname), [boolean $append]) * * @param $target a string containing the name of the variable into which substituted $varnames are to be stored * @param $varname if a string, the name the name of the variable to substitute or if an array a list of variables to be substituted * @param $append if true, the substituted variables are appended to $target otherwise the existing value of $target is replaced * @access public * @return string * @see subst */ function parse($target, $varname, $append = false) { if (!is_array($varname)) { if ($this->debug & 4) { echo "<p><b>parse:</b> (with scalar) target = $target, varname = $varname, append = $append</p>\n"; } $str = $this->subst($varname); if ($append) { $this->set_var($target, $this->get_var($target) . $str); } else { $this->set_var($target, $str); } } else { foreach ($varname as $i => $v) { if ($this->debug & 4) { echo "<p><b>parse:</b> (with array) target = $target, i = $i, varname = $v, append = $append</p>\n"; } $str = $this->subst($v); if ($append) { $this->set_var($target, $this->get_var($target) . $str); } else { $this->set_var($target, $str); } } } if ($this->debug & 4) { echo "<p><b>parse:</b> completed</p>\n"; } return $str; } /****************************************************************************** * This is shorthand for print $this->parse(...) and is functionally identical. * See parse for further details. * * Returns: always returns false. * * usage: pparse(string $target, string $varname, [boolean $append]) * or * usage: pparse(string $target, array $varname = (string $varname), [boolean $append]) * * @param $target a string containing the name of the variable into which substituted $varnames are to be stored * @param $varname if a string, the name the name of the variable to substitute or if an array a list of variables to be substituted * @param $append if true, the substituted variables are appended to $target otherwise the existing value of $target is replaced * @access public * @return false * @see parse */ function pparse($target, $varname, $append = false) { if ($this->debug & 4) { echo "<p><b>pparse:</b> passing parameters to parse...</p>\n"; } print $this->finish($this->parse($target, $varname, $append)); return false; } /****************************************************************************** * This function returns an associative array of all defined variables with the * name as the key and the value of the variable as the value. * * This is mostly useful for debugging. Also note that $this->debug can be used * to echo all variable assignments as they occur and to trace execution. * * Returns: a hash of all defined variable values keyed by their names. * * usage: get_vars() * * @access public * @return array * @see $debug */ function get_vars() { if ($this->debug & 4) { echo "<p><b>get_vars:</b> constructing array of vars...</p>\n"; } return $this->varvals; } /****************************************************************************** * This function returns the value of the variable named by $varname. * If $varname references a file and that file has not been loaded yet, the * variable will be reported as empty. * * When called with an array of variable names this function will return a a * hash of variable values keyed by their names. * * Returns: a string or an array containing the value of $varname. * * usage: get_var(string $varname) * or * usage: get_var(array $varname) * * @param $varname if a string, the name the name of the variable to get the value of, or if an array a list of variables to return the value of * @access public * @return string or array */ function get_var($varname) { if (!is_array($varname)) { if (isset($this->varvals[$varname])) { $str = $this->varvals[$varname]; } else { $str = ''; } if ($this->debug & 2) { printf ("<b>get_var</b> (with scalar) <b>%s</b> = '%s'<br" . XHTML . ">\n", $varname, htmlentities($str)); } return $str; } else { foreach ($varname as $v) { if (isset($this->varvals[$v])) { $str = $this->varvals[$v]; } else { $str = ''; } if ($this->debug & 2) { printf ("<b>get_var:</b> (with array) <b>%s</b> = '%s'<br" . XHTML . ">\n", $v, htmlentities($str)); } $result[$v] = $str; } return $result; } } /****************************************************************************** * This function returns a hash of unresolved variable names in $varname, keyed * by their names (that is, the hash has the form $a[$name] = $name). * * Returns: a hash of varname/varname pairs or false on error. * * usage: get_undefined(string $varname) * * @param $varname a string containing the name the name of the variable to scan for unresolved variables * @access public * @return array */ function get_undefined($varname) { if ($this->debug & 4) { echo "<p><b>get_undefined:</b> varname = $varname</p>\n"; } if (!$this->loadfile($varname)) { $this->halt("get_undefined: unable to load $varname."); return false; } preg_match_all('/{([^ \t\r\n}]+)}/', $this->get_var($varname), $m); $m = $m[1]; if (!is_array($m)) { return false; } $result = array(); foreach ($m as $v) { if (!array_key_exists($v, $this->varvals)) { if ($this->debug & 4) { echo "<p><b>get_undefined:</b> undefined: $v</p>\n"; } $result[$v] = $v; } } if (count($result)) { return $result; } else { return false; } } /****************************************************************************** * This function returns the finished version of $str. That is, the policy * regarding unresolved variable names will be applied to $str. * * Returns: a finished string derived from $str and $this->unknowns. * * usage: finish(string $str) * * @param $str a string to which to apply the unresolved variable policy * @access public * @return string * @see set_unknowns */ function finish($str) { switch ($this->unknowns) { case 'keep': break; case 'remove': $str = preg_replace('/{[^ \t\r\n}]+}/', '', $str); break; case 'comment': $str = preg_replace('/{([^ \t\r\n}]+)}/', "<!-- Template variable \\1 undefined -->", $str); break; } $str = $this->_postprocess($str); return $str; } /****************************************************************************** * This function prints the finished version of the value of the variable named * by $varname. That is, the policy regarding unresolved variable names will be * applied to the variable $varname then it will be printed. * * usage: p(string $varname) * * @param $varname a string containing the name of the variable to finish and print * @access public * @return void * @see set_unknowns * @see finish */ function p($varname) { print $this->finish($this->get_var($varname)); } /****************************************************************************** * This function returns the finished version of the value of the variable named * by $varname. That is, the policy regarding unresolved variable names will be * applied to the variable $varname and the result returned. * * Returns: a finished string derived from the variable $varname. * * usage: get(string $varname) * * @param $varname a string containing the name of the variable to finish * @access public * @return void * @see set_unknowns * @see finish */ function get($varname) { return $this->finish($this->get_var($varname)); } /****************************************************************************** * When called with a relative pathname, this function will return the pathname * with $this->root prepended. Absolute pathnames are returned unchanged. * * Returns: a string containing an absolute pathname. * * usage: filename(string $filename) * * @param $filename a string containing a filename * @access private * @return string * @see set_root */ function filename($filename) { if ($this->debug & 4) { echo "<p><b>filename:</b> filename = $filename</p>\n"; } // Test if file exist and add physical path as 2nd test if (!file_exists($filename)) { // Try appending file to template root $filename = $this->root.'/'.$filename; if (!file_exists($filename)) { $this->halt("filename: file $filename does not exist."); } } return $filename; } /****************************************************************************** * If a variable's value is undefined and the variable has a filename stored in * $this->file[$varname] then the backing file will be loaded and the file's * contents will be assigned as the variable's value. * * Note that the behaviour of this function changed slightly after the 7.2d * release. Where previously a variable was reloaded from file if the value * was empty, now this is not done. This allows a variable to be loaded then * set to "", and also prevents attempts to load empty variables. Files are * now only loaded if $this->varvals[$varname] is unset. * * Returns: true on success, false on error. * * usage: loadfile(string $varname) * * @param $varname a string containing the name of a variable to load * @access private * @return boolean * @see set_file */ function loadfile($varname) { if ($this->debug & 4) { echo "<p><b>loadfile:</b> varname = $varname</p>\n"; } if (!isset($this->file[$varname])) { // $varname does not reference a file so return if ($this->debug & 4) { echo "<p><b>loadfile:</b> varname $varname does not reference a file</p>\n"; } return true; } if (isset($this->varvals[$varname])) { // will only be unset if varname was created with set_file and has never been loaded // $varname has already been loaded so return if ($this->debug & 4) { echo "<p><b>loadfile:</b> varname $varname is already loaded</p>\n"; } return true; } $filename = $this->file[$varname]; $str = @file_get_contents($filename); if (empty($str)) { $this->halt("loadfile: While loading $varname, $filename does not exist or is empty."); return false; } if ($this->debug & 4) { printf("<b>loadfile:</b> loaded $filename into $varname<br" . XHTML . ">\n"); } $str = $this->_preprocess($str); $this->set_var($varname, $str); return true; } /****************************************************************************** * This function is called whenever an error occurs and will handle the error * according to the policy defined in $this->halt_on_error. Additionally the * error message will be saved in $this->last_error. * * Returns: always returns false. * * usage: halt(string $msg) * * @param $msg a string containing an error message * @access private * @return void * @see $halt_on_error */ function halt($msg) { $this->last_error = $msg; if ($this->halt_on_error != 'no') { $this->haltmsg($msg); } /* we won't be coming back from haltmsg() in that case anyway if ($this->halt_on_error == 'yes') { die("<b>Halted.</b>"); } */ return false; } /****************************************************************************** * This function prints an error message. * It can be overridden by your subclass of Template. It will be called with an * error message to display. * * usage: haltmsg(string $msg) * * @param $msg a string containing the error message to display * @access public * @return void * @see halt */ function haltmsg($msg) { if ($this->halt_on_error == 'yes') { trigger_error(sprintf("Template Error: %s", $msg), E_USER_ERROR); } else { printf("<b>Template Error:</b> %s<br" . XHTML . ">\n", $msg); } } } class MultiRootTemplate extends Template { function Template($root = Array(), $unknowns = 'remove') { if ($this->debug & 4) { echo "<p><b>Template:</b> root = $root, unknowns = $unknowns</p>\n"; } $this->set_root($root); $this->set_unknowns($unknowns); } function set_root($A) { $this->root = Array(); foreach ($A as $r) { if (is_dir($r)) { $this->root[] = $r; } } } function filename($name) { if (file_exists($name)) return $name; foreach ($this->root as $root) { $filename = $root . $name; if (file_exists($filename)) return $name; } $this->halt('file not found: ' . $name); } } ?>