PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

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