(file) Return to template.php CVS log (file) (dir) Up to [RizwankCVS] / geekymedia_web / phpBB2 / includes

  1 rizwank 1.1 <?php
  2             /***************************************************************************
  3              *                              template.php
  4              *                            -------------------
  5              *   begin                : Saturday, Feb 13, 2001
  6              *   copyright            : (C) 2001 The phpBB Group
  7              *   email                : support@phpbb.com
  8              *
  9              *   $Id: template.php,v 1.10.2.3 2002/12/21 19:09:57 psotfx Exp $
 10              *
 11              *
 12              ***************************************************************************/
 13             
 14             /***************************************************************************
 15              *
 16              *   This program is free software; you can redistribute it and/or modify
 17              *   it under the terms of the GNU General Public License as published by
 18              *   the Free Software Foundation; either version 2 of the License, or
 19              *   (at your option) any later version.
 20              *
 21              ***************************************************************************/
 22 rizwank 1.1 
 23             /**
 24              * Template class. By Nathan Codding of the phpBB group.
 25              * The interface was originally inspired by PHPLib templates,
 26              * and the template file formats are quite similar.
 27              *
 28              */
 29             
 30             class Template {
 31             	var $classname = "Template";
 32             
 33             	// variable that holds all the data we'll be substituting into
 34             	// the compiled templates.
 35             	// ...
 36             	// This will end up being a multi-dimensional array like this:
 37             	// $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
 38             	// if it's a root-level variable, it'll be like this:
 39             	// $this->_tpldata[.][0][varname] == value
 40             	var $_tpldata = array();
 41             
 42             	// Hash of filenames for each template handle.
 43 rizwank 1.1 	var $files = array();
 44             
 45             	// Root template directory.
 46             	var $root = "";
 47             
 48             	// this will hash handle names to the compiled code for that handle.
 49             	var $compiled_code = array();
 50             
 51             	// This will hold the uncompiled code for that handle.
 52             	var $uncompiled_code = array();
 53             
 54             	/**
 55             	 * Constructor. Simply sets the root dir.
 56             	 *
 57             	 */
 58             	function Template($root = ".")
 59             	{
 60             		$this->set_rootdir($root);
 61             	}
 62             
 63             	/**
 64 rizwank 1.1 	 * Destroys this template object. Should be called when you're done with it, in order
 65             	 * to clear out the template data so you can load/parse a new template set.
 66             	 */
 67             	function destroy()
 68             	{
 69             		$this->_tpldata = array();
 70             	}
 71             
 72             	/**
 73             	 * Sets the template root directory for this Template object.
 74             	 */
 75             	function set_rootdir($dir)
 76             	{
 77             		if (!is_dir($dir))
 78             		{
 79             			return false;
 80             		}
 81             
 82             		$this->root = $dir;
 83             		return true;
 84             	}
 85 rizwank 1.1 
 86             	/**
 87             	 * Sets the template filenames for handles. $filename_array
 88             	 * should be a hash of handle => filename pairs.
 89             	 */
 90             	function set_filenames($filename_array)
 91             	{
 92             		if (!is_array($filename_array))
 93             		{
 94             			return false;
 95             		}
 96             
 97             		reset($filename_array);
 98             		while(list($handle, $filename) = each($filename_array))
 99             		{
100             			$this->files[$handle] = $this->make_filename($filename);
101             		}
102             
103             		return true;
104             	}
105             
106 rizwank 1.1 
107             	/**
108             	 * Load the file for the handle, compile the file,
109             	 * and run the compiled code. This will print out
110             	 * the results of executing the template.
111             	 */
112             	function pparse($handle)
113             	{
114             		if (!$this->loadfile($handle))
115             		{
116             			die("Template->pparse(): Couldn't load template file for handle $handle");
117             		}
118             
119             		// actually compile the template now.
120             		if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle]))
121             		{
122             			// Actually compile the code now.
123             			$this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
124             		}
125             
126             		// Run the compiled code.
127 rizwank 1.1 		eval($this->compiled_code[$handle]);
128             		return true;
129             	}
130             
131             	/**
132             	 * Inserts the uncompiled code for $handle as the
133             	 * value of $varname in the root-level. This can be used
134             	 * to effectively include a template in the middle of another
135             	 * template.
136             	 * Note that all desired assignments to the variables in $handle should be done
137             	 * BEFORE calling this function.
138             	 */
139             	function assign_var_from_handle($varname, $handle)
140             	{
141             		if (!$this->loadfile($handle))
142             		{
143             			die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
144             		}
145             
146             		// Compile it, with the "no echo statements" option on.
147             		$_str = "";
148 rizwank 1.1 		$code = $this->compile($this->uncompiled_code[$handle], true, '_str');
149             
150             		// evaluate the variable assignment.
151             		eval($code);
152             		// assign the value of the generated variable to the given varname.
153             		$this->assign_var($varname, $_str);
154             
155             		return true;
156             	}
157             
158             	/**
159             	 * Block-level variable assignment. Adds a new block iteration with the given
160             	 * variable assignments. Note that this should only be called once per block
161             	 * iteration.
162             	 */
163             	function assign_block_vars($blockname, $vararray)
164             	{
165             		if (strstr($blockname, '.'))
166             		{
167             			// Nested block.
168             			$blocks = explode('.', $blockname);
169 rizwank 1.1 			$blockcount = sizeof($blocks) - 1;
170             			$str = '$this->_tpldata';
171             			for ($i = 0; $i < $blockcount; $i++)
172             			{
173             				$str .= '[\'' . $blocks[$i] . '.\']';
174             				eval('$lastiteration = sizeof(' . $str . ') - 1;');
175             				$str .= '[' . $lastiteration . ']';
176             			}
177             			// Now we add the block that we're actually assigning to.
178             			// We're adding a new iteration to this block with the given
179             			// variable assignments.
180             			$str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';
181             
182             			// Now we evaluate this assignment we've built up.
183             			eval($str);
184             		}
185             		else
186             		{
187             			// Top-level block.
188             			// Add a new iteration to this block with the variable assignments
189             			// we were given.
190 rizwank 1.1 			$this->_tpldata[$blockname . '.'][] = $vararray;
191             		}
192             
193             		return true;
194             	}
195             
196             	/**
197             	 * Root-level variable assignment. Adds to current assignments, overriding
198             	 * any existing variable assignment with the same name.
199             	 */
200             	function assign_vars($vararray)
201             	{
202             		reset ($vararray);
203             		while (list($key, $val) = each($vararray))
204             		{
205             			$this->_tpldata['.'][0][$key] = $val;
206             		}
207             
208             		return true;
209             	}
210             
211 rizwank 1.1 	/**
212             	 * Root-level variable assignment. Adds to current assignments, overriding
213             	 * any existing variable assignment with the same name.
214             	 */
215             	function assign_var($varname, $varval)
216             	{
217             		$this->_tpldata['.'][0][$varname] = $varval;
218             
219             		return true;
220             	}
221             
222             
223             	/**
224             	 * Generates a full path+filename for the given filename, which can either
225             	 * be an absolute name, or a name relative to the rootdir for this Template
226             	 * object.
227             	 */
228             	function make_filename($filename)
229             	{
230             		// Check if it's an absolute or relative path.
231             		if (substr($filename, 0, 1) != '/')
232 rizwank 1.1 		{
233                    		$filename = phpbb_realpath($this->root . '/' . $filename);
234             		}
235             
236             		if (!file_exists($filename))
237             		{
238             			die("Template->make_filename(): Error - file $filename does not exist");
239             		}
240             
241             		return $filename;
242             	}
243             
244             
245             	/**
246             	 * If not already done, load the file for the given handle and populate
247             	 * the uncompiled_code[] hash with its code. Do not compile.
248             	 */
249             	function loadfile($handle)
250             	{
251             		// If the file for this handle is already loaded and compiled, do nothing.
252             		if (isset($this->uncompiled_code[$handle]) && !empty($this->uncompiled_code[$handle]))
253 rizwank 1.1 		{
254             			return true;
255             		}
256             
257             		// If we don't have a file assigned to this handle, die.
258             		if (!isset($this->files[$handle]))
259             		{
260             			die("Template->loadfile(): No file specified for handle $handle");
261             		}
262             
263             		$filename = $this->files[$handle];
264             
265             		$str = implode("", @file($filename));
266             		if (empty($str))
267             		{
268             			die("Template->loadfile(): File $filename for handle $handle is empty");
269             		}
270             
271             		$this->uncompiled_code[$handle] = $str;
272             
273             		return true;
274 rizwank 1.1 	}
275             
276             
277             
278             	/**
279             	 * Compiles the given string of code, and returns
280             	 * the result in a string.
281             	 * If "do_not_echo" is true, the returned code will not be directly
282             	 * executable, but can be used as part of a variable assignment
283             	 * for use in assign_code_from_handle().
284             	 */
285             	function compile($code, $do_not_echo = false, $retvar = '')
286             	{
287             		// replace \ with \\ and then ' with \'.
288             		$code = str_replace('\\', '\\\\', $code);
289             		$code = str_replace('\'', '\\\'', $code);
290             
291             		// change template varrefs into PHP varrefs
292             
293             		// This one will handle varrefs WITH namespaces
294             		$varrefs = array();
295 rizwank 1.1 		preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
296             		$varcount = sizeof($varrefs[1]);
297             		for ($i = 0; $i < $varcount; $i++)
298             		{
299             			$namespace = $varrefs[1][$i];
300             			$varname = $varrefs[3][$i];
301             			$new = $this->generate_block_varref($namespace, $varname);
302             
303             			$code = str_replace($varrefs[0][$i], $new, $code);
304             		}
305             
306             		// This will handle the remaining root-level varrefs
307             		$code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code);
308             
309             		// Break it up into lines.
310             		$code_lines = explode("\n", $code);
311             
312             		$block_nesting_level = 0;
313             		$block_names = array();
314             		$block_names[0] = ".";
315             
316 rizwank 1.1 		// Second: prepend echo ', append ' . "\n"; to each line.
317             		$line_count = sizeof($code_lines);
318             		for ($i = 0; $i < $line_count; $i++)
319             		{
320             			$code_lines[$i] = chop($code_lines[$i]);
321             			if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m))
322             			{
323             				$n[0] = $m[0];
324             				$n[1] = $m[1];
325             
326             				// Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. :)
327             				if ( preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n) )
328             				{
329             					$block_nesting_level++;
330             					$block_names[$block_nesting_level] = $m[1];
331             					if ($block_nesting_level < 2)
332             					{
333             						// Block is not nested.
334             						$code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ?  sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;';
335             						$code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
336             						$code_lines[$i] .= "\n" . '{';
337 rizwank 1.1 					}
338             					else
339             					{
340             						// This block is nested.
341             
342             						// Generate a namespace string for this block.
343             						$namespace = implode('.', $block_names);
344             						// strip leading period from root level..
345             						$namespace = substr($namespace, 2);
346             						// Get a reference to the data array for this block that depends on the
347             						// current indices of all parent blocks.
348             						$varref = $this->generate_block_data_ref($namespace, false);
349             						// Create the for loop code to iterate over this block.
350             						$code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
351             						$code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
352             						$code_lines[$i] .= "\n" . '{';
353             					}
354             
355             					// We have the end of a block.
356             					unset($block_names[$block_nesting_level]);
357             					$block_nesting_level--;
358 rizwank 1.1 					$code_lines[$i] .= '} // END ' . $n[1];
359             					$m[0] = $n[0];
360             					$m[1] = $n[1];
361             				}
362             				else
363             				{
364             					// We have the start of a block.
365             					$block_nesting_level++;
366             					$block_names[$block_nesting_level] = $m[1];
367             					if ($block_nesting_level < 2)
368             					{
369             						// Block is not nested.
370             						$code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;';
371             						$code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
372             						$code_lines[$i] .= "\n" . '{';
373             					}
374             					else
375             					{
376             						// This block is nested.
377             
378             						// Generate a namespace string for this block.
379 rizwank 1.1 						$namespace = implode('.', $block_names);
380             						// strip leading period from root level..
381             						$namespace = substr($namespace, 2);
382             						// Get a reference to the data array for this block that depends on the
383             						// current indices of all parent blocks.
384             						$varref = $this->generate_block_data_ref($namespace, false);
385             						// Create the for loop code to iterate over this block.
386             						$code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
387             						$code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
388             						$code_lines[$i] .= "\n" . '{';
389             					}
390             				}
391             			}
392             			else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m))
393             			{
394             				// We have the end of a block.
395             				unset($block_names[$block_nesting_level]);
396             				$block_nesting_level--;
397             				$code_lines[$i] = '} // END ' . $m[1];
398             			}
399             			else
400 rizwank 1.1 			{
401             				// We have an ordinary line of code.
402             				if (!$do_not_echo)
403             				{
404             					$code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";';
405             				}
406             				else
407             				{
408             					$code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";'; 
409             				}
410             			}
411             		}
412             
413             		// Bring it back into a single string of lines of code.
414             		$code = implode("\n", $code_lines);
415             		return $code	;
416             
417             	}
418             
419             
420             	/**
421 rizwank 1.1 	 * Generates a reference to the given variable inside the given (possibly nested)
422             	 * block namespace. This is a string of the form:
423             	 * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
424             	 * It's ready to be inserted into an "echo" line in one of the templates.
425             	 * NOTE: expects a trailing "." on the namespace.
426             	 */
427             	function generate_block_varref($namespace, $varname)
428             	{
429             		// Strip the trailing period.
430             		$namespace = substr($namespace, 0, strlen($namespace) - 1);
431             
432             		// Get a reference to the data block for this namespace.
433             		$varref = $this->generate_block_data_ref($namespace, true);
434             		// Prepend the necessary code to stick this in an echo line.
435             
436             		// Append the variable reference.
437             		$varref .= '[\'' . $varname . '\']';
438             
439             		$varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \'';
440             
441             		return $varref;
442 rizwank 1.1 
443             	}
444             
445             
446             	/**
447             	 * Generates a reference to the array of data values for the given
448             	 * (possibly nested) block namespace. This is a string of the form:
449             	 * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
450             	 *
451             	 * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
452             	 * NOTE: does not expect a trailing "." on the blockname.
453             	 */
454             	function generate_block_data_ref($blockname, $include_last_iterator)
455             	{
456             		// Get an array of the blocks involved.
457             		$blocks = explode(".", $blockname);
458             		$blockcount = sizeof($blocks) - 1;
459             		$varref = '$this->_tpldata';
460             		// Build up the string with everything but the last child.
461             		for ($i = 0; $i < $blockcount; $i++)
462             		{
463 rizwank 1.1 			$varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]';
464             		}
465             		// Add the block reference for the last child.
466             		$varref .= '[\'' . $blocks[$blockcount] . '.\']';
467             		// Add the iterator for the last child if requried.
468             		if ($include_last_iterator)
469             		{
470             			$varref .= '[$_' . $blocks[$blockcount] . '_i]';
471             		}
472             
473             		return $varref;
474             	}
475             
476             }
477             
478             ?>

Rizwan Kassim
Powered by
ViewCVS 0.9.2