PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/phpbb2/phpbb2_template.class.php

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