system/classes/template.class.php
author Dirk Haun <dirk@haun-online.de>
Sat, 17 Oct 2009 19:54:49 +0200
branchHEAD
changeset 7384 062fc7ef2c35
parent 6928 4aa10bdc1ff6
child 7538 45315295756f
permissions -rw-r--r--
The template class should really trigger our error handler instead of printing out error messages
     1 <?php
     2 /*
     3  * Session Management for PHP3
     4  *
     5  * (C) Copyright 1999-2000 NetUSE GmbH
     6  *                    Kristian Koehntopp
     7  *
     8  * $Id: template.class.php,v 1.9 2008/06/26 00:26:43 blaine Exp $
     9  *
    10  */
    11 
    12 /*
    13  * Change log since version 7.2c
    14  *
    15  * Bug fixes to version 7.2c compiled by Richard Archer <rha@juggernaut.com.au>:
    16  * (credits given to first person to post a diff to phplib mailing list)
    17  *
    18  * Normalised all comments and whitespace (rha)
    19  * replaced "$handle" with "$varname" and "$h" with "$v" throughout (from phplib-devel)
    20  * added braces around all one-line if statements in: get_undefined, loadfile and halt (rha)
    21  * set_var was missing two sets of braces (rha)
    22  * added a couple of "return true" statements (rha)
    23  * set_unknowns had "keep" as default instead of "remove" (from phplib-devel)
    24  * set_file failed to check for empty strings if passed an array of filenames (phplib-devel)
    25  * remove @ from call to preg_replace in subst -- report errors if there are any (NickM)
    26  * set_block unnecessarily required a newline in the template file (Marc Tardif)
    27  * pparse now calls this->finish to replace undefined vars (Layne Weathers)
    28  * get_var now checks for unset varnames (NickM & rha)
    29  * get_var when passed an array used the array key instead of the value (rha)
    30  * get_vars now uses a call to get_var rather than this->varvals to prevent undefined var warning (rha)
    31  * in finish, the replacement string referenced an unset variable (rha)
    32  * loadfile would try to load a file if the varval had been set to "" (rha)
    33  * in get_undefined, only match non-whitespace in variable tags as in finish (Layne Weathers & rha)
    34  * more elegant fix to the problem of subst stripping '$n', '\n' and '\\' strings (rha)
    35  *
    36  *
    37  * Changes in functionality which go beyond bug fixes:
    38  *
    39  * changed debug handling so set, get and internals can be tracked separately (rha)
    40  * added debug statements throughout to track most function calls (rha)
    41  * debug output contained raw HTML -- is now escaped with htmlentities (rha)
    42  * Alter regex in set_block to remove more whitespace around BEGIN/END tags to improve HTML layout (rha)
    43  * Add "append" option to set_var, works just like append in parse (dale at linuxwebpro.com, rha)
    44  * Altered parse so that append is honored if passed an array (Brian)
    45  * Converted comments and documentation to phpdoc style (rha)
    46  * Added clear_var to set the value of variables to "" (rha)
    47  * Added unset_var to usset variables (rha)
    48  *
    49  */
    50 
    51 /**
    52  * The template class allows you to keep your HTML code in some external files
    53  * which are completely free of PHP code, but contain replacement fields.
    54  * The class provides you with functions which can fill in the replacement fields
    55  * with arbitrary strings. These strings can become very large, e.g. entire tables.
    56  *
    57  * Note: If you think that this is like FastTemplates, read carefully. It isn't.
    58  *
    59  */
    60 
    61 class Template
    62 {
    63  /**
    64   * Serialization helper, the name of this class.
    65   *
    66   * @var       string
    67   * @access    public
    68   */
    69   var $classname = 'Template';
    70 
    71  /**
    72   * Determines how much debugging output Template will produce.
    73   * This is a bitwise mask of available debug levels:
    74   * 0 = no debugging
    75   * 1 = debug variable assignments
    76   * 2 = debug calls to get variable
    77   * 4 = debug internals (outputs all function calls with parameters).
    78   *
    79   * Note: setting $this->debug = true will enable debugging of variable
    80   * assignments only which is the same behaviour as versions up to release 7.2d.
    81   *
    82   * @var       int
    83   * @access    public
    84   */
    85   var $debug    = false;
    86 
    87  /**
    88   * The base directory from which template files are loaded.
    89   *
    90   * @var       string
    91   * @access    private
    92   * @see       set_root
    93   */
    94   var $root     = '.';
    95 
    96  /**
    97   * A hash of strings forming a translation table which translates variable names
    98   * into names of files containing the variable content.
    99   * $file[varname] = "filename";
   100   *
   101   * @var       array
   102   * @access    private
   103   * @see       set_file
   104   */
   105   var $file     = array();
   106 
   107  /**
   108   * A hash of strings forming a translation table which translates variable names
   109   * into values for their respective varkeys.
   110   * $varvals[varname] = "value"
   111   *
   112   * @var       array
   113   * @access    private
   114   * @see       set_var
   115   */
   116   var $varvals  = array();
   117 
   118  /**
   119   * Determines how to output variable tags with no assigned value in templates.
   120   *
   121   * @var       string
   122   * @access    private
   123   * @see       set_unknowns
   124   */
   125   var $unknowns = 'remove';
   126 
   127  /**
   128   * Determines how Template handles error conditions.
   129   * "yes"      = the error is reported, then execution is halted
   130   * "report"   = the error is reported, then execution continues by returning "false"
   131   * "no"       = errors are silently ignored, and execution resumes reporting "false"
   132   *
   133   * @var       string
   134   * @access    public
   135   * @see       halt
   136   */
   137   var $halt_on_error  = 'yes';
   138 
   139  /**
   140   * The last error message is retained in this variable.
   141   *
   142   * @var       string
   143   * @access    public
   144   * @see       halt
   145   */
   146   var $last_error     = '';
   147 
   148  /******************************************************************************
   149   * Class constructor. May be called with two optional parameters.
   150   * The first parameter sets the template directory the second parameter
   151   * sets the policy regarding handling of unknown variables.
   152   *
   153   * usage: Template([string $root = "."], [string $unknowns = "remove"])
   154   *
   155   * @param     $root        path to template directory
   156   * @param     $string      what to do with undefined variables
   157   * @see       set_root
   158   * @see       set_unknowns
   159   * @access    public
   160   * @return    void
   161   */
   162   function Template($root = '.', $unknowns = 'remove') {
   163     if ($this->debug & 4) {
   164       echo "<p><b>Template:</b> root = $root, unknowns = $unknowns</p>\n";
   165     }
   166     $this->set_root($root);
   167     $this->set_unknowns($unknowns);
   168   }
   169 
   170 
   171  /******************************************************************************
   172   * Checks that $root is a valid directory and if so sets this directory as the
   173   * base directory from which templates are loaded by storing the value in
   174   * $this->root. Relative filenames are prepended with the path in $this->root.
   175   *
   176   * Returns true on success, false on error.
   177   *
   178   * usage: set_root(string $root)
   179   *
   180   * @param     $root         string containing new template directory
   181   * @see       root
   182   * @access    public
   183   * @return    boolean
   184   */
   185   function set_root($root) {
   186     if ($this->debug & 4) {
   187       echo "<p><b>set_root:</b> root = $root</p>\n";
   188     }
   189     if (substr ($root, -1) == '/') {
   190       $root = substr ($root, 0, -1);
   191     }
   192     if (!is_dir($root)) {
   193       $this->halt("set_root: $root is not a directory.");
   194       return false;
   195     }
   196 
   197     $this->root = $root;
   198     return true;
   199   }
   200 
   201 
   202  /******************************************************************************
   203   * Sets the policy for dealing with unresolved variable names.
   204   *
   205   * unknowns defines what to do with undefined template variables
   206   * "remove"   = remove undefined variables
   207   * "comment"  = replace undefined variables with comments
   208   * "keep"     = keep undefined variables
   209   *
   210   * Note: "comment" can cause unexpected results when the variable tag is embedded
   211   * inside an HTML tag, for example a tag which is expected to be replaced with a URL.
   212   *
   213   * usage: set_unknowns(string $unknowns)
   214   *
   215   * @param     $unknowns         new value for unknowns
   216   * @see       unknowns
   217   * @access    public
   218   * @return    void
   219   */
   220   function set_unknowns($unknowns = 'remove') {
   221     if ($this->debug & 4) {
   222       echo "<p><b>unknowns:</b> unknowns = $unknowns</p>\n";
   223     }
   224     $this->unknowns = $unknowns;
   225   }
   226 
   227 
   228  /******************************************************************************
   229   * Defines a filename for the initial value of a variable.
   230   *
   231   * It may be passed either a varname and a file name as two strings or
   232   * a hash of strings with the key being the varname and the value
   233   * being the file name.
   234   *
   235   * The new mappings are stored in the array $this->file.
   236   * The files are not loaded yet, but only when needed.
   237   *
   238   * Returns true on success, false on error.
   239   *
   240   * usage: set_file(array $filelist = (string $varname => string $filename))
   241   * or
   242   * usage: set_file(string $varname, string $filename)
   243   *
   244   * @param     $varname      either a string containing a varname or a hash of varname/file name pairs.
   245   * @param     $filename     if varname is a string this is the filename otherwise filename is not required
   246   * @access    public
   247   * @return    boolean
   248   */
   249   function set_file($varname, $filename = '') {
   250     if (!is_array($varname)) {
   251       if ($this->debug & 4) {
   252         echo "<p><b>set_file:</b> (with scalar) varname = $varname, filename = $filename</p>\n";
   253       }
   254       if ($filename == '') {
   255         $this->halt("set_file: For varname $varname filename is empty.");
   256         return false;
   257       }
   258       $this->file[$varname] = $this->filename($filename);
   259     } else {
   260       foreach ($varname as $v => $f) {
   261         if ($this->debug & 4) {
   262           echo "<p><b>set_file:</b> (with array) varname = $v, filename = $f</p>\n";
   263         }
   264         if ($f == '') {
   265           $this->halt("set_file: For varname $v filename is empty.");
   266           return false;
   267         }
   268         $this->file[$v] = $this->filename($f);
   269       }
   270     }
   271     return true;
   272   }
   273 
   274 
   275  /******************************************************************************
   276   * A variable $parent may contain a variable block defined by:
   277   * &lt;!-- BEGIN $varname --&gt; content &lt;!-- END $varname --&gt;. This function removes
   278   * that block from $parent and replaces it with a variable reference named $name.
   279   * The block is inserted into the varvals hashes. If $name is
   280   * omitted, it is assumed to be the same as $varname.
   281   *
   282   * Blocks may be nested but care must be taken to extract the blocks in order
   283   * from the innermost block to the outermost block.
   284   *
   285   * Returns true on success, false on error.
   286   *
   287   * usage: set_block(string $parent, string $varname, [string $name = ""])
   288   *
   289   * @param     $parent       a string containing the name of the parent variable
   290   * @param     $varname      a string containing the name of the block to be extracted
   291   * @param     $name         the name of the variable in which to store the block
   292   * @access    public
   293   * @return    boolean
   294   */
   295   function set_block($parent, $varname, $name = '') {
   296     if ($this->debug & 4) {
   297       echo "<p><b>set_block:</b> parent = $parent, varname = $varname, name = $name</p>\n";
   298     }
   299     if (!$this->loadfile($parent)) {
   300       $this->halt("set_block: unable to load $parent.");
   301       return false;
   302     }
   303     if ($name == '') {
   304       $name = $varname;
   305     }
   306 
   307     $str = $this->get_var($parent);
   308     $reg = "/[ \t]*<!--\s+BEGIN $varname\s+-->\s*?\n?(\s*.*?\n?)\s*<!--\s+END $varname\s+-->\s*?\n?/sm";
   309     preg_match_all($reg, $str, $m);
   310     $str = str_replace($m[0][0], '{' . $name . '}', $str);
   311     $this->set_var($varname, $m[1][0]);
   312     $this->set_var($parent, $str);
   313     return true;
   314   }
   315 
   316 
   317  /******************************************************************************
   318   * This functions sets the value of a variable.
   319   *
   320   * It may be called with either a varname and a value as two strings or an
   321   * an associative array with the key being the varname and the value being
   322   * the new variable value.
   323   *
   324   * The function inserts the new value of the variable into the $varvals hashes.
   325   * It is not necessary for a variable to exist in these hashes before calling
   326   * this function.
   327   *
   328   * An optional third parameter allows the value for each varname to be appended
   329   * to the existing variable instead of replacing it. The default is to replace.
   330   * This feature was introduced after the 7.2d release.
   331   *
   332   *
   333   * usage: set_var(string $varname, [string $value = ""], [boolean $append = false])
   334   * or
   335   * usage: set_var(array $varname = (string $varname => string $value), [mixed $dummy_var], [boolean $append = false])
   336   *
   337   * @param     $varname      either a string containing a varname or a hash of varname/value pairs.
   338   * @param     $value        if $varname is a string this contains the new value for the variable otherwise this parameter is ignored
   339   * @param     $append       if true, the value is appended to the variable's existing value
   340   * @access    public
   341   * @return    void
   342   */
   343   function set_var($varname, $value = '', $append = false) {
   344     if (!is_array($varname)) {
   345       if (!empty($varname)) {
   346         if ($this->debug & 1) {
   347           printf("<b>set_var:</b> (with scalar) <b>%s</b> = '%s'<br" . XHTML . ">\n", $varname, htmlentities($value));
   348         }
   349         if ($append && isset($this->varvals[$varname])) {
   350           $this->varvals[$varname] .= $value;
   351         } else {
   352           $this->varvals[$varname] = $value;
   353         }
   354       }
   355     } else {
   356       foreach ($varname as $k => $v) {
   357         if (!empty($k)) {
   358           if ($this->debug & 1) {
   359             printf("<b>set_var:</b> (with array) <b>%s</b> = '%s'<br" . XHTML . ">\n", $k, htmlentities($v));
   360           }
   361           if ($append && isset($this->varvals[$k])) {
   362             $this->varvals[$k] .= $v;
   363           } else {
   364             $this->varvals[$k] = $v;
   365           }
   366         }
   367       }
   368     }
   369   }
   370 
   371 
   372  /******************************************************************************
   373   * This functions clears the value of a variable.
   374   *
   375   * It may be called with either a varname as a string or an array with the 
   376   * values being the varnames to be cleared.
   377   *
   378   * The function sets the value of the variable in the $varvals hashes to "".
   379   * It is not necessary for a variable to exist in these hashes before calling
   380   * this function.
   381   *
   382   *
   383   * usage: clear_var(string $varname)
   384   * or
   385   * usage: clear_var(array $varname = (string $varname))
   386   *
   387   * @param     $varname      either a string containing a varname or an array of varnames.
   388   * @access    public
   389   * @return    void
   390   */
   391   function clear_var($varname) {
   392     if (!is_array($varname)) {
   393       if (!empty($varname)) {
   394         if ($this->debug & 1) {
   395           printf("<b>clear_var:</b> (with scalar) <b>%s</b><br" . XHTML . ">\n", $varname);
   396         }
   397         $this->set_var($varname, '');
   398       }
   399     } else {
   400       foreach ($varname as $v) {
   401         if (!empty($v)) {
   402           if ($this->debug & 1) {
   403             printf("<b>clear_var:</b> (with array) <b>%s</b><br" . XHTML . ">\n", $v);
   404           }
   405           $this->set_var($v, '');
   406         }
   407       }
   408     }
   409   }
   410 
   411 
   412  /******************************************************************************
   413   * This functions unsets a variable completely.
   414   *
   415   * It may be called with either a varname as a string or an array with the 
   416   * values being the varnames to be cleared.
   417   *
   418   * The function removes the variable from the $varkeys and $varvals hashes.
   419   * It is not necessary for a variable to exist in these hashes before calling
   420   * this function.
   421   *
   422   *
   423   * usage: unset_var(string $varname)
   424   * or
   425   * usage: unset_var(array $varname = (string $varname))
   426   *
   427   * @param     $varname      either a string containing a varname or an array of varnames.
   428   * @access    public
   429   * @return    void
   430   */
   431   function unset_var($varname) {
   432     if (!is_array($varname)) {
   433       if (!empty($varname)) {
   434         if ($this->debug & 1) {
   435           printf("<b>unset_var:</b> (with scalar) <b>%s</b><br" . XHTML . ">\n", $varname);
   436         }
   437         unset($this->varvals[$varname]);
   438       }
   439     } else {
   440       foreach ($varname as $v) {
   441         if (!empty($v)) {
   442           if ($this->debug & 1) {
   443             printf("<b>unset_var:</b> (with array) <b>%s</b><br" . XHTML . ">\n", $v);
   444           }
   445           unset($this->varvals[$v]);
   446         }
   447       }
   448     }
   449   }
   450 
   451 
   452  /******************************************************************************
   453   * This function fills in all the variables contained within the variable named
   454   * $varname. The resulting value is returned as the function result and the
   455   * original value of the variable varname is not changed. The resulting string
   456   * is not "finished", that is, the unresolved variable name policy has not been
   457   * applied yet.
   458   *
   459   * Returns: the value of the variable $varname with all variables substituted.
   460   *
   461   * usage: subst(string $varname)
   462   *
   463   * @param     $varname      the name of the variable within which variables are to be substituted
   464   * @access    public
   465   * @return    string
   466   */
   467   function subst($varname) {
   468     if ($this->debug & 4) {
   469       echo "<p><b>subst:</b> varname = $varname</p>\n";
   470     }
   471     if (!$this->loadfile($varname)) {
   472       $this->halt("subst: unable to load $varname.");
   473       return false;
   474     }
   475     
   476 	$varkeys = array_map(
   477 		create_function('$a', 'return "{" . $a . "}";'),
   478 		array_keys($this->varvals)
   479 	);
   480     $str = $this->get_var($varname);
   481     $str = str_replace($varkeys, array_values($this->varvals), $str);
   482     return $str;
   483   }
   484 
   485 
   486  /******************************************************************************
   487   * This is shorthand for print $this->subst($varname). See subst for further
   488   * details.
   489   *
   490   * Returns: always returns false.
   491   *
   492   * usage: psubst(string $varname)
   493   *
   494   * @param     $varname      the name of the variable within which variables are to be substituted
   495   * @access    public
   496   * @return    false
   497   * @see       subst
   498   */
   499   function psubst($varname) {
   500     if ($this->debug & 4) {
   501       echo "<p><b>psubst:</b> varname = $varname</p>\n";
   502     }
   503     print $this->subst($varname);
   504 
   505     return false;
   506   }
   507 
   508 
   509  /******************************************************************************
   510   * The function substitutes the values of all defined variables in the variable
   511   * named $varname and stores or appends the result in the variable named $target.
   512   *
   513   * It may be called with either a target and a varname as two strings or a
   514   * target as a string and an array of variable names in varname.
   515   *
   516   * The function inserts the new value of the variable into the $varvals hashes.
   517   * It is not necessary for a variable to exist in these hashes before calling
   518   * this function.
   519   *
   520   * An optional third parameter allows the value for each varname to be appended
   521   * to the existing target variable instead of replacing it. The default is to
   522   * replace.
   523   *
   524   * If $target and $varname are both strings, the substituted value of the
   525   * variable $varname is inserted into or appended to $target.
   526   *
   527   * If $handle is an array of variable names the variables named by $handle are
   528   * sequentially substituted and the result of each substitution step is
   529   * inserted into or appended to in $target. The resulting substitution is
   530   * available in the variable named by $target, as is each intermediate step
   531   * for the next $varname in sequence. Note that while it is possible, it
   532   * is only rarely desirable to call this function with an array of varnames
   533   * and with $append = true. This append feature was introduced after the 7.2d
   534   * release.
   535   *
   536   * Returns: the last value assigned to $target.
   537   *
   538   * usage: parse(string $target, string $varname, [boolean $append])
   539   * or
   540   * usage: parse(string $target, array $varname = (string $varname), [boolean $append])
   541   *
   542   * @param     $target      a string containing the name of the variable into which substituted $varnames are to be stored
   543   * @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
   544   * @param     $append      if true, the substituted variables are appended to $target otherwise the existing value of $target is replaced
   545   * @access    public
   546   * @return    string
   547   * @see       subst
   548   */
   549   function parse($target, $varname, $append = false) {
   550     if (!is_array($varname)) {
   551       if ($this->debug & 4) {
   552         echo "<p><b>parse:</b> (with scalar) target = $target, varname = $varname, append = $append</p>\n";
   553       }
   554       $str = $this->subst($varname);
   555       if ($append) {
   556         $this->set_var($target, $this->get_var($target) . $str);
   557       } else {
   558         $this->set_var($target, $str);
   559       }
   560     } else {
   561       foreach ($varname as $i => $v) {
   562         if ($this->debug & 4) {
   563           echo "<p><b>parse:</b> (with array) target = $target, i = $i, varname = $v, append = $append</p>\n";
   564         }
   565         $str = $this->subst($v);
   566         if ($append) {
   567           $this->set_var($target, $this->get_var($target) . $str);
   568         } else {
   569           $this->set_var($target, $str);
   570         }
   571       }
   572     }
   573 
   574     if ($this->debug & 4) {
   575       echo "<p><b>parse:</b> completed</p>\n";
   576     }
   577     return $str;
   578   }
   579 
   580 
   581  /******************************************************************************
   582   * This is shorthand for print $this->parse(...) and is functionally identical.
   583   * See parse for further details.
   584   *
   585   * Returns: always returns false.
   586   *
   587   * usage: pparse(string $target, string $varname, [boolean $append])
   588   * or
   589   * usage: pparse(string $target, array $varname = (string $varname), [boolean $append])
   590   *
   591   * @param     $target      a string containing the name of the variable into which substituted $varnames are to be stored
   592   * @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
   593   * @param     $append      if true, the substituted variables are appended to $target otherwise the existing value of $target is replaced
   594   * @access    public
   595   * @return    false
   596   * @see       parse
   597   */
   598   function pparse($target, $varname, $append = false) {
   599     if ($this->debug & 4) {
   600       echo "<p><b>pparse:</b> passing parameters to parse...</p>\n";
   601     }
   602     print $this->finish($this->parse($target, $varname, $append));
   603     return false;
   604   }
   605 
   606 
   607  /******************************************************************************
   608   * This function returns an associative array of all defined variables with the
   609   * name as the key and the value of the variable as the value.
   610   *
   611   * This is mostly useful for debugging. Also note that $this->debug can be used
   612   * to echo all variable assignments as they occur and to trace execution.
   613   *
   614   * Returns: a hash of all defined variable values keyed by their names.
   615   *
   616   * usage: get_vars()
   617   *
   618   * @access    public
   619   * @return    array
   620   * @see       $debug
   621   */
   622   function get_vars() {
   623     if ($this->debug & 4) {
   624       echo "<p><b>get_vars:</b> constructing array of vars...</p>\n";
   625     }
   626     return $this->varvals;
   627   }
   628 
   629 
   630  /******************************************************************************
   631   * This function returns the value of the variable named by $varname.
   632   * If $varname references a file and that file has not been loaded yet, the
   633   * variable will be reported as empty.
   634   *
   635   * When called with an array of variable names this function will return a a
   636   * hash of variable values keyed by their names.
   637   *
   638   * Returns: a string or an array containing the value of $varname.
   639   *
   640   * usage: get_var(string $varname)
   641   * or
   642   * usage: get_var(array $varname)
   643   *
   644   * @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
   645   * @access    public
   646   * @return    string or array
   647   */
   648   function get_var($varname) {
   649     if (!is_array($varname)) {
   650       if (isset($this->varvals[$varname])) {
   651         $str = $this->varvals[$varname];
   652       } else {
   653         $str = '';
   654       }
   655       if ($this->debug & 2) {
   656         printf ("<b>get_var</b> (with scalar) <b>%s</b> = '%s'<br" . XHTML . ">\n", $varname, htmlentities($str));
   657       }
   658       return $str;
   659     } else {
   660       foreach ($varname as $v) {
   661         if (isset($this->varvals[$v])) {
   662           $str = $this->varvals[$v];
   663         } else {
   664           $str = '';
   665         }
   666         if ($this->debug & 2) {
   667           printf ("<b>get_var:</b> (with array) <b>%s</b> = '%s'<br" . XHTML . ">\n", $v, htmlentities($str));
   668         }
   669         $result[$v] = $str;
   670       }
   671       return $result;
   672     }
   673   }
   674 
   675 
   676  /******************************************************************************
   677   * This function returns a hash of unresolved variable names in $varname, keyed
   678   * by their names (that is, the hash has the form $a[$name] = $name).
   679   *
   680   * Returns: a hash of varname/varname pairs or false on error.
   681   *
   682   * usage: get_undefined(string $varname)
   683   *
   684   * @param     $varname     a string containing the name the name of the variable to scan for unresolved variables
   685   * @access    public
   686   * @return    array
   687   */
   688   function get_undefined($varname) {
   689     if ($this->debug & 4) {
   690       echo "<p><b>get_undefined:</b> varname = $varname</p>\n";
   691     }
   692     if (!$this->loadfile($varname)) {
   693       $this->halt("get_undefined: unable to load $varname.");
   694       return false;
   695     }
   696 
   697     preg_match_all('/{([^ \t\r\n}]+)}/', $this->get_var($varname), $m);
   698     $m = $m[1];
   699     if (!is_array($m)) {
   700       return false;
   701     }
   702 
   703     foreach ($m as $v) {
   704       if (!array_key_exists($v, $this->varvals)) {
   705         if ($this->debug & 4) {
   706          echo "<p><b>get_undefined:</b> undefined: $v</p>\n";
   707         }
   708         $result[$v] = $v;
   709       }
   710     }
   711 
   712     if (count($result)) {
   713       return $result;
   714     } else {
   715       return false;
   716     }
   717   }
   718 
   719 
   720  /******************************************************************************
   721   * This function returns the finished version of $str. That is, the policy
   722   * regarding unresolved variable names will be applied to $str.
   723   *
   724   * Returns: a finished string derived from $str and $this->unknowns.
   725   *
   726   * usage: finish(string $str)
   727   *
   728   * @param     $str         a string to which to apply the unresolved variable policy
   729   * @access    public
   730   * @return    string
   731   * @see       set_unknowns
   732   */
   733   function finish($str) {
   734     switch ($this->unknowns) {
   735       case 'keep':
   736       break;
   737 
   738       case 'remove':
   739         $str = preg_replace('/{[^ \t\r\n}]+}/', '', $str);
   740       break;
   741 
   742       case 'comment':
   743         $str = preg_replace('/{([^ \t\r\n}]+)}/', "<!-- Template variable \\1 undefined -->", $str);
   744       break;
   745     }
   746 
   747     return $str;
   748   }
   749 
   750 
   751  /******************************************************************************
   752   * This function prints the finished version of the value of the variable named
   753   * by $varname. That is, the policy regarding unresolved variable names will be
   754   * applied to the variable $varname then it will be printed.
   755   *
   756   * usage: p(string $varname)
   757   *
   758   * @param     $varname     a string containing the name of the variable to finish and print
   759   * @access    public
   760   * @return    void
   761   * @see       set_unknowns
   762   * @see       finish
   763   */
   764   function p($varname) {
   765     print $this->finish($this->get_var($varname));
   766   }
   767 
   768 
   769  /******************************************************************************
   770   * This function returns the finished version of the value of the variable named
   771   * by $varname. That is, the policy regarding unresolved variable names will be
   772   * applied to the variable $varname and the result returned.
   773   *
   774   * Returns: a finished string derived from the variable $varname.
   775   *
   776   * usage: get(string $varname)
   777   *
   778   * @param     $varname     a string containing the name of the variable to finish
   779   * @access    public
   780   * @return    void
   781   * @see       set_unknowns
   782   * @see       finish
   783   */
   784   function get($varname) {
   785     return $this->finish($this->get_var($varname));
   786   }
   787 
   788 
   789  /******************************************************************************
   790   * When called with a relative pathname, this function will return the pathname
   791   * with $this->root prepended. Absolute pathnames are returned unchanged.
   792   *
   793   * Returns: a string containing an absolute pathname.
   794   *
   795   * usage: filename(string $filename)
   796   *
   797   * @param     $filename    a string containing a filename
   798   * @access    private
   799   * @return    string
   800   * @see       set_root
   801   */
   802   function filename($filename) {
   803     if ($this->debug & 4) {
   804       echo "<p><b>filename:</b> filename = $filename</p>\n";
   805     }
   806 
   807     // Test if file exist and add physical path as 2nd test
   808     if (!file_exists($filename)) {
   809         // Try appending file to template root
   810         $filename = $this->root.'/'.$filename;
   811         if (!file_exists($filename)) {
   812             $this->halt("filename: file $filename does not exist.");
   813         }
   814     }
   815     return $filename;
   816   }
   817 
   818 
   819  /******************************************************************************
   820   * If a variable's value is undefined and the variable has a filename stored in
   821   * $this->file[$varname] then the backing file will be loaded and the file's
   822   * contents will be assigned as the variable's value.
   823   *
   824   * Note that the behaviour of this function changed slightly after the 7.2d
   825   * release. Where previously a variable was reloaded from file if the value
   826   * was empty, now this is not done. This allows a variable to be loaded then
   827   * set to "", and also prevents attempts to load empty variables. Files are
   828   * now only loaded if $this->varvals[$varname] is unset.
   829   *
   830   * Returns: true on success, false on error.
   831   *
   832   * usage: loadfile(string $varname)
   833   *
   834   * @param     $varname    a string containing the name of a variable to load
   835   * @access    private
   836   * @return    boolean
   837   * @see       set_file
   838   */
   839   function loadfile($varname) {
   840     if ($this->debug & 4) {
   841       echo "<p><b>loadfile:</b> varname = $varname</p>\n";
   842     }
   843 
   844     if (!isset($this->file[$varname])) {
   845       // $varname does not reference a file so return
   846       if ($this->debug & 4) {
   847         echo "<p><b>loadfile:</b> varname $varname does not reference a file</p>\n";
   848       }
   849       return true;
   850     }
   851 
   852     if (isset($this->varvals[$varname])) {
   853       // will only be unset if varname was created with set_file and has never been loaded
   854       // $varname has already been loaded so return
   855       if ($this->debug & 4) {
   856         echo "<p><b>loadfile:</b> varname $varname is already loaded</p>\n";
   857       }
   858       return true;
   859     }
   860     $filename = $this->file[$varname];
   861     $str = @file_get_contents($filename);
   862     if (empty($str)) {
   863       $this->halt("loadfile: While loading $varname, $filename does not exist or is empty.");
   864       return false;
   865     }
   866 
   867     if ($this->debug & 4) {
   868       printf("<b>loadfile:</b> loaded $filename into $varname<br" . XHTML . ">\n");
   869     }
   870     $this->set_var($varname, $str);
   871 
   872     return true;
   873   }
   874 
   875 
   876  /******************************************************************************
   877   * This function is called whenever an error occurs and will handle the error
   878   * according to the policy defined in $this->halt_on_error. Additionally the
   879   * error message will be saved in $this->last_error.
   880   *
   881   * Returns: always returns false.
   882   *
   883   * usage: halt(string $msg)
   884   *
   885   * @param     $msg         a string containing an error message
   886   * @access    private
   887   * @return    void
   888   * @see       $halt_on_error
   889   */
   890   function halt($msg) {
   891     $this->last_error = $msg;
   892 
   893     if ($this->halt_on_error != 'no') {
   894       $this->haltmsg($msg);
   895     }
   896 
   897     /* we won't be coming back from haltmsg() in that case anyway
   898     if ($this->halt_on_error == 'yes') {
   899       die("<b>Halted.</b>");
   900     }
   901     */
   902 
   903     return false;
   904   }
   905 
   906 
   907  /******************************************************************************
   908   * This function prints an error message.
   909   * It can be overridden by your subclass of Template. It will be called with an
   910   * error message to display.
   911   *
   912   * usage: haltmsg(string $msg)
   913   *
   914   * @param     $msg         a string containing the error message to display
   915   * @access    public
   916   * @return    void
   917   * @see       halt
   918   */
   919   function haltmsg($msg) {
   920     if ($this->halt_on_error == 'yes') {
   921       trigger_error(sprintf("Template Error: %s", $msg));
   922     } else {
   923       printf("<b>Template Error:</b> %s<br" . XHTML . ">\n", $msg);
   924     }
   925   }
   926 
   927 }
   928 ?>