PageRenderTime 56ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/template.php

https://github.com/Ganonmaster/Uren
PHP | 1479 lines | 958 code | 216 blank | 305 comment | 155 complexity | 1d641171debe06409cdc0c8837f7b3bf MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * @package phpBB3
  5. * @version $Id$
  6. * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10. /**
  11. * Base Template class.
  12. * @package phpBB3
  13. */
  14. class template
  15. {
  16. /** variable that holds all the data we'll be substituting into
  17. * the compiled templates. Takes form:
  18. * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value
  19. * if it's a root-level variable, it'll be like this:
  20. * --> $this->_tpldata[.][0][varname] == value
  21. */
  22. var $_tpldata = array('.' => array(0 => array()));
  23. var $_rootref;
  24. // Root dir and hash of filenames for each template handle.
  25. var $root = '';
  26. var $cachepath = '';
  27. var $files = array();
  28. var $filename = array();
  29. var $files_inherit = array();
  30. var $files_template = array();
  31. var $inherit_root = '';
  32. var $orig_tpl_storedb;
  33. var $orig_tpl_inherits_id;
  34. // this will hash handle names to the compiled/uncompiled code for that handle.
  35. var $compiled_code = array();
  36. /**
  37. * Set template location
  38. * @access public
  39. */
  40. function set_template()
  41. {
  42. global $phpbb_root_path, $user;
  43. if (file_exists($phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'))
  44. {
  45. $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template';
  46. $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_';
  47. if ($this->orig_tpl_storedb === null)
  48. {
  49. $this->orig_tpl_storedb = $user->theme['template_storedb'];
  50. }
  51. if ($this->orig_tpl_inherits_id === null)
  52. {
  53. $this->orig_tpl_inherits_id = $user->theme['template_inherits_id'];
  54. }
  55. $user->theme['template_storedb'] = $this->orig_tpl_storedb;
  56. $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id;
  57. if ($user->theme['template_inherits_id'])
  58. {
  59. $this->inherit_root = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template';
  60. }
  61. }
  62. else
  63. {
  64. trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR);
  65. }
  66. $this->_rootref = &$this->_tpldata['.'][0];
  67. return true;
  68. }
  69. /**
  70. * Set custom template location (able to use directory outside of phpBB)
  71. * @access public
  72. */
  73. function set_custom_template($template_path, $template_name, $fallback_template_path = false)
  74. {
  75. global $phpbb_root_path, $user;
  76. // Make sure $template_path has no ending slash
  77. if (substr($template_path, -1) == '/')
  78. {
  79. $template_path = substr($template_path, 0, -1);
  80. }
  81. $this->root = $template_path;
  82. $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_';
  83. if ($fallback_template_path !== false)
  84. {
  85. if (substr($fallback_template_path, -1) == '/')
  86. {
  87. $fallback_template_path = substr($fallback_template_path, 0, -1);
  88. }
  89. $this->inherit_root = $fallback_template_path;
  90. $this->orig_tpl_inherits_id = true;
  91. }
  92. else
  93. {
  94. $this->orig_tpl_inherits_id = false;
  95. }
  96. // the database does not store the path or name of a custom template
  97. // so there is no way we can properly store custom templates there
  98. $this->orig_tpl_storedb = false;
  99. $this->_rootref = &$this->_tpldata['.'][0];
  100. return true;
  101. }
  102. /**
  103. * Sets the template filenames for handles. $filename_array
  104. * should be a hash of handle => filename pairs.
  105. * @access public
  106. */
  107. function set_filenames($filename_array)
  108. {
  109. if (!is_array($filename_array))
  110. {
  111. return false;
  112. }
  113. foreach ($filename_array as $handle => $filename)
  114. {
  115. if (empty($filename))
  116. {
  117. trigger_error("template->set_filenames: Empty filename specified for $handle", E_USER_ERROR);
  118. }
  119. $this->filename[$handle] = $filename;
  120. $this->files[$handle] = $this->root . '/' . $filename;
  121. if ($this->inherit_root)
  122. {
  123. $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename;
  124. }
  125. }
  126. return true;
  127. }
  128. /**
  129. * Destroy template data set
  130. * @access public
  131. */
  132. function destroy()
  133. {
  134. $this->_tpldata = array('.' => array(0 => array()));
  135. $this->_rootref = &$this->_tpldata['.'][0];
  136. }
  137. /**
  138. * Reset/empty complete block
  139. * @access public
  140. */
  141. function destroy_block_vars($blockname)
  142. {
  143. if (strpos($blockname, '.') !== false)
  144. {
  145. // Nested block.
  146. $blocks = explode('.', $blockname);
  147. $blockcount = sizeof($blocks) - 1;
  148. $str = &$this->_tpldata;
  149. for ($i = 0; $i < $blockcount; $i++)
  150. {
  151. $str = &$str[$blocks[$i]];
  152. $str = &$str[sizeof($str) - 1];
  153. }
  154. unset($str[$blocks[$blockcount]]);
  155. }
  156. else
  157. {
  158. // Top-level block.
  159. unset($this->_tpldata[$blockname]);
  160. }
  161. return true;
  162. }
  163. /**
  164. * Display handle
  165. * @access public
  166. */
  167. function display($handle, $include_once = true)
  168. {
  169. global $user, $phpbb_hook;
  170. if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this))
  171. {
  172. if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
  173. {
  174. return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
  175. }
  176. }
  177. if (defined('IN_ERROR_HANDLER'))
  178. {
  179. if ((E_NOTICE & error_reporting()) == E_NOTICE)
  180. {
  181. error_reporting(error_reporting() ^ E_NOTICE);
  182. }
  183. }
  184. if ($filename = $this->_tpl_load($handle))
  185. {
  186. ($include_once) ? include_once($filename) : include($filename);
  187. }
  188. else
  189. {
  190. eval(' ?>' . $this->compiled_code[$handle] . '<?php ');
  191. }
  192. return true;
  193. }
  194. /**
  195. * Display the handle and assign the output to a template variable or return the compiled result.
  196. * @access public
  197. */
  198. function assign_display($handle, $template_var = '', $return_content = true, $include_once = false)
  199. {
  200. ob_start();
  201. $this->display($handle, $include_once);
  202. $contents = ob_get_clean();
  203. if ($return_content)
  204. {
  205. return $contents;
  206. }
  207. $this->assign_var($template_var, $contents);
  208. return true;
  209. }
  210. /**
  211. * Load a compiled template if possible, if not, recompile it
  212. * @access private
  213. */
  214. function _tpl_load(&$handle)
  215. {
  216. global $user, $phpEx, $config;
  217. if (!isset($this->filename[$handle]))
  218. {
  219. trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR);
  220. }
  221. // reload these settings to have the values they had when this object was initialised
  222. // using set_template or set_custom_template, they might otherwise have been overwritten
  223. // by other template class instances in between.
  224. //$user->theme['template_storedb'] = $this->orig_tpl_storedb;
  225. //$user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id;
  226. $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx;
  227. $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0;
  228. $recompile = false;
  229. if (!file_exists($filename) || @filesize($filename) === 0 || defined('DEBUG_EXTRA'))
  230. {
  231. $recompile = true;
  232. }
  233. else if ($config['load_tplcompile'])
  234. {
  235. // No way around it: we need to check inheritance here
  236. if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle]))
  237. {
  238. $this->files[$handle] = $this->files_inherit[$handle];
  239. $this->files_template[$handle] = $user->theme['template_inherits_id'];
  240. }
  241. $recompile = (@filemtime($filename) < filemtime($this->files[$handle])) ? true : false;
  242. }
  243. // Recompile page if the original template is newer, otherwise load the compiled version
  244. if (!$recompile)
  245. {
  246. return $filename;
  247. }
  248. global $db, $phpbb_root_path;
  249. if (!class_exists('template_compile'))
  250. {
  251. include($phpbb_root_path . 'includes/functions_template.' . $phpEx);
  252. }
  253. // Inheritance - we point to another template file for this one. Equality is also used for store_db
  254. if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle]))
  255. {
  256. $this->files[$handle] = $this->files_inherit[$handle];
  257. $this->files_template[$handle] = $user->theme['template_inherits_id'];
  258. }
  259. $compile = new template_compile($this);
  260. // If we don't have a file assigned to this handle, die.
  261. if (!isset($this->files[$handle]))
  262. {
  263. trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR);
  264. }
  265. // Just compile if no user object is present (happens within the installer)
  266. if (!$user)
  267. {
  268. $compile->_tpl_load_file($handle);
  269. return false;
  270. }
  271. if (isset($user->theme['template_storedb']) && $user->theme['template_storedb'])
  272. {
  273. $rows = array();
  274. $ids = array();
  275. // Inheritance
  276. if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'])
  277. {
  278. $ids[] = $user->theme['template_inherits_id'];
  279. }
  280. $ids[] = $user->theme['template_id'];
  281. foreach ($ids as $id)
  282. {
  283. $sql = 'SELECT *
  284. FROM ' . STYLES_TEMPLATE_DATA_TABLE . '
  285. WHERE template_id = ' . $id . "
  286. AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "'
  287. OR template_included " . $db->sql_like_expression($db->any_char . $this->filename[$handle] . ':' . $db->any_char) . ')';
  288. $result = $db->sql_query($sql);
  289. while ($row = $db->sql_fetchrow($result))
  290. {
  291. $rows[$row['template_filename']] = $row;
  292. }
  293. $db->sql_freeresult($result);
  294. }
  295. if (sizeof($rows))
  296. {
  297. foreach ($rows as $row)
  298. {
  299. $file = $this->root . '/' . $row['template_filename'];
  300. $force_reload = false;
  301. if ($row['template_id'] != $user->theme['template_id'])
  302. {
  303. // make sure that we are not overlooking a file not in the db yet
  304. if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file))
  305. {
  306. $file = $this->inherit_root . '/' . $row['template_filename'];
  307. $this->files[$row['template_filename']] = $file;
  308. $this->files_inherit[$row['template_filename']] = $file;
  309. $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
  310. }
  311. else if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'])
  312. {
  313. // Ok, we have a situation. There is a file in the subtemplate, but nothing in the DB. We have to fix that.
  314. $force_reload = true;
  315. $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
  316. }
  317. }
  318. else
  319. {
  320. $this->files_template[$row['template_filename']] = $user->theme['template_id'];
  321. }
  322. if ($force_reload || $row['template_mtime'] < filemtime($file))
  323. {
  324. if ($row['template_filename'] == $this->filename[$handle])
  325. {
  326. $compile->_tpl_load_file($handle, true);
  327. }
  328. else
  329. {
  330. $this->files[$row['template_filename']] = $file;
  331. $this->filename[$row['template_filename']] = $row['template_filename'];
  332. $compile->_tpl_load_file($row['template_filename'], true);
  333. unset($this->compiled_code[$row['template_filename']]);
  334. unset($this->files[$row['template_filename']]);
  335. unset($this->filename[$row['template_filename']]);
  336. }
  337. }
  338. if ($row['template_filename'] == $this->filename[$handle])
  339. {
  340. $this->compiled_code[$handle] = $compile->compile(trim($row['template_data']));
  341. $compile->compile_write($handle, $this->compiled_code[$handle]);
  342. }
  343. else
  344. {
  345. // Only bother compiling if it doesn't already exist
  346. if (!file_exists($this->cachepath . str_replace('/', '.', $row['template_filename']) . '.' . $phpEx))
  347. {
  348. $this->filename[$row['template_filename']] = $row['template_filename'];
  349. $compile->compile_write($row['template_filename'], $compile->compile(trim($row['template_data'])));
  350. unset($this->filename[$row['template_filename']]);
  351. }
  352. }
  353. }
  354. }
  355. else
  356. {
  357. $file = $this->root . '/' . $row['template_filename'];
  358. if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file))
  359. {
  360. $file = $this->inherit_root . '/' . $row['template_filename'];
  361. $this->files[$row['template_filename']] = $file;
  362. $this->files_inherit[$row['template_filename']] = $file;
  363. $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
  364. }
  365. // Try to load from filesystem and instruct to insert into the styles table...
  366. $compile->_tpl_load_file($handle, true);
  367. return false;
  368. }
  369. return false;
  370. }
  371. $compile->_tpl_load_file($handle);
  372. return false;
  373. }
  374. /**
  375. * Assign key variable pairs from an array
  376. * @access public
  377. */
  378. function assign_vars($vararray)
  379. {
  380. foreach ($vararray as $key => $val)
  381. {
  382. $this->_rootref[$key] = $val;
  383. }
  384. return true;
  385. }
  386. /**
  387. * Assign a single variable to a single key
  388. * @access public
  389. */
  390. function assign_var($varname, $varval)
  391. {
  392. $this->_rootref[$varname] = $varval;
  393. return true;
  394. }
  395. /**
  396. * Assign key variable pairs from an array to a specified block
  397. * @access public
  398. */
  399. function assign_block_vars($blockname, $vararray)
  400. {
  401. if (strpos($blockname, '.') !== false)
  402. {
  403. // Nested block.
  404. $blocks = explode('.', $blockname);
  405. $blockcount = sizeof($blocks) - 1;
  406. $str = &$this->_tpldata;
  407. for ($i = 0; $i < $blockcount; $i++)
  408. {
  409. $str = &$str[$blocks[$i]];
  410. $str = &$str[sizeof($str) - 1];
  411. }
  412. $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0;
  413. $vararray['S_ROW_COUNT'] = $s_row_count;
  414. // Assign S_FIRST_ROW
  415. if (!$s_row_count)
  416. {
  417. $vararray['S_FIRST_ROW'] = true;
  418. }
  419. // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
  420. // This is much more clever than going through the complete template data on display (phew)
  421. $vararray['S_LAST_ROW'] = true;
  422. if ($s_row_count > 0)
  423. {
  424. unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']);
  425. }
  426. // Now we add the block that we're actually assigning to.
  427. // We're adding a new iteration to this block with the given
  428. // variable assignments.
  429. $str[$blocks[$blockcount]][] = $vararray;
  430. }
  431. else
  432. {
  433. // Top-level block.
  434. $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0;
  435. $vararray['S_ROW_COUNT'] = $s_row_count;
  436. // Assign S_FIRST_ROW
  437. if (!$s_row_count)
  438. {
  439. $vararray['S_FIRST_ROW'] = true;
  440. }
  441. // We always assign S_LAST_ROW and remove the entry before
  442. $vararray['S_LAST_ROW'] = true;
  443. if ($s_row_count > 0)
  444. {
  445. unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']);
  446. }
  447. // Add a new iteration to this block with the variable assignments we were given.
  448. $this->_tpldata[$blockname][] = $vararray;
  449. }
  450. return true;
  451. }
  452. /**
  453. * Change already assigned key variable pair (one-dimensional - single loop entry)
  454. *
  455. * An example of how to use this function:
  456. * {@example alter_block_array.php}
  457. *
  458. * @param string $blockname the blockname, for example 'loop'
  459. * @param array $vararray the var array to insert/add or merge
  460. * @param mixed $key Key to search for
  461. *
  462. * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
  463. *
  464. * int: Position [the position to change or insert at directly given]
  465. *
  466. * If key is false the position is set to 0
  467. * If key is true the position is set to the last entry
  468. *
  469. * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
  470. *
  471. * If insert, the vararray is inserted at the given position (position counting from zero).
  472. * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value).
  473. *
  474. * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
  475. * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
  476. *
  477. * @return bool false on error, true on success
  478. * @access public
  479. */
  480. function alter_block_array($blockname, $vararray, $key = false, $mode = 'insert')
  481. {
  482. if (strpos($blockname, '.') !== false)
  483. {
  484. // Nested blocks are not supported
  485. return false;
  486. }
  487. // Change key to zero (change first position) if false and to last position if true
  488. if ($key === false || $key === true)
  489. {
  490. $key = ($key === false) ? 0 : sizeof($this->_tpldata[$blockname]);
  491. }
  492. // Get correct position if array given
  493. if (is_array($key))
  494. {
  495. // Search array to get correct position
  496. list($search_key, $search_value) = @each($key);
  497. $key = NULL;
  498. foreach ($this->_tpldata[$blockname] as $i => $val_ary)
  499. {
  500. if ($val_ary[$search_key] === $search_value)
  501. {
  502. $key = $i;
  503. break;
  504. }
  505. }
  506. // key/value pair not found
  507. if ($key === NULL)
  508. {
  509. return false;
  510. }
  511. }
  512. // Insert Block
  513. if ($mode == 'insert')
  514. {
  515. // Make sure we are not exceeding the last iteration
  516. if ($key >= sizeof($this->_tpldata[$blockname]))
  517. {
  518. $key = sizeof($this->_tpldata[$blockname]);
  519. unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']);
  520. $vararray['S_LAST_ROW'] = true;
  521. }
  522. else if ($key === 0)
  523. {
  524. unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']);
  525. $vararray['S_FIRST_ROW'] = true;
  526. }
  527. // Re-position template blocks
  528. for ($i = sizeof($this->_tpldata[$blockname]); $i > $key; $i--)
  529. {
  530. $this->_tpldata[$blockname][$i] = $this->_tpldata[$blockname][$i-1];
  531. $this->_tpldata[$blockname][$i]['S_ROW_COUNT'] = $i;
  532. }
  533. // Insert vararray at given position
  534. $vararray['S_ROW_COUNT'] = $key;
  535. $this->_tpldata[$blockname][$key] = $vararray;
  536. return true;
  537. }
  538. // Which block to change?
  539. if ($mode == 'change')
  540. {
  541. if ($key == sizeof($this->_tpldata[$blockname]))
  542. {
  543. $key--;
  544. }
  545. $this->_tpldata[$blockname][$key] = array_merge($this->_tpldata[$blockname][$key], $vararray);
  546. return true;
  547. }
  548. return false;
  549. }
  550. /**
  551. * Include a separate template
  552. * @access private
  553. */
  554. function _tpl_include($filename, $include = true)
  555. {
  556. $handle = $filename;
  557. $this->filename[$handle] = $filename;
  558. $this->files[$handle] = $this->root . '/' . $filename;
  559. if ($this->inherit_root)
  560. {
  561. $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename;
  562. }
  563. $filename = $this->_tpl_load($handle);
  564. if ($include)
  565. {
  566. global $user;
  567. if ($filename)
  568. {
  569. include($filename);
  570. return;
  571. }
  572. eval(' ?>' . $this->compiled_code[$handle] . '<?php ');
  573. }
  574. }
  575. /**
  576. * Include a php-file
  577. * @access private
  578. */
  579. function _php_include($filename)
  580. {
  581. global $phpbb_root_path;
  582. $file = $phpbb_root_path . $filename;
  583. if (!file_exists($file))
  584. {
  585. // trigger_error cannot be used here, as the output already started
  586. echo 'template->_php_include(): File ' . htmlspecialchars($file) . ' does not exist or is empty';
  587. return;
  588. }
  589. include($file);
  590. }
  591. }
  592. /**
  593. * Extension of template class - Functions needed for compiling templates only.
  594. *
  595. * psoTFX, phpBB Development Team - Completion of file caching, decompilation
  596. * routines and implementation of conditionals/keywords and associated changes
  597. *
  598. * The interface was inspired by PHPLib templates, and the template file (formats are
  599. * quite similar)
  600. *
  601. * The keyword/conditional implementation is currently based on sections of code from
  602. * the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
  603. * (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
  604. * derived from an LGPL application may be relicenced under the GPL, this applies
  605. * to this source
  606. *
  607. * DEFINE directive inspired by a request by Cyberalien
  608. *
  609. * @package phpBB3
  610. */
  611. class template_compile
  612. {
  613. var $template;
  614. // Various storage arrays
  615. var $block_names = array();
  616. var $block_else_level = array();
  617. /**
  618. * constuctor
  619. */
  620. function template_compile(&$template)
  621. {
  622. $this->template = &$template;
  623. }
  624. /**
  625. * Load template source from file
  626. * @access private
  627. */
  628. function _tpl_load_file($handle, $store_in_db = false)
  629. {
  630. // Try and open template for read
  631. if (!file_exists($this->template->files[$handle]))
  632. {
  633. trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR);
  634. }
  635. $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle])));
  636. // Actually compile the code now.
  637. $this->compile_write($handle, $this->template->compiled_code[$handle]);
  638. // Store in database if required...
  639. if ($store_in_db)
  640. {
  641. global $db, $user;
  642. $sql_ary = array(
  643. 'template_id' => $this->template->files_template[$handle],
  644. 'template_filename' => $this->template->filename[$handle],
  645. 'template_included' => '',
  646. 'template_mtime' => time(),
  647. 'template_data' => trim(@file_get_contents($this->template->files[$handle])),
  648. );
  649. $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  650. $db->sql_query($sql);
  651. }
  652. }
  653. /**
  654. * Remove any PHP tags that do not belong, these regular expressions are derived from
  655. * the ones that exist in zend_language_scanner.l
  656. * @access private
  657. */
  658. function remove_php_tags(&$code)
  659. {
  660. // This matches the information gathered from the internal PHP lexer
  661. $match = array(
  662. '#<([\?%])=?.*?\1>#s',
  663. '#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s',
  664. '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s'
  665. );
  666. $code = preg_replace($match, '', $code);
  667. }
  668. /**
  669. * The all seeing all doing compile method. Parts are inspired by or directly from Smarty
  670. * @access private
  671. */
  672. function compile($code, $no_echo = false, $echo_var = '')
  673. {
  674. global $config;
  675. if ($echo_var)
  676. {
  677. global $$echo_var;
  678. }
  679. // Remove any "loose" php ... we want to give admins the ability
  680. // to switch on/off PHP for a given template. Allowing unchecked
  681. // php is a no-no. There is a potential issue here in that non-php
  682. // content may be removed ... however designers should use entities
  683. // if they wish to display < and >
  684. $this->remove_php_tags($code);
  685. // Pull out all block/statement level elements and separate plain text
  686. preg_match_all('#<!-- PHP -->(.*?)<!-- ENDPHP -->#s', $code, $matches);
  687. $php_blocks = $matches[1];
  688. $code = preg_replace('#<!-- PHP -->.*?<!-- ENDPHP -->#s', '<!-- PHP -->', $code);
  689. preg_match_all('#<!-- INCLUDE (\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches);
  690. $include_blocks = $matches[1];
  691. $code = preg_replace('#<!-- INCLUDE (?:\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', '<!-- INCLUDE -->', $code);
  692. preg_match_all('#<!-- INCLUDEPHP ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches);
  693. $includephp_blocks = $matches[1];
  694. $code = preg_replace('#<!-- INCLUDEPHP [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDEPHP -->', $code);
  695. preg_match_all('#<!-- ([^<].*?) (.*?)? ?-->#', $code, $blocks, PREG_SET_ORDER);
  696. $text_blocks = preg_split('#<!-- [^<].*? (?:.*?)? ?-->#', $code);
  697. for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++)
  698. {
  699. $this->compile_var_tags($text_blocks[$i]);
  700. }
  701. $compile_blocks = array();
  702. for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++)
  703. {
  704. $block_val = &$blocks[$curr_tb];
  705. switch ($block_val[1])
  706. {
  707. case 'BEGIN':
  708. $this->block_else_level[] = false;
  709. $compile_blocks[] = '<?php ' . $this->compile_tag_block($block_val[2]) . ' ?>';
  710. break;
  711. case 'BEGINELSE':
  712. $this->block_else_level[sizeof($this->block_else_level) - 1] = true;
  713. $compile_blocks[] = '<?php }} else { ?>';
  714. break;
  715. case 'END':
  716. array_pop($this->block_names);
  717. $compile_blocks[] = '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>';
  718. break;
  719. case 'IF':
  720. $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], false) . ' ?>';
  721. break;
  722. case 'ELSE':
  723. $compile_blocks[] = '<?php } else { ?>';
  724. break;
  725. case 'ELSEIF':
  726. $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], true) . ' ?>';
  727. break;
  728. case 'ENDIF':
  729. $compile_blocks[] = '<?php } ?>';
  730. break;
  731. case 'DEFINE':
  732. $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], true) . ' ?>';
  733. break;
  734. case 'UNDEFINE':
  735. $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], false) . ' ?>';
  736. break;
  737. case 'INCLUDE':
  738. $temp = array_shift($include_blocks);
  739. // Dynamic includes
  740. // Cheap match rather than a full blown regexp, we already know
  741. // the format of the input so just use string manipulation.
  742. if ($temp[0] == '{')
  743. {
  744. $file = false;
  745. if ($temp[1] == '$')
  746. {
  747. $var = substr($temp, 2, -1);
  748. //$file = $this->template->_tpldata['DEFINE']['.'][$var];
  749. $temp = "\$this->_tpldata['DEFINE']['.']['$var']";
  750. }
  751. else
  752. {
  753. $var = substr($temp, 1, -1);
  754. //$file = $this->template->_rootref[$var];
  755. $temp = "\$this->_rootref['$var']";
  756. }
  757. }
  758. else
  759. {
  760. $file = $temp;
  761. }
  762. $compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>';
  763. // No point in checking variable includes
  764. if ($file)
  765. {
  766. $this->template->_tpl_include($file, false);
  767. }
  768. break;
  769. case 'INCLUDEPHP':
  770. $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : '';
  771. break;
  772. case 'PHP':
  773. $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : '';
  774. break;
  775. default:
  776. $this->compile_var_tags($block_val[0]);
  777. $trim_check = trim($block_val[0]);
  778. $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : '');
  779. break;
  780. }
  781. }
  782. $template_php = '';
  783. for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++)
  784. {
  785. $trim_check_text = trim($text_blocks[$i]);
  786. $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '');
  787. }
  788. // Remove unused opening/closing tags
  789. $template_php = str_replace(' ?><?php ', ' ', $template_php);
  790. // Now add a newline after each php closing tag which already has a newline
  791. // PHP itself strips a newline if a closing tag is used (this is documented behaviour) and it is mostly not intended by style authors to remove newlines
  792. $template_php = preg_replace('#\?\>([\r\n])#', '?>\1\1', $template_php);
  793. // There will be a number of occasions where we switch into and out of
  794. // PHP mode instantaneously. Rather than "burden" the parser with this
  795. // we'll strip out such occurences, minimising such switching
  796. if ($no_echo)
  797. {
  798. return "\$$echo_var .= '" . $template_php . "'";
  799. }
  800. return $template_php;
  801. }
  802. /**
  803. * Compile variables
  804. * @access private
  805. */
  806. function compile_var_tags(&$text_blocks)
  807. {
  808. // change template varrefs into PHP varrefs
  809. $varrefs = array();
  810. // This one will handle varrefs WITH namespaces
  811. preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER);
  812. foreach ($varrefs as $var_val)
  813. {
  814. $namespace = $var_val[1];
  815. $varname = $var_val[3];
  816. $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]);
  817. $text_blocks = str_replace($var_val[0], $new, $text_blocks);
  818. }
  819. // This will handle the remaining root-level varrefs
  820. // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
  821. if (strpos($text_blocks, '{L_') !== false)
  822. {
  823. $text_blocks = preg_replace('#\{L_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks);
  824. }
  825. // Handle addslashed language variables prefixed with LA_
  826. // If a template variable already exist, it will be used in favor of it...
  827. if (strpos($text_blocks, '{LA_') !== false)
  828. {
  829. $text_blocks = preg_replace('#\{LA_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks);
  830. }
  831. // Handle remaining varrefs
  832. $text_blocks = preg_replace('#\{([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks);
  833. $text_blocks = preg_replace('#\{\$([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks);
  834. return;
  835. }
  836. /**
  837. * Compile blocks
  838. * @access private
  839. */
  840. function compile_tag_block($tag_args)
  841. {
  842. $no_nesting = false;
  843. // Is the designer wanting to call another loop in a loop?
  844. if (strpos($tag_args, '!') === 0)
  845. {
  846. // Count the number of ! occurrences (not allowed in vars)
  847. $no_nesting = substr_count($tag_args, '!');
  848. $tag_args = substr($tag_args, $no_nesting);
  849. }
  850. // Allow for control of looping (indexes start from zero):
  851. // foo(2) : Will start the loop on the 3rd entry
  852. // foo(-2) : Will start the loop two entries from the end
  853. // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth
  854. // foo(3,-4) : Will start the loop on the fourth entry and end it four from last
  855. if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match))
  856. {
  857. $tag_args = $match[1];
  858. if ($match[2] < 0)
  859. {
  860. $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')';
  861. }
  862. else
  863. {
  864. $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')';
  865. }
  866. if (strlen($match[3]) < 1 || $match[3] == -1)
  867. {
  868. $loop_end = '$_' . $tag_args . '_count';
  869. }
  870. else if ($match[3] >= 0)
  871. {
  872. $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')';
  873. }
  874. else //if ($match[3] < -1)
  875. {
  876. $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1);
  877. }
  878. }
  879. else
  880. {
  881. $loop_start = 0;
  882. $loop_end = '$_' . $tag_args . '_count';
  883. }
  884. $tag_template_php = '';
  885. array_push($this->block_names, $tag_args);
  886. if ($no_nesting !== false)
  887. {
  888. // We need to implode $no_nesting times from the end...
  889. $block = array_slice($this->block_names, -$no_nesting);
  890. }
  891. else
  892. {
  893. $block = $this->block_names;
  894. }
  895. if (sizeof($block) < 2)
  896. {
  897. // Block is not nested.
  898. $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;";
  899. $varref = "\$this->_tpldata['$tag_args']";
  900. }
  901. else
  902. {
  903. // This block is nested.
  904. // Generate a namespace string for this block.
  905. $namespace = implode('.', $block);
  906. // Get a reference to the data array for this block that depends on the
  907. // current indices of all parent blocks.
  908. $varref = $this->generate_block_data_ref($namespace, false);
  909. // Create the for loop code to iterate over this block.
  910. $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
  911. }
  912. $tag_template_php .= 'if ($_' . $tag_args . '_count) {';
  913. /**
  914. * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory
  915. * <code>
  916. * if (!$offset)
  917. * {
  918. * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
  919. * }
  920. * </code>
  921. */
  922. $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){';
  923. $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];';
  924. return $tag_template_php;
  925. }
  926. /**
  927. * Compile IF tags - much of this is from Smarty with
  928. * some adaptions for our block level methods
  929. * @access private
  930. */
  931. function compile_tag_if($tag_args, $elseif)
  932. {
  933. // Tokenize args for 'if' tag.
  934. preg_match_all('/(?:
  935. "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
  936. \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
  937. [(),] |
  938. [^\s(),]+)/x', $tag_args, $match);
  939. $tokens = $match[0];
  940. $is_arg_stack = array();
  941. for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
  942. {
  943. $token = &$tokens[$i];
  944. switch ($token)
  945. {
  946. case '!==':
  947. case '===':
  948. case '<<':
  949. case '>>':
  950. case '|':
  951. case '^':
  952. case '&':
  953. case '~':
  954. case ')':
  955. case ',':
  956. case '+':
  957. case '-':
  958. case '*':
  959. case '/':
  960. case '@':
  961. break;
  962. case '==':
  963. case 'eq':
  964. $token = '==';
  965. break;
  966. case '!=':
  967. case '<>':
  968. case 'ne':
  969. case 'neq':
  970. $token = '!=';
  971. break;
  972. case '<':
  973. case 'lt':
  974. $token = '<';
  975. break;
  976. case '<=':
  977. case 'le':
  978. case 'lte':
  979. $token = '<=';
  980. break;
  981. case '>':
  982. case 'gt':
  983. $token = '>';
  984. break;
  985. case '>=':
  986. case 'ge':
  987. case 'gte':
  988. $token = '>=';
  989. break;
  990. case '&&':
  991. case 'and':
  992. $token = '&&';
  993. break;
  994. case '||':
  995. case 'or':
  996. $token = '||';
  997. break;
  998. case '!':
  999. case 'not':
  1000. $token = '!';
  1001. break;
  1002. case '%':
  1003. case 'mod':
  1004. $token = '%';
  1005. break;
  1006. case '(':
  1007. array_push($is_arg_stack, $i);
  1008. break;
  1009. case 'is':
  1010. $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
  1011. $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
  1012. $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
  1013. array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens);
  1014. $i = $is_arg_start;
  1015. // no break
  1016. default:
  1017. if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs))
  1018. {
  1019. $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']');
  1020. }
  1021. else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs))
  1022. {
  1023. // Allow checking if loops are set with .loopname
  1024. // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
  1025. $blocks = explode('.', $varrefs[1]);
  1026. // If the block is nested, we have a reference that we can grab.
  1027. // If the block is not nested, we just go and grab the block from _tpldata
  1028. if (sizeof($blocks) > 1)
  1029. {
  1030. $block = array_pop($blocks);
  1031. $namespace = implode('.', $blocks);
  1032. $varref = $this->generate_block_data_ref($namespace, true);
  1033. // Add the block reference for the last child.
  1034. $varref .= "['" . $block . "']";
  1035. }
  1036. else
  1037. {
  1038. $varref = '$this->_tpldata';
  1039. // Add the block reference for the last child.
  1040. $varref .= "['" . $blocks[0] . "']";
  1041. }
  1042. $token = "sizeof($varref)";
  1043. }
  1044. else if (!empty($token))
  1045. {
  1046. $token = '(' . $token . ')';
  1047. }
  1048. break;
  1049. }
  1050. }
  1051. // If there are no valid tokens left or only control/compare characters left, we do skip this statement
  1052. if (!sizeof($tokens) || str_replace(array(' ', '=', '!', '<', '>', '&', '|', '%', '(', ')'), '', implode('', $tokens)) == '')
  1053. {
  1054. $tokens = array('false');
  1055. }
  1056. return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { ');
  1057. }
  1058. /**
  1059. * Compile DEFINE tags
  1060. * @access private
  1061. */
  1062. function compile_tag_define($tag_args, $op)
  1063. {
  1064. preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match);
  1065. if (empty($match[2]) || (!isset($match[4]) && $op))
  1066. {
  1067. return '';
  1068. }
  1069. if (!$op)
  1070. {
  1071. return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
  1072. }
  1073. // Are we a string?
  1074. if ($match[3] && $match[5])
  1075. {
  1076. $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]);
  1077. // Compile reference, we allow template variables in defines...
  1078. $match[4] = $this->compile($match[4]);
  1079. // Now replace the php code
  1080. $match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'";
  1081. }
  1082. else
  1083. {
  1084. preg_match('#true|false|\.#i', $match[4], $type);
  1085. switch (strtolower($type[0]))
  1086. {
  1087. case 'true':
  1088. case 'false':
  1089. $match[4] = strtoupper($match[4]);
  1090. break;
  1091. case '.':
  1092. $match[4] = doubleval($match[4]);
  1093. break;
  1094. default:
  1095. $match[4] = intval($match[4]);
  1096. break;
  1097. }
  1098. }
  1099. return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';';
  1100. }
  1101. /**
  1102. * Compile INCLUDE tag
  1103. * @access private
  1104. */
  1105. function compile_tag_include($tag_args)
  1106. {
  1107. // Process dynamic includes
  1108. if ($tag_args[0] == '$')
  1109. {
  1110. return "if (isset($tag_args)) { \$this->_tpl_include($tag_args); }";
  1111. }
  1112. return "\$this->_tpl_include('$tag_args');";
  1113. }
  1114. /**
  1115. * Compile INCLUDE_PHP tag
  1116. * @access private
  1117. */
  1118. function compile_tag_include_php($tag_args)
  1119. {
  1120. return "\$this->_php_include('$tag_args');";
  1121. }
  1122. /**
  1123. * parse expression
  1124. * This is from Smarty
  1125. * @access private
  1126. */
  1127. function _parse_is_expr($is_arg, $tokens)
  1128. {
  1129. $expr_end = 0;
  1130. $negate_expr = false;
  1131. if (($first_token = array_shift($tokens)) == 'not')
  1132. {
  1133. $negate_expr = true;
  1134. $expr_type = array_shift($tokens);
  1135. }
  1136. else
  1137. {
  1138. $expr_type = $first_token;
  1139. }
  1140. switch ($expr_type)
  1141. {
  1142. case 'even':
  1143. if (@$tokens[$expr_end] == 'by')
  1144. {
  1145. $expr_end++;
  1146. $expr_arg = $tokens[$expr_end++];
  1147. $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
  1148. }
  1149. else
  1150. {
  1151. $expr = "!($is_arg & 1)";
  1152. }
  1153. break;
  1154. case 'odd':
  1155. if (@$tokens[$expr_end] == 'by')
  1156. {
  1157. $expr_end++;
  1158. $expr_arg = $tokens[$expr_end++];
  1159. $expr = "(($is_arg / $expr_arg) % $expr_arg)";
  1160. }
  1161. else
  1162. {
  1163. $expr = "($is_arg & 1)";
  1164. }
  1165. break;
  1166. case 'div':
  1167. if (@$tokens[$expr_end] == 'by')
  1168. {
  1169. $expr_end++;
  1170. $expr_arg = $tokens[$expr_end++];
  1171. $expr = "!($is_arg % $expr_arg)";
  1172. }
  1173. break;
  1174. }
  1175. if ($negate_expr)
  1176. {
  1177. $expr = "!($expr)";
  1178. }
  1179. array_splice($tokens, 0, $expr_end, $expr);
  1180. return $tokens;
  1181. }
  1182. /**
  1183. * Generates a reference to the given variable inside the given (possibly nested)
  1184. * block namespace. This is a string of the form:
  1185. * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
  1186. * It's ready to be inserted into an "echo" line in one of the templates.
  1187. * NOTE: expects a trailing "." on the namespace.
  1188. * @access private
  1189. */
  1190. function generate_block_varref($namespace, $varname, $echo = true, $defop = false)
  1191. {
  1192. // Strip the trailing period.
  1193. $namespace = substr($namespace, 0, -1);
  1194. // Get a reference to the data block for this namespace.
  1195. $varref = $this->generate_block_data_ref($namespace, true, $defop);
  1196. // Prepend the necessary code to stick this in an echo line.
  1197. // Append the variable reference.
  1198. $varref .= "['$varname']";
  1199. $varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : '');
  1200. return $varref;
  1201. }
  1202. /**
  1203. * Generates a reference to the array of data values for the given
  1204. * (possibly nested) block namespace. This is a string of the form:
  1205. * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
  1206. *
  1207. * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
  1208. * NOTE: does not expect a trailing "." on the blockname.
  1209. * @access private
  1210. */
  1211. function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
  1212. {
  1213. // Get an array of the blocks involved.
  1214. $blocks = explode('.', $blockname);
  1215. $blockcount = sizeof($blocks) - 1;
  1216. // DEFINE is not an element of any referenced variable, we must use _tpldata to access it
  1217. if ($defop)
  1218. {
  1219. $varref = '$this->_tpldata[\'DEFINE\']';
  1220. // Build up the string with everything but the last child.
  1221. for ($i = 0; $i < $blockcount; $i++)
  1222. {
  1223. $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
  1224. }
  1225. // Add the block reference for the last child.
  1226. $varref .= "['" . $blocks[$blockcount] . "']";
  1227. // Add the iterator for the last child if requried.
  1228. if ($include_last_iterator)
  1229. {
  1230. $varref .= '[$_' . $blocks[$blockcount] . '_i]';
  1231. }
  1232. return $varref;
  1233. }
  1234. else if ($include_last_iterator)
  1235. {
  1236. return '$_'. $blocks[$blockcount] . '_val';
  1237. }
  1238. else
  1239. {
  1240. return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']';
  1241. }
  1242. }
  1243. /**
  1244. * Write compiled file to cache directory
  1245. * @access private
  1246. */
  1247. function compile_write($handle, $data)
  1248. {
  1249. global $phpEx;
  1250. $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx;
  1251. $data = "<?php" . ((strpos($data, '<?php') === 0) ? substr($data, 5) : ' ?>' . $data);
  1252. if ($fp = @fopen($filename, 'wb'))
  1253. {
  1254. @flock($fp, LOCK_EX);
  1255. @fwrite ($fp, $data);
  1256. @flock($fp, LOCK_UN);
  1257. @fclose($fp);
  1258. chmod($filename, 0777);
  1259. //phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE);
  1260. }
  1261. return;
  1262. }
  1263. }