'; /** * Template block start word * * @access public * @var string */ public $block_start_word = 'BEGIN:'; /** * Template block end word * * The last 3 properties and this make the delimiters look like: * @example * if you use the default syntax. * * @access public * @var string */ public $block_end_word = 'END:'; /** * Template tag start delimiter * * This makes the delimiters look like: * @example {tagname} * if you use the default syntax. * * @access public * @var string */ public $tag_start_delim = '{'; /** * Template tag end delimiter * * This makes the delimiters look like: * @example {tagname} * if you use the default syntax. * * @access public * @var string */ public $tag_end_delim = '}'; /* this makes the delimiters look like: {tagname} if you use my syntax. */ /** * Regular expression element for comments within tags and blocks * * @example {tagname#My Comment} * @example {tagname #My Comment} * @example * @example * * @access public * @var string */ public $comment_preg = '( ?#.*?)?'; /** * Default main template block name * * @access public * @var string */ public $mainblock = 'main'; /** * Script output type * * @access public * @var string */ public $output_type = 'HTML'; /** * Debug mode * * @access public * @var boolean */ public $debug = false; /** * Null string for unassigned vars * * @access protected * @var array */ protected $_null_string = array('' => ''); /** * Null string for unassigned blocks * * @access protected * @var array */ protected $_null_block = array('' => ''); /** * Errors * * @access protected * @var string */ protected $_error = ''; /** * Auto-reset sub blocks * * @access protected * @var boolean */ protected $_autoreset = true; /** * Set to FALSE to generate errors if a non-existant blocks is referenced * * @author NW * @since 2002/10/17 * @access protected * @var boolean */ protected $_ignore_missing_blocks = true; /** * PHP 5 Constructor - Instantiate the object * * @param string $file Template file to work on * @param string/array $tpldir Location of template files (useful for keeping files outside web server root) * @param array $files Filenames lookup * @param string $mainblock Name of main block in the template * @param boolean $autosetup If true, run setup() as part of constuctor * @return XTemplate */ public function __construct($file, $tpldir = '', $files = null, $mainblock = 'main', $autosetup = true) { $this->restart($file, $tpldir, $files, $mainblock, $autosetup, $this->tag_start_delim, $this->tag_end_delim); } /** * PHP 4 Constructor - Instantiate the object * * @deprecated Use PHP 5 constructor instead * @param string $file Template file to work on * @param string/array $tpldir Location of template files (useful for keeping files outside web server root) * @param array $files Filenames lookup * @param string $mainblock Name of main block in the template * @param boolean $autosetup If true, run setup() as part of constuctor * @return XTemplate */ public function XTemplate ($file, $tpldir = '', $files = null, $mainblock = 'main', $autosetup = true) { assert('Deprecated - use PHP 5 constructor'); } /***************************************************************************/ /***[ public stuff ]********************************************************/ /***************************************************************************/ /** * Restart the class - allows one instantiation with several files processed by restarting * e.g. $xtpl = new XTemplate('file1.xtpl'); * $xtpl->parse('main'); * $xtpl->out('main'); * $xtpl->restart('file2.xtpl'); * $xtpl->parse('main'); * $xtpl->out('main'); * (Added in response to sf:641407 feature request) * * @param string $file Template file to work on * @param string/array $tpldir Location of template files * @param array $files Filenames lookup * @param string $mainblock Name of main block in the template * @param boolean $autosetup If true, run setup() as part of restarting * @param string $tag_start { * @param string $tag_end } */ public function restart ($file, $tpldir = '', $files = null, $mainblock = 'main', $autosetup = true, $tag_start = '{', $tag_end = '}') { $this->filename = $file; // From SF Feature request 1202027 // Kenneth Kalmer $this->tpldir = $tpldir; if (defined('XTPL_DIR') && empty($this->tpldir)) { $this->tpldir = XTPL_DIR; } if (is_array($files)) { $this->files = $files; } $this->mainblock = $mainblock; $this->tag_start_delim = $tag_start; $this->tag_end_delim = $tag_end; // Start with fresh file contents $this->filecontents = ''; // Reset the template arrays $this->blocks = array(); $this->parsed_blocks = array(); $this->preparsed_blocks = array(); $this->block_parse_order = array(); $this->sub_blocks = array(); $this->vars = array(); $this->filevars = array(); $this->filevar_parent = array(); $this->filecache = array(); if ($autosetup) { $this->setup(); } } /** * setup - the elements that were previously in the constructor * * @access public * @param boolean $add_outer If true is passed when called, it adds an outer main block to the file */ public function setup ($add_outer = false) { $this->tag_start_delim = preg_quote($this->tag_start_delim); $this->tag_end_delim = preg_quote($this->tag_end_delim); // Setup the file delimiters // regexp for file includes $this->file_delim = "/" . $this->tag_start_delim . "FILE\s*\"([^\"]+)\"" . $this->comment_preg . $this->tag_end_delim . "/m"; // regexp for file includes $this->filevar_delim = "/" . $this->tag_start_delim . "FILE\s*" . $this->tag_start_delim . "([A-Za-z0-9\._]+?)" . $this->comment_preg . $this->tag_end_delim . $this->comment_preg . $this->tag_end_delim . "/m"; // regexp for file includes w/ newlines $this->filevar_delim_nl = "/^\s*" . $this->tag_start_delim . "FILE\s*" . $this->tag_start_delim . "([A-Za-z0-9\._]+?)" . $this->comment_preg . $this->tag_end_delim . $this->comment_preg . $this->tag_end_delim . "\s*\n/m"; if (empty($this->filecontents)) { // read in template file $this->filecontents = $this->_r_getfile($this->filename); } if ($add_outer) { $this->_add_outer_block(); } // preprocess some stuff $this->blocks = $this->_maketree($this->filecontents, ''); $this->filevar_parent = $this->_store_filevar_parents($this->blocks); $this->scan_globals(); } /** * assign a variable * * @example Simplest case: * @example $xtpl->assign('name', 'value'); * @example {name} in template * * @example Array assign: * @example $xtpl->assign(array('name' => 'value', 'name2' => 'value2')); * @example {name} {name2} in template * * @example Value as array assign: * @example $xtpl->assign('name', array('key' => 'value', 'key2' => 'value2')); * @example {name.key} {name.key2} in template * * @example Reset array: * @example $xtpl->assign('name', array('key' => 'value', 'key2' => 'value2')); * @example // Other code then: * @example $xtpl->assign('name', array('key3' => 'value3'), false); * @example {name.key} {name.key2} {name.key3} in template * * @access public * @param string $name Variable to assign $val to * @param string / array $val Value to assign to $name * @param boolean $reset_array Reset the variable array if $val is an array */ public function assign ($name, $val = '', $reset_array = true) { if (is_array($name)) { foreach ($name as $k => $v) { $this->vars[$k] = $v; } } elseif (is_array($val)) { // Clear the existing values if ($reset_array) { $this->vars[$name] = array(); } foreach ($val as $k => $v) { $this->vars[$name][$k] = $v; } } else { $this->vars[$name] = $val; } } /** * assign a file variable * * @access public * @param string $name Variable to assign $val to * @param string / array $val Values to assign to $name */ public function assign_file ($name, $val = '') { if (is_array($name)) { foreach ($name as $k => $v) { $this->_assign_file_sub($k, $v); } } else { $this->_assign_file_sub($name, $val); } } /** * parse a block * * @access public * @param string $bname Block name to parse */ public function parse ($bname) { if (isset($this->preparsed_blocks[$bname])) { $copy = $this->preparsed_blocks[$bname]; } elseif (isset($this->blocks[$bname])) { $copy = $this->blocks[$bname]; } elseif ($this->_ignore_missing_blocks) { // ------------------------------------------------------ // NW : 17 Oct 2002. Added default of ignore_missing_blocks // to allow for generalised processing where some // blocks may be removed from the HTML without the // processing code needing to be altered. // ------------------------------------------------------ // JRC: 3/1/2003 added set error to ignore missing functionality $this->_set_error("parse: blockname [$bname] does not exist"); return; } else { $this->_set_error("parse: blockname [$bname] does not exist"); } /* from there we should have no more {FILE } directives */ if (!isset($copy)) { die('Block: ' . $bname); } $copy = preg_replace($this->filevar_delim_nl, '', $copy); $var_array = array(); /* find & replace variables+blocks */ preg_match_all("|" . $this->tag_start_delim . "([A-Za-z0-9\._]+?" . $this->comment_preg . ")" . $this->tag_end_delim. "|", $copy, $var_array); $var_array = $var_array[1]; foreach ($var_array as $k => $v) { // Are there any comments in the tags {tag#a comment for documenting the template} $any_comments = explode('#', $v); $v = rtrim($any_comments[0]); if (sizeof($any_comments) > 1) { $comments = $any_comments[1]; } else { $comments = ''; } $sub = explode('.', $v); if ($sub[0] == '_BLOCK_') { unset($sub[0]); $bname2 = implode('.', $sub); // trinary operator eliminates assign error in E_ALL reporting $var = isset($this->parsed_blocks[$bname2]) ? $this->parsed_blocks[$bname2] : null; $nul = (!isset($this->_null_block[$bname2])) ? $this->_null_block[''] : $this->_null_block[$bname2]; if ($var === '') { if ($nul == '') { // ----------------------------------------------------------- // Removed requirement for blocks to be at the start of string // ----------------------------------------------------------- // $copy=preg_replace("/^\s*\{".$v."\}\s*\n*/m","",$copy); // Now blocks don't need to be at the beginning of a line, //$copy=preg_replace("/\s*" . $this->tag_start_delim . $v . $this->tag_end_delim . "\s*\n*/m","",$copy); $copy = preg_replace("|" . $this->tag_start_delim . $v . $this->tag_end_delim . "|m", '', $copy); } else { $copy = preg_replace("|" . $this->tag_start_delim . $v . $this->tag_end_delim . "|m", "$nul", $copy); } } else { //$var = trim($var); switch (true) { case preg_match('/^\n/', $var) && preg_match('/\n$/', $var): $var = substr($var, 1, -1); break; case preg_match('/^\n/', $var): $var = substr($var, 1); break; case preg_match('/\n$/', $var): $var = substr($var, 0, -1); break; } // SF Bug no. 810773 - thanks anonymous $var = str_replace('\\', '\\\\', $var); // Ensure dollars in strings are not evaluated reported by SadGeezer 31/3/04 $var = str_replace('$', '\\$', $var); // Replaced str_replaces with preg_quote //$var = preg_quote($var); $var = str_replace('\\|', '|', $var); $copy = preg_replace("|" . $this->tag_start_delim . $v . $this->tag_end_delim . "|m", "$var", $copy); if (preg_match('/^\n/', $copy) && preg_match('/\n$/', $copy)) { $copy = substr($copy, 1, -1); } } } else { $var = $this->vars; foreach ($sub as $v1) { // NW 4 Oct 2002 - Added isset and is_array check to avoid NOTICE messages // JC 17 Oct 2002 - Changed EMPTY to stlen=0 // if (empty($var[$v1])) { // this line would think that zeros(0) were empty - which is not true if (!isset($var[$v1]) || (!is_array($var[$v1]) && strlen($var[$v1]) == 0)) { // Check for constant, when variable not assigned if (defined($v1)) { $var[$v1] = constant($v1); } else { $var[$v1] = null; } } $var = $var[$v1]; } $nul = (!isset($this->_null_string[$v])) ? ($this->_null_string[""]) : ($this->_null_string[$v]); $var = (!isset($var)) ? $nul : $var; if ($var === '') { // ----------------------------------------------------------- // Removed requriement for blocks to be at the start of string // ----------------------------------------------------------- // $copy=preg_replace("|^\s*\{".$v." ?#?".$comments."\}\s*\n|m","",$copy); $copy = preg_replace("|" . $this->tag_start_delim . $v . "( ?#" . $comments . ")?" . $this->tag_end_delim . "|m", '', $copy); } $var = trim($var); // SF Bug no. 810773 - thanks anonymous $var = str_replace('\\', '\\\\', $var); // Ensure dollars in strings are not evaluated reported by SadGeezer 31/3/04 $var = str_replace('$', '\\$', $var); // Replace str_replaces with preg_quote //$var = preg_quote($var); $var = str_replace('\\|', '|', $var); $copy = preg_replace("|" . $this->tag_start_delim . $v . "( ?#" . $comments . ")?" . $this->tag_end_delim . "|m", "$var", $copy); if (preg_match('/^\n/', $copy) && preg_match('/\n$/', $copy)) { $copy = substr($copy, 1); } } } if (isset($this->parsed_blocks[$bname])) { $this->parsed_blocks[$bname] .= $copy; } else { $this->parsed_blocks[$bname] = $copy; } /* reset sub-blocks */ if ($this->_autoreset && (!empty($this->sub_blocks[$bname]))) { reset($this->sub_blocks[$bname]); foreach ($this->sub_blocks[$bname] as $k => $v) { $this->reset($v); } } } /** * returns the parsed text for a block, including all sub-blocks. * * @access public * @param string $bname Block name to parse */ public function rparse ($bname) { if (!empty($this->sub_blocks[$bname])) { reset($this->sub_blocks[$bname]); foreach ($this->sub_blocks[$bname] as $k => $v) { if (!empty($v)) { $this->rparse($v); } } } $this->parse($bname); } /** * inserts a loop ( call assign & parse ) * * @access public * @param string $bname Block name to assign * @param string $var Variable to assign values to * @param string / array $value Value to assign to $var */ public function insert_loop ($bname, $var, $value = '') { $this->assign($var, $value); $this->parse($bname); } /** * parses a block for every set of data in the values array * * @access public * @param string $bname Block name to loop * @param string $var Variable to assign values to * @param array $values Values to assign to $var */ public function array_loop ($bname, $var, &$values) { if (is_array($values)) { foreach($values as $v) { $this->insert_loop($bname, $var, $v); } } } /** * returns the parsed text for a block * * @access public * @param string $bname Block name to return * @return string */ public function text ($bname = '') { $text = ''; if ($this->debug && $this->output_type == 'HTML') { // JC 20/11/02 echo the template filename if in development as // html comment $text .= '\n"; } $bname = !empty($bname) ? $bname : $this->mainblock; $text .= isset($this->parsed_blocks[$bname]) ? $this->parsed_blocks[$bname] : $this->get_error(); return str_replace(array("\r", "\n"), '', $text);//my edit //return $text; } /** * prints the parsed text * * @access public * @param string $bname Block name to echo out */ public function out ($bname) { $out = $this->text($bname); // $length=strlen($out); //header("Content-Length: ".$length); // TODO: Comment this back in later echo $out; } /** * prints the parsed text to a specified file * * @access public * @param string $bname Block name to write out * @param string $fname File name to write to */ public function out_file ($bname, $fname) { if (!empty($bname) && !empty($fname) && is_writeable($fname)) { $fp = fopen($fname, 'w'); fwrite($fp, $this->text($bname)); fclose($fp); } } /** * resets the parsed text * * @access public * @param string $bname Block to reset */ public function reset ($bname) { $this->parsed_blocks[$bname] = ''; } /** * returns true if block was parsed, false if not * * @access public * @param string $bname Block name to test * @return boolean */ public function parsed ($bname) { return (!empty($this->parsed_blocks[$bname])); } /** * sets the string to replace in case the var was not assigned * * @access public * @param string $str Display string for null block * @param string $varname Variable name to apply $str to */ public function set_null_string($str, $varname = '') { $this->_null_string[$varname] = $str; } /** * Backwards compatibility only * * @param string $str * @param string $varname * @deprecated Change to set_null_string to keep in with rest of naming convention */ public function SetNullString ($str, $varname = '') { $this->set_null_string($str, $varname); } /** * sets the string to replace in case the block was not parsed * * @access public * @param string $str Display string for null block * @param string $bname Block name to apply $str to */ public function set_null_block ($str, $bname = '') { $this->_null_block[$bname] = $str; } /** * Backwards compatibility only * * @param string $str * @param string $bname * @deprecated Change to set_null_block to keep in with rest of naming convention */ public function SetNullBlock ($str, $bname = '') { $this->set_null_block($str, $bname); } /** * sets AUTORESET to 1. (default is 1) * if set to 1, parse() automatically resets the parsed blocks' sub blocks * (for multiple level blocks) * * @access public */ public function set_autoreset () { $this->_autoreset = true; } /** * sets AUTORESET to 0. (default is 1) * if set to 1, parse() automatically resets the parsed blocks' sub blocks * (for multiple level blocks) * * @access public */ public function clear_autoreset () { $this->_autoreset = false; } /** * scans global variables and assigns to PHP array * * @access public */ public function scan_globals () { reset($GLOBALS); foreach ($GLOBALS as $k => $v) { $GLOB[$k] = $v; } /** * Access global variables as: * @example {PHP._SERVER.HTTP_HOST} * in your template! */ $this->assign('PHP', $GLOB); } /** * gets error condition / string * * @access public * @return boolean / string */ public function get_error () { // JRC: 3/1/2003 Added ouptut wrapper and detection of output type for error message output $retval = false; if ($this->_error != '') { switch ($this->output_type) { case 'HTML': case 'html': $retval = '[XTemplate]
'; var_dump(func_get_args()); echo ''; } } } /* end of XTemplate class. */ ?>