<?php class ubF_templates { // Holds the array of filehandles FILELIST[HANDLE] == "fileName" var $FILELIST = array(); // Holds the array of dynamic blocks, and the fileHandles they live in. var $DYNAMIC = array(); // Holds the array of Variable handles. PARSEVARS[HANDLE] == "value" var $PARSEVARS = array(); // We only want to load a template once - when it's used. LOADED[FILEHANDLE] == 1 if loaded undefined if not loaded yet. var $LOADED = array(); var $HANDLE = array(); // Holds the handle names assigned by a call to parse() var $ROOT = ""; // Holds path-to-templates var $WIN32 = false; // Set to true if this is a WIN32 server // Holds the last error message var $ERROR = ""; // Holds the HANDLE to the last template parsed by parse() var $LAST = ""; // Strict template checking. Unresolved vars in templates will generate a warning when found. var $STRICT = true; // ************************************************************ function ubF_templates($pathToTemplates = "") { global $php_errormsg; if (! empty($pathToTemplates)) $this->set_root($pathToTemplates); } // end (new) FastTemplate () /** * * All templates will be loaded from this "root" directory * Can be changed in mid-process by re-calling with a new * value. * * @param unknown $root */ public function set_root($root) { $trailer = substr($root, - 1); if (! $this->WIN32) { if ((ord($trailer)) != 47) $root = "$root" . chr(47); if (is_dir($root)) $this->ROOT = $root; else { $this->ROOT = ""; $this->error("Specified ROOT dir [$root] is not a directory"); } } else { // WIN32 box - no testing if ((ord($trailer)) != 92) $root = "$root" . chr(92); $this->ROOT = $root; } } // End set_root() // ************************************************************** // Calculates current microtime // I throw this into all my classes for benchmarking purposes // It's not used by anything in this class and can be removed // if you don't need it. function utime() { $time = explode(" ", microtime()); $usec = (double) $time[0]; $sec = (double) $time[1]; return $sec + $usec; } // ************************************************************** // Strict template checking, if true sends warnings to STDOUT when // parsing a template with undefined variable references // Used for tracking down bugs-n-such. Use no_strict() to disable. function strict() { $this->STRICT = true; } // ************************************************************ // Silently discards (removes) undefined variable references // found in templates function no_strict() { $this->STRICT = false; } // ************************************************************ // A quick check of the template file before reading it. // This is -not- a reliable check, mostly due to inconsistencies // in the way PHP determines if a file is readable. function is_safe($filename) { if (! file_exists($filename)) { $this->error("[$filename] does not exist", 0); return false; } return true; } // ************************************************************ // Grabs a template from the root dir and // reads it into a (potentially REALLY) big string function get_template($template) { if (empty($this->ROOT)) { $this->error("Cannot open template. Root not valid.", 1); return false; } $filename = "$this->ROOT" . "$template"; $contents = implode("", (@file($filename))); if ((! $contents) or (empty($contents))) { $this->error("get_template() failure: [$filename] $php_errormsg", 1); } return $contents; } // end get_template // ************************************************************ // Prints the warnings for unresolved variable references // in template files. Used if STRICT is true function show_unknowns($Line) { $unknown = array(); if (preg_match("({[A-Z0-9_]+})", $Line, $unknown)) { if (isset($unknown[1])) $UnkVar = $unknown[1]; if (! (empty($UnkVar))) { @error_log("[FastTemplate] Warning: no value found for variable: $UnkVar ", 0); } } } // end show_unknowns() // ************************************************************ // This routine get's called by parse() and does the actual // {VAR} to VALUE conversion within the template. function parse_template($template, $tpl_array) { while (list ($key, $val) = each($tpl_array)) { if (! (empty($key))) { if (gettype($val) != "string") { settype($val, "string"); } // php4 doesn't like '{$' combinations. $key = '{' . "$key" . '}'; // $template = preg_replace("$key","$val","$template"); $template = str_replace("$key", "$val", "$template"); } } if (! $this->STRICT) { // Silently remove anything not already found $template = preg_replace("{([A-Z0-9_]+)}", "", $template); } else { // Warn about unresolved template variables if (preg_match("({[A-Z0-9_]+})", $template)) { $unknown = preg_split("/\n/", $template); while (list ($Element, $Line) = each($unknown)) { $UnkVar = $Line; if (! (empty($UnkVar))) { $this->show_unknowns($UnkVar); } } } } return $template; } // end parse_template(); // ************************************************************ // The meat of the whole class. The magic happens here. function parse($ReturnVar, $FileTags) { $append = false; $this->LAST = $ReturnVar; $this->HANDLE[$ReturnVar] = 1; if (gettype($FileTags) == "array") { unset($this->$ReturnVar); // Clear any previous data while (list ($key, $val) = each($FileTags)) { if ((! isset($this->$val)) || (empty($this->$val))) { $this->LOADED["$val"] = 1; if (isset($this->DYNAMIC["$val"])) { $this->parse_dynamic($val, $ReturnVar); } else { $fileName = $this->FILELIST[$val]; $this->$val = $this->get_template($fileName); } } // Array context implies overwrite $this->$ReturnVar = $this->parse_template($this->$val, $this->PARSEVARS); // For recursive calls. $this->assign(array( $ReturnVar => $this->$ReturnVar )); } } // end if FileTags is array() else { // FileTags is not an array $val = $FileTags; if ((substr($val, 0, 1)) == '.') { // Append this template to a previous ReturnVar $append = true; $val = substr($val, 1); } if ((! isset($this->$val)) || (empty($this->$val))) { $this->LOADED["$val"] = 1; if (isset($this->DYNAMIC["$val"])) { $this->parse_dynamic($val, $ReturnVar); } else { $fileName = $this->FILELIST[$val]; $this->$val = $this->get_template($fileName); } } if ($append) { $this->$ReturnVar .= $this->parse_template($this->$val, $this->PARSEVARS); } else { $this->$ReturnVar = $this->parse_template($this->$val, $this->PARSEVARS); } // For recursive calls. $this->assign(array( $ReturnVar => $this->$ReturnVar )); } return; } // End parse() // ************************************************************ function FastPrint($template = "") { if (empty($template)) { $template = $this->LAST; } if ((! (isset($this->$template))) || (empty($this->$template))) { $this->error("Nothing parsed, nothing printed", 0); return; } else { print $this->$template; } return; } // ************************************************************ function fetch($template = "") { if (empty($template)) $template = $this->LAST; if ((! (isset($this->$template))) || (empty($this->$template))) { $this->error("Nothing parsed, nothing printed", 0); return ""; } return ($this->$template); } // ************************************************************ function define_dynamic($Macro, $ParentName) { // A dynamic block lives inside another template file. // It will be stripped from the template when parsed // and replaced with the {$Tag}. $this->DYNAMIC["$Macro"] = $ParentName; return true; } // ************************************************************ function parse_dynamic($Macro, $MacroName) { // The file must already be in memory. $ParentTag = $this->DYNAMIC["$Macro"]; if ((! $this->$ParentTag) or (empty($this->$ParentTag))) { $fileName = $this->FILELIST[$ParentTag]; $this->$ParentTag = $this->get_template($fileName); $this->LOADED[$ParentTag] = 1; } if ($this->$ParentTag) { $template = $this->$ParentTag; $DataArray = split("\n", $template); $newMacro = ""; $newParent = ""; $outside = true; $start = false; $end = false; while (list ($lineNum, $lineData) = each($DataArray)) { $lineTest = trim($lineData); if ("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest") { $start = true; $end = false; $outside = false; } if ("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest") { $start = false; $end = true; $outside = true; } if ((! $outside) and (! $start) and (! $end)) { $newMacro .= "$lineData\n"; // Restore linebreaks } if (($outside) and (! $start) and (! $end)) { $newParent .= "$lineData\n"; // Restore linebreaks } if ($end) { $newParent .= '{' . "$MacroName}\n"; } // Next line please if ($end) { $end = false; } if ($start) { $start = false; } } // end While $this->$Macro = $newMacro; $this->$ParentTag = $newParent; return true; } // $ParentTag NOT loaded - MAJOR oopsie else { @error_log("ParentTag: [$ParentTag] not loaded!", 0); $this->error("ParentTag: [$ParentTag] not loaded!", 0); } return false; } // ************************************************************ // Strips a DYNAMIC BLOCK from a template. function clear_dynamic($Macro = "") { if (empty($Macro)) { return false; } // The file must already be in memory. $ParentTag = $this->DYNAMIC["$Macro"]; if ((! $this->$ParentTag) or (empty($this->$ParentTag))) { $fileName = $this->FILELIST[$ParentTag]; $this->$ParentTag = $this->get_template($fileName); $this->LOADED[$ParentTag] = 1; } if ($this->$ParentTag) { $template = $this->$ParentTag; $DataArray = split("\n", $template); $newParent = ""; $outside = true; $start = false; $end = false; while (list ($lineNum, $lineData) = each($DataArray)) { $lineTest = trim($lineData); if ("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest") { $start = true; $end = false; $outside = false; } if ("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest") { $start = false; $end = true; $outside = true; } if (($outside) and (! $start) and (! $end)) { $newParent .= "$lineData\n"; // Restore linebreaks } // Next line please if ($end) { $end = false; } if ($start) { $start = false; } } // end While $this->$ParentTag = $newParent; return true; } // $ParentTag NOT loaded - MAJOR oopsie else { @error_log("ParentTag: [$ParentTag] not loaded!", 0); $this->error("ParentTag: [$ParentTag] not loaded!", 0); } return false; } // ************************************************************ function define($fileList) { while (list ($FileTag, $FileName) = each($fileList)) { $this->FILELIST[$FileTag] = $FileName; } return true; } // ************************************************************ function clear_parse($ReturnVar = "") { $this->clear($ReturnVar); } // ************************************************************ function clear($ReturnVar = "") { // Clears out hash created by call to parse() if (! empty($ReturnVar)) { if ((gettype($ReturnVar)) != "array") { unset($this->$ReturnVar); return; } else { while (list ($key, $val) = each($ReturnVar)) { unset($this->$val); } return; } } // Empty - clear all of them while (list ($key, $val) = each($this->HANDLE)) { $KEY = $key; unset($this->$KEY); } return; } // end clear() // ************************************************************ function clear_all() { $this->clear(); $this->clear_assign(); $this->clear_define(); $this->clear_tpl(); return; } // end clear_all // ************************************************************ function clear_tpl($fileHandle = "") { if (empty($this->LOADED)) { // Nothing loaded, nothing to clear return true; } if (empty($fileHandle)) { // Clear ALL fileHandles while (list ($key, $val) = each($this->LOADED)) { unset($this->$key); } unset($this->LOADED); return true; } else { if ((gettype($fileHandle)) != "array") { if ((isset($this->$fileHandle)) || (! empty($this->$fileHandle))) { unset($this->LOADED[$fileHandle]); unset($this->$fileHandle); return true; } } else { while (list ($Key, $Val) = each($fileHandle)) { unset($this->LOADED[$Key]); unset($this->$Key); } return true; } } return false; } // end clear_tpl // ************************************************************ function clear_define($FileTag = "") { if (empty($FileTag)) { unset($this->FILELIST); return; } if ((gettype($Files)) != "array") { unset($this->FILELIST[$FileTag]); return; } else { while (list ($Tag, $Val) = each($FileTag)) { unset($this->FILELIST[$Tag]); } return; } } // ************************************************************ // Aliased function - used for compatibility with CGI::FastTemplate // function clear_parse () // { // $this->clear_assign(); // } // ************************************************************ // Clears all variables set by assign() function clear_assign() { if (! (empty($this->PARSEVARS))) { while (list ($Ref, $Val) = each($this->PARSEVARS)) { unset($this->PARSEVARS["$Ref"]); } } } // ************************************************************ function clear_href($href) { if (! empty($href)) { if ((gettype($href)) != "array") { unset($this->PARSEVARS[$href]); return; } else { while (list ($Ref, $val) = each($href)) { unset($this->PARSEVARS[$Ref]); } return; } } else { // Empty - clear them all $this->clear_assign(); } return; } // ************************************************************ function assign($tpl_array, $trailer = "") { if (gettype($tpl_array) == "array") { while (list ($key, $val) = each($tpl_array)) { if (! (empty($key))) { // Empty values are allowed // Empty Keys are NOT $this->PARSEVARS["$key"] = $val; } } } else { // Empty values are allowed in non-array context now. if (! empty($tpl_array)) { $this->PARSEVARS["$tpl_array"] = $trailer; } } } // ************************************************************ // Return the value of an assigned variable. // Christian Brandel cbrandel@gmx.de function get_assigned($tpl_name = "") { if (empty($tpl_name)) { return false; } if (isset($this->PARSEVARS["$tpl_name"])) { return ($this->PARSEVARS["$tpl_name"]); } else { return false; } } // ************************************************************ function error($errorMsg, $die = 0) { $this->ERROR = $errorMsg; echo "ERROR: $this->ERROR <BR> \n"; if ($die == 1) { exit(); } return; } // end error() // ************************************************************ // ************************************************************ } // End class.FastTemplate.php3 ?>