PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/includes/class.xtemplate.php

http://eveow.googlecode.com/
PHP | 998 lines | 872 code | 37 blank | 89 comment | 4 complexity | abde5b0ddf946930e03ca8d2a99b422e MD5 | raw file
Possible License(s): LGPL-2.1, CC0-1.0
  1. <?PHP
  2. /* $Id: xtemplate.class.php,v 1.7 2005/04/11 11:20:28 cocomp Exp $
  3. // $Log: xtemplate.class.php,v $
  4. // Revision 1.7 2005/04/11 11:20:28 cocomp
  5. // Fixed backslashes issue (properly\!)
  6. //
  7. // Revision 1.6 2005/04/11 10:00:47 cocomp
  8. // Added restart() method sf:641407 feature request
  9. //
  10. // Revision 1.5 2005/04/08 09:17:37 cocomp
  11. // Fixed bug with backslashes sf:810773 & updated docs
  12. //
  13. // Revision 1.4 2005/04/07 12:02:52 cocomp
  14. // MAJOR UPDATE: E_ALL safe, better internal documentation, code readability ++, many bugfixes and new features - considered stable
  15. //
  16. */
  17. /*
  18. XTemplate class - http://www.phpxtemplate.org/
  19. Latest stable & CVS versions available @ http://sourceforge.net/projects/xtpl/
  20. License: LGPL / BSD - see license.txt
  21. html generation with templates - fast & easy
  22. Copyright (c) 2000-2001 Barnabas Debreceni [cranx@users.sourceforge.net], 2002-2005 Jeremy Coates [cocomp@users.sourceforge.net]
  23. contributors:
  24. Ivar Smolin <okul@linux.ee> (14-march-2001)
  25. - made some code optimizations
  26. Bert Jandehoop <bert.jandehoop@users.info.wau.nl> (26-june-2001)
  27. - new feature to substitute template files by other templates
  28. - new method array_loop()
  29. Various contributions over the years from:
  30. Code: Noel Walsh (NW), John Carter (JC)
  31. Bug reporting: SadGeezer
  32. */
  33. // When developing uncomment the line below, re-comment before making public
  34. //error_reporting(E_ALL);
  35. class XTemplate {
  36. /***[ variables ]***********************************************************/
  37. var $filecontents = ''; /* raw contents of template file */
  38. var $blocks = array(); /* unparsed blocks */
  39. var $parsed_blocks = array(); /* parsed blocks */
  40. var $preparsed_blocks = array(); /* preparsed blocks, for file includes */
  41. var $block_parse_order = array(); /* block parsing order for recursive parsing (sometimes reverse:) */
  42. var $sub_blocks = array(); /* store sub-block names for fast resetting */
  43. var $vars = array(); /* variables array */
  44. var $filevars = array(); /* file variables array */
  45. var $filevar_parent = array(); /* filevars' parent block */
  46. var $filecache = array(); /* file caching */
  47. var $tpldir = ''; /* location of template files */
  48. var $files = null; /* file names lookup table */
  49. var $filename = '';
  50. // moved to setup method so uses the tag_start & end_delims
  51. var $file_delim = '';//"/\{FILE\s*\"([^\"]+)\"\s*\}/m"; /* regexp for file includes */
  52. var $filevar_delim = '';//"/\{FILE\s*\{([A-Za-z0-9\._]+?)\}\s*\}/m"; /* regexp for file includes */
  53. var $filevar_delim_nl = '';//"/^\s*\{FILE\s*\{([A-Za-z0-9\._]+?)\}\s*\}\s*\n/m"; /* regexp for file includes w/ newlines */
  54. var $block_start_delim = '<!-- '; /* block start delimiter */
  55. var $block_end_delim = '-->'; /* block end delimiter */
  56. var $block_start_word = 'BEGIN:'; /* block start word */
  57. var $block_end_word = 'END:'; /* block end word */
  58. /* this makes the delimiters look like: <!-- BEGIN: block_name --> if you use my syntax. */
  59. var $tag_start_delim = '{';
  60. var $tag_end_delim = '}';
  61. /* this makes the delimiters look like: {tagname} if you use my syntax. */
  62. var $mainblock = 'main';
  63. var $output_type = 'HTML';
  64. var $_null_string = array('' => ''); /* null string for unassigned vars */
  65. var $_null_block = array('' => ''); /* null string for unassigned blocks */
  66. var $_error = '';
  67. var $_autoreset = true; /* auto-reset sub blocks */
  68. var $_ignore_missing_blocks = true ; // NW 17 oct 2002 - Set to FALSE to
  69. // generate errors if a non-existant blocks is referenced
  70. // JC 20/11/02 for echoing the template filename if in development
  71. var $_file_name_full_path = '';
  72. /**
  73. * Constructor - Instantiate the object
  74. *
  75. * @param string $file Template file to work on
  76. * @param string $tpldir Location of template files (useful for keeping files outside web server root)
  77. * @param array $files Filenames lookup
  78. * @param string $mainblock Name of main block in the template
  79. * @param boolean $autosetup If true, run setup() as part of constuctor
  80. * @return XTemplate
  81. */
  82. function XTemplate ($file, $tpldir = '', $files = null, $mainblock = 'main', $autosetup = true) {
  83. $this->filename = $file;
  84. // JC 20/11/02 for echoing the template filename if in development
  85. $this->_file_name_full_path = realpath($file);
  86. $this->tpldir = $tpldir;
  87. if (is_array($files)) {
  88. $this->files = $files;
  89. }
  90. $this->mainblock = $mainblock;
  91. if ($autosetup) {
  92. // setup the rest of the preprocess elements
  93. $this->setup();
  94. }
  95. }
  96. /***************************************************************************/
  97. /***[ public stuff ]********************************************************/
  98. /***************************************************************************/
  99. /**
  100. * Restart the class - allows one instantiation with several files processed by restarting
  101. * e.g. $xtpl = new XTemplate('file1.xtpl');
  102. * $xtpl->parse('main');
  103. * $xtpl->out('main');
  104. * $xtpl->restart('file2.xtpl');
  105. * $xtpl->parse('main');
  106. * $xtpl->out('main');
  107. * (Added in response to sf:641407 feature request)
  108. *
  109. * @param string $file Template file to work on
  110. * @param string $tpldir Location of template files
  111. * @param array $files Filenames lookup
  112. * @param string $mainblock Name of main block in the template
  113. * @param boolean $autosetup If true, run setup() as part of restarting
  114. * @param string $tag_start {
  115. * @param string $tag_end }
  116. */
  117. function restart ($file, $tpldir = '', $files = null, $mainblock = 'main', $autosetup = true, $tag_start = '{', $tag_end = '}') {
  118. $this->filename = $file;
  119. $this->_file_name_full_path = realpath($file);
  120. $this->tpldir = $tpldir;
  121. if (is_array($files)) {
  122. $this->files = $files;
  123. }
  124. $this->mainblock = $mainblock;
  125. $this->tag_start_delim = $tag_start;
  126. $this->tag_end_delim = $tag_end;
  127. // Start with fresh file contents
  128. $this->filecontents = '';
  129. // Reset the template arrays
  130. $this->blocks = array();
  131. $this->parsed_blocks = array();
  132. $this->preparsed_blocks = array();
  133. $this->block_parse_order = array();
  134. $this->sub_blocks = array();
  135. $this->vars = array();
  136. $this->filevars = array();
  137. $this->filevar_parent = array();
  138. $this->filecache = array();
  139. if ($autosetup) {
  140. $this->setup();
  141. }
  142. }
  143. /**
  144. * setup - the elements that were previously in the constructor
  145. *
  146. * @access public
  147. * @param boolean $add_outer If true is passed when called, it adds an outer main block to the file
  148. */
  149. function setup ($add_outer = false) {
  150. $this->tag_start_delim = preg_quote($this->tag_start_delim);
  151. $this->tag_end_delim = preg_quote($this->tag_end_delim);
  152. // Setup the file delimiters
  153. // regexp for file includes
  154. $this->file_delim = "/" . $this->tag_start_delim . "FILE\s*\"([^\"]+)\"\s*" . $this->tag_end_delim . "/m";
  155. // regexp for file includes
  156. $this->filevar_delim = "/" . $this->tag_start_delim . "FILE\s*" . $this->tag_start_delim . "([A-Za-z0-9\._]+?)" . $this->tag_end_delim . "\s*" . $this->tag_end_delim . "/m";
  157. // regexp for file includes w/ newlines
  158. $this->filevar_delim_nl = "/^\s*" . $this->tag_start_delim . "FILE\s*" . $this->tag_start_delim . "([A-Za-z0-9\._]+?)" . $this->tag_end_delim . "\s*" . $this->tag_end_delim . "\s*\n/m";
  159. if (empty($this->filecontents)) {
  160. // read in template file
  161. $this->filecontents = $this->_r_getfile($this->filename);
  162. }
  163. if ($add_outer) {
  164. $this->_add_outer_block();
  165. }
  166. // preprocess some stuff
  167. $this->blocks = $this->_maketree($this->filecontents, '');
  168. $this->filevar_parent = $this->_store_filevar_parents($this->blocks);
  169. $this->scan_globals();
  170. }
  171. /**
  172. * assign a variable
  173. *
  174. * @access public
  175. * @param string $name Variable to assign $val to
  176. * @param string / array $val Value to assign to $name
  177. */
  178. function assign ($name, $val = '') {
  179. if (is_array($name)) {
  180. foreach ($name as $k => $v) {
  181. $this->vars[$k] = $v;
  182. }
  183. } else {
  184. $this->vars[$name] = $val;
  185. }
  186. }
  187. /**
  188. * assign a file variable
  189. *
  190. * @access public
  191. * @param string $name Variable to assign $val to
  192. * @param string / array $val Values to assign to $name
  193. */
  194. function assign_file ($name, $val = '') {
  195. if (is_array($name)) {
  196. foreach ($name as $k => $v) {
  197. $this->_assign_file_sub($k, $v);
  198. }
  199. } else {
  200. $this->_assign_file_sub($name, $val);
  201. }
  202. }
  203. /**
  204. * parse a block
  205. *
  206. * @access public
  207. * @param string $bname Block name to parse
  208. */
  209. function parse ($bname) {
  210. if (isset($this->preparsed_blocks[$bname])) {
  211. $copy = $this->preparsed_blocks[$bname];
  212. } elseif (isset($this->blocks[$bname])) {
  213. $copy = $this->blocks[$bname];
  214. } elseif ($this->_ignore_missing_blocks) {
  215. // ------------------------------------------------------
  216. // NW : 17 Oct 2002. Added default of ignore_missing_blocks
  217. // to allow for generalised processing where some
  218. // blocks may be removed from the HTML without the
  219. // processing code needing to be altered.
  220. // ------------------------------------------------------
  221. // JRC: 3/1/2003 added set error to ignore missing functionality
  222. $this->_set_error("parse: blockname [$bname] does not exist");
  223. return;
  224. } else {
  225. $this->_set_error("parse: blockname [$bname] does not exist");
  226. }
  227. /* from there we should have no more {FILE } directives */
  228. if (!isset($copy)) {
  229. die('Block: ' . $bname);
  230. }
  231. $copy = preg_replace($this->filevar_delim_nl, '', $copy);
  232. $var_array = array();
  233. /* find & replace variables+blocks */
  234. preg_match_all("/" . $this->tag_start_delim . "([A-Za-z0-9\._]+? ?#?.*?)" . $this->tag_end_delim. "/", $copy, $var_array);
  235. $var_array = $var_array[1];
  236. foreach ($var_array as $k => $v) {
  237. // Are there any comments in the tags {tag#a comment for documenting the template}
  238. $any_comments = explode('#', $v);
  239. $v = rtrim($any_comments[0]);
  240. if (sizeof($any_comments) > 1) {
  241. $comments = $any_comments[1];
  242. } else {
  243. $comments = '';
  244. }
  245. $sub = explode('.', $v);
  246. if ($sub[0] == '_BLOCK_') {
  247. unset($sub[0]);
  248. $bname2 = implode('.', $sub);
  249. // trinary operator eliminates assign error in E_ALL reporting
  250. $var = isset($this->parsed_blocks[$bname2]) ? $this->parsed_blocks[$bname2] : null;
  251. $nul = (!isset($this->_null_block[$bname2])) ? $this->_null_block[''] : $this->_null_block[$bname2];
  252. if ($var == '') {
  253. if ($nul == '') {
  254. // -----------------------------------------------------------
  255. // Removed requriement for blocks to be at the start of string
  256. // -----------------------------------------------------------
  257. // $copy=preg_replace("/^\s*\{".$v."\}\s*\n*/m","",$copy);
  258. // Now blocks don't need to be at the beginning of a line,
  259. //$copy=preg_replace("/\s*" . $this->tag_start_delim . $v . $this->tag_end_delim . "\s*\n*/m","",$copy);
  260. $copy = preg_replace("/" . $this->tag_start_delim . $v . $this->tag_end_delim . "/m", '', $copy);
  261. } else {
  262. $copy = preg_replace("/" . $this->tag_start_delim . $v . $this->tag_end_delim . "/", "$nul", $copy);
  263. }
  264. } else {
  265. $var = trim($var);
  266. // SF Bug no. 810773 - thanks anonymous
  267. $var = str_replace('\\', '\\\\', $var);
  268. // Ensure dollars in strings are not evaluated reported by SadGeezer 31/3/04
  269. $var = str_replace('$', '\\$', $var);
  270. // Replaced str_replaces with preg_quote
  271. //$var = preg_quote($var);
  272. $var = str_replace('\\|', '|', $var);
  273. $copy = preg_replace("|" . $this->tag_start_delim . $v . $this->tag_end_delim . "|", "$var", $copy);
  274. }
  275. } else {
  276. $var = $this->vars;
  277. foreach ($sub as $v1) {
  278. // NW 4 Oct 2002 - Added isset and is_array check to avoid NOTICE messages
  279. // JC 17 Oct 2002 - Changed EMPTY to stlen=0
  280. // if (empty($var[$v1])) { // this line would think that zeros(0) were empty - which is not true
  281. if (!isset($var[$v1]) || (!is_array($var[$v1]) && strlen($var[$v1]) == 0)) {
  282. // Check for constant, when variable not assigned
  283. if (defined($v1)) {
  284. $var[$v1] = constant($v1);
  285. } else {
  286. $var[$v1] = null;
  287. }
  288. }
  289. $var = $var[$v1];
  290. }
  291. $nul = (!isset($this->_null_string[$v])) ? ($this->_null_string[""]) : ($this->_null_string[$v]);
  292. $var = (!isset($var)) ? $nul : $var;
  293. if ($var == '') {
  294. // -----------------------------------------------------------
  295. // Removed requriement for blocks to be at the start of string
  296. // -----------------------------------------------------------
  297. // $copy=preg_replace("|^\s*\{".$v." ?#?".$comments."\}\s*\n|m","",$copy);
  298. $copy=preg_replace("|\s*" . $this->tag_start_delim . $v . " ?#?" . $comments . $this->tag_end_delim . "\s*\n|m", '', $copy);
  299. }
  300. $var = trim($var);
  301. // SF Bug no. 810773 - thanks anonymous
  302. $var = str_replace('\\', '\\\\', $var);
  303. // Ensure dollars in strings are not evaluated reported by SadGeezer 31/3/04
  304. $var = str_replace('$', '\\$', $var);
  305. // Replace str_replaces with preg_quote
  306. //$var = preg_quote($var);
  307. $var = str_replace('\\|', '|', $var);
  308. $copy=preg_replace("|" . $this->tag_start_delim . $v . " ?#?" . $comments . $this->tag_end_delim . "|", "$var", $copy);
  309. }
  310. }
  311. if (isset($this->parsed_blocks[$bname])) {
  312. $this->parsed_blocks[$bname] .= $copy;
  313. } else {
  314. $this->parsed_blocks[$bname] = $copy;
  315. }
  316. /* reset sub-blocks */
  317. if ($this->_autoreset && (!empty($this->sub_blocks[$bname]))) {
  318. reset($this->sub_blocks[$bname]);
  319. foreach ($this->sub_blocks[$bname] as $k => $v) {
  320. $this->reset($v);
  321. }
  322. }
  323. }
  324. /**
  325. * returns the parsed text for a block, including all sub-blocks.
  326. *
  327. * @access public
  328. * @param string $bname Block name to parse
  329. */
  330. function rparse ($bname) {
  331. if (!empty($this->sub_blocks[$bname])) {
  332. reset($this->sub_blocks[$bname]);
  333. foreach ($this->sub_blocks[$bname] as $k => $v) {
  334. if (!empty($v)) {
  335. $this->rparse($v);
  336. }
  337. }
  338. }
  339. $this->parse($bname);
  340. }
  341. /**
  342. * inserts a loop ( call assign & parse )
  343. *
  344. * @access public
  345. * @param string $bname Block name to assign
  346. * @param string $var Variable to assign values to
  347. * @param string / array $value Value to assign to $var
  348. */
  349. function insert_loop ($bname, $var, $value = '') {
  350. $this->assign($var, $value);
  351. $this->parse($bname);
  352. }
  353. /**
  354. * parses a block for every set of data in the values array
  355. *
  356. * @access public
  357. * @param string $bname Block name to loop
  358. * @param string $var Variable to assign values to
  359. * @param array $values Values to assign to $var
  360. */
  361. function array_loop ($bname, $var, &$values) {
  362. if (is_array($values)) {
  363. foreach($values as $v) {
  364. $this->assign($var, $v);
  365. $this->parse($bname);
  366. }
  367. }
  368. }
  369. /**
  370. * returns the parsed text for a block
  371. *
  372. * @access public
  373. * @param string $bname Block name to return
  374. * @return string
  375. */
  376. function text ($bname = '') {
  377. // JC 20/11/02 moved from ::out()
  378. $text = '';
  379. /*if (SYSTEM_TYPE == 'development' && $this->output_type == "HTML") {
  380. $Text = "<!-- Template: " . $this->_file_name_full_path . " -->\n";
  381. } else {
  382. $Text = "";
  383. }*/
  384. $bname = !empty($bname) ? $bname : $this->mainblock;
  385. $text .= isset($this->parsed_blocks[$bname]) ? $this->parsed_blocks[$bname] : $this->get_error();
  386. return $text;
  387. }
  388. /**
  389. * prints the parsed text
  390. *
  391. * @access public
  392. * @param string $bname Block name to echo out
  393. */
  394. function out ($bname) {
  395. $out = $this->text($bname);
  396. // $length=strlen($out);
  397. //header("Content-Length: ".$length); // TODO: Comment this back in later
  398. // JC 20/11/02 echo the template filename if in development as
  399. // html comment
  400. // note 4.3.0 and ZE2 have new function debug_backtrace() that show a
  401. // function call list - it may be nice to dump that here too
  402. //if (SYSTEM_TYPE == 'development') {
  403. // echo "<!-- Template: " . $this->_file_name_full_path . " -->\n";
  404. //}
  405. // moved to ::text() so parsing sub templates work
  406. echo $out;
  407. }
  408. /**
  409. * prints the parsed text to a specified file
  410. *
  411. * @access public
  412. * @param string $bname Block name to write out
  413. * @param string $fname File name to write to
  414. */
  415. function out_file ($bname, $fname) {
  416. if (!empty($bname) && !empty($fname) && is_writeable($fname)) {
  417. $fp = fopen($fname, 'w');
  418. fwrite($fp, $this->text($bname));
  419. fclose($fp);
  420. }
  421. }
  422. /**
  423. * resets the parsed text
  424. *
  425. * @access public
  426. * @param string $bname Block to reset
  427. */
  428. function reset ($bname) {
  429. $this->parsed_blocks[$bname] = '';
  430. }
  431. /**
  432. * returns true if block was parsed, false if not
  433. *
  434. * @access public
  435. * @param string $bname Block name to test
  436. * @return boolean
  437. */
  438. function parsed ($bname) {
  439. return (!empty($this->parsed_blocks[$bname]));
  440. }
  441. /**
  442. * sets the string to replace in case the var was not assigned
  443. *
  444. * @access public
  445. * @param string $str Display string for null block
  446. * @param string $varname Variable name to apply $str to
  447. */
  448. function SetNullString ($str, $varname = '') {
  449. $this->_null_string[$varname] = $str;
  450. }
  451. /**
  452. * sets the string to replace in case the block was not parsed
  453. *
  454. * @access public
  455. * @param string $str Display string for null block
  456. * @param string $bname Block name to apply $str to
  457. */
  458. function SetNullBlock ($str, $bname = '') {
  459. $this->_null_block[$bname] = $str;
  460. }
  461. /**
  462. * sets AUTORESET to 1. (default is 1)
  463. * if set to 1, parse() automatically resets the parsed blocks' sub blocks
  464. * (for multiple level blocks)
  465. *
  466. * @access public
  467. */
  468. function set_autoreset () {
  469. $this->_autoreset = true;
  470. }
  471. /**
  472. * sets AUTORESET to 0. (default is 1)
  473. * if set to 1, parse() automatically resets the parsed blocks' sub blocks
  474. * (for multiple level blocks)
  475. *
  476. * @access public
  477. */
  478. function clear_autoreset () {
  479. $this->_autoreset = false;
  480. }
  481. /**
  482. * scans global variables and assigns to PHP array
  483. *
  484. * @access public
  485. */
  486. function scan_globals () {
  487. reset($GLOBALS);
  488. foreach ($GLOBALS as $k => $v) {
  489. $GLOB[$k] = $v;
  490. }
  491. $this->assign('PHP', $GLOB); /* access global variables as {PHP.HTTP_SERVER_VARS.HTTP_HOST} in your template! */
  492. }
  493. /**
  494. * gets error condition / string
  495. *
  496. * @access public
  497. * @return boolean / string
  498. */
  499. function get_error () {
  500. // JRC: 3/1/2003 Added ouptut wrapper and detection of output type for error message output
  501. $retval = false;
  502. if ($this->_error != '') {
  503. switch ($this->output_type) {
  504. case 'HTML':
  505. case 'html':
  506. $retval = '<b>[XTemplate]</b><ul>' . nl2br(str_replace('* ', '<li>', str_replace(" *\n", "</li>\n", $this->_error))) . '</ul>';
  507. break;
  508. default:
  509. $retval = '[XTemplate] ' . str_replace(' *\n', "\n", $this->_error);
  510. break;
  511. }
  512. }
  513. return $retval;
  514. }
  515. /***************************************************************************/
  516. /***[ private stuff ]*******************************************************/
  517. /***************************************************************************/
  518. /**
  519. * generates the array containing to-be-parsed stuff: $blocks["main"],$blocks["main.table"],$blocks["main.table.row"], etc. also builds the reverse parse order.
  520. *
  521. * @access private
  522. * @param string $con content to be processed
  523. * @param string $parentblock name of the parent block in the block hierarchy
  524. */
  525. function _maketree ($con, $parentblock='') {
  526. $blocks = array();
  527. $con2 = explode($this->block_start_delim, $con);
  528. if (!empty($parentblock)) {
  529. $block_names = explode('.', $parentblock);
  530. $level = sizeof($block_names);
  531. } else {
  532. $block_names = array();
  533. $level = 0;
  534. }
  535. foreach($con2 as $k => $v) {
  536. // JRC 06/04/2005 Added block comments (on BEGIN or END) <!-- BEGIN: block_name#Comments placed here -->
  537. //$patt = "($this->block_start_word|$this->block_end_word)\s*(\w+)\s*$this->block_end_delim(.*)";
  538. $patt = "($this->block_start_word|$this->block_end_word)\s*(\w+) ?#?.*?\s*$this->block_end_delim(.*)";
  539. $res = array();
  540. if (preg_match_all("/$patt/ims", $v, $res, PREG_SET_ORDER)) {
  541. // $res[0][1] = BEGIN or END
  542. // $res[0][2] = block name
  543. // $res[0][3] = kinda content
  544. $block_word = $res[0][1];
  545. $block_name = $res[0][2];
  546. $content = $res[0][3];
  547. if (strtoupper($block_word) == $this->block_start_word) {
  548. $parent_name = implode('.', $block_names);
  549. // add one level - array("main","table","row")
  550. $block_names[++$level] = $block_name;
  551. // make block name (main.table.row)
  552. $cur_block_name=implode('.', $block_names);
  553. // build block parsing order (reverse)
  554. $this->block_parse_order[] = $cur_block_name;
  555. //add contents. trinary operator eliminates assign error in E_ALL reporting
  556. $blocks[$cur_block_name] = isset($blocks[$cur_block_name]) ? $blocks[$cur_block_name] . $content : $content;
  557. // add {_BLOCK_.blockname} string to parent block
  558. $blocks[$parent_name] .= str_replace('\\', '', $this->tag_start_delim) . '_BLOCK_.' . $cur_block_name . str_replace('\\', '', $this->tag_end_delim);
  559. // store sub block names for autoresetting and recursive parsing
  560. $this->sub_blocks[$parent_name][] = $cur_block_name;
  561. // store sub block names for autoresetting
  562. $this->sub_blocks[$cur_block_name][] = '';
  563. } else if (strtoupper($block_word) == $this->block_end_word) {
  564. unset($block_names[$level--]);
  565. $parent_name = implode('.', $block_names);
  566. // add rest of block to parent block
  567. $blocks[$parent_name] .= $res[0][3];
  568. }
  569. } else {
  570. // no block delimiters found
  571. // Saves doing multiple implodes - less overhead
  572. $tmp = implode('.', $block_names);
  573. if ($k) {
  574. $blocks[$tmp] .= $this->block_start_delim;
  575. }
  576. // trinary operator eliminates assign error in E_ALL reporting
  577. $blocks[$tmp] = isset($blocks[$tmp]) ? $blocks[$tmp] . $v : $v;
  578. }
  579. }
  580. return $blocks;
  581. }
  582. /**
  583. * Sub processing for assign_file method
  584. *
  585. * @param string $name
  586. * @param string $val
  587. */
  588. function _assign_file_sub ($name, $val) {
  589. if (isset($this->filevar_parent[$name])) {
  590. if ($val != '') {
  591. $val = $this->_r_getfile($val);
  592. foreach($this->filevar_parent[$name] as $parent) {
  593. if (isset($this->preparsed_blocks[$parent]) && !isset($this->filevars[$name])) {
  594. $copy = $this->preparsed_blocks[$parent];
  595. } elseif (isset($this->blocks[$parent])) {
  596. $copy = $this->blocks[$parent];
  597. }
  598. $res = array();
  599. preg_match_all($this->filevar_delim, $copy, $res, PREG_SET_ORDER);
  600. if (is_array($res) && isset($res[0])) {
  601. foreach ($res[0] as $v) {
  602. $copy = preg_replace("/" . preg_quote($v) . "/", "$val", $copy);
  603. $this->preparsed_blocks = array_merge($this->preparsed_blocks, $this->_maketree($copy, $parent));
  604. $this->filevar_parent = array_merge($this->filevar_parent, $this->_store_filevar_parents($this->preparsed_blocks));
  605. }
  606. }
  607. }
  608. }
  609. }
  610. $this->filevars[$name] = $val;
  611. }
  612. /**
  613. * store container block's name for file variables
  614. *
  615. * @access private
  616. * @param array $blocks
  617. * @return array
  618. */
  619. function _store_filevar_parents ($blocks){
  620. $parents = array();
  621. foreach ($blocks as $bname => $con) {
  622. $res = array();
  623. preg_match_all($this->filevar_delim, $con, $res);
  624. foreach ($res[1] as $k => $v) {
  625. $parents[$v][] = $bname;
  626. }
  627. }
  628. return $parents;
  629. }
  630. /**
  631. * Set the error string
  632. *
  633. * @param string $str
  634. */
  635. function _set_error ($str) {
  636. //$this->_error="<b>[XTemplate]</b>&nbsp;<i>".$str."</i>";
  637. // JRC: 3/1/2003 Made to append the error messages
  638. $this->_error .= '* ' . $str . " *\n";
  639. // JRC: 3/1/2003 Removed trigger error, use this externally if you want it eg. trigger_error($xtpl->get_error())
  640. //trigger_error($this->get_error());
  641. }
  642. /**
  643. * returns the contents of a file
  644. *
  645. * @access private
  646. * @param string $file
  647. * @return string
  648. */
  649. function _getfile ($file) {
  650. if (!isset($file)) {
  651. // JC 19/12/02 added $file to error message
  652. $this->_set_error('!isset file name!' . $file);
  653. return '';
  654. }
  655. // check if filename is mapped to other filename
  656. if (isset($this->files)) {
  657. if (isset($this->files[$file])) {
  658. $file = $this->files[$file];
  659. }
  660. }
  661. // prepend template dir
  662. if (!empty($this->tpldir)) {
  663. $file = $this->tpldir. '/' . $file;
  664. }
  665. if (isset($this->filecache[$file])) {
  666. $file_text=$this->filecache[$file];
  667. } else {
  668. if (is_file($file)) {
  669. if (!($fh = fopen($file, 'r'))) {
  670. $this->_set_error('Cannot open file: ' . $file);
  671. return '';
  672. }
  673. $file_text = fread($fh,filesize($file));
  674. fclose($fh);
  675. } else {
  676. // NW 17Oct 2002 : Added realpath around the file name to identify where the code is searching.
  677. $this->_set_error("[" . realpath($file) . "] ($file) does not exist");
  678. $file_text = "<b>__XTemplate fatal error: file [$file] does not exist__</b>";
  679. }
  680. $this->filecache[$file] = $file_text;
  681. }
  682. return $file_text;
  683. }
  684. /**
  685. * recursively gets the content of a file with {FILE "filename.tpl"} directives
  686. *
  687. * @access private
  688. * @param string $file
  689. * @return string
  690. */
  691. function _r_getfile ($file) {
  692. $text = $this->_getfile($file);
  693. $res = array();
  694. while (preg_match($this->file_delim,$text,$res)) {
  695. $text2 = $this->_getfile($res[1]);
  696. $text = preg_replace("'".preg_quote($res[0])."'",$text2,$text);
  697. }
  698. return $text;
  699. }
  700. /**
  701. * add an outer block delimiter set useful for rtfs etc - keeps them editable in word
  702. *
  703. * @access private
  704. */
  705. function _add_outer_block () {
  706. $before = $this->block_start_delim . $this->block_start_word . ' ' . $this->mainblock . ' ' . $this->block_end_delim;
  707. $after = $this->block_start_delim . $this->block_end_word . ' ' . $this->mainblock . ' ' . $this->block_end_delim;
  708. $this->filecontents = $before . "\n" . $this->filecontents . "\n" . $after;
  709. }
  710. /**
  711. * Debug function - var_dump wrapped in '<pre></pre>' tags
  712. *
  713. * @access private
  714. * @param multiple Var_dumps all the supplied arguments
  715. */
  716. function _pre_var_dump () {
  717. echo '<pre>';
  718. var_dump(func_get_args());
  719. echo '</pre>';
  720. }
  721. } /* end of XTemplate class. */
  722. /* Stuff from development outside sourceforge
  723. // Revision 1.2 2003/12/05 22:22:17 jeremy
  724. // Removed duplicate function call in out method
  725. //
  726. // Revision 1.1.1.1 2003/10/29 20:22:43 jeremy
  727. // Initial Import
  728. //
  729. // Revision 1.1 2003/06/25 17:17:52 jeremy
  730. // Initial Import
  731. //
  732. // Revision 1.4 2001/08/17 18:25:45 jeremy
  733. // Sorted greedy matching regular expression in parse function preg_match_all line 166: added ? after .* when looking for comments
  734. //
  735. */
  736. /* Old log stuff
  737. Revision 1.2 2001/09/19 14:11:25 cranx
  738. fixed a bug in the whitespace-stripping block variable interpolating regexp.
  739. Revision 1.1 2001/07/11 10:42:39 cranx
  740. added:
  741. - filename substitution, no nested arrays for the moment, sorry
  742. (including happens when assigning, so assign filevar in the outside blocks first!)
  743. Revision 1.5 2001/07/11 10:39:08 cranx
  744. added:
  745. - we can now specify base dir
  746. - array_loop()
  747. - trigger_error in _set_error
  748. modified:
  749. - newline bugs fixed (for XML)
  750. - in out(): content-length header added
  751. - whiles changed to foreach
  752. - from now on, the class is php4 only :P
  753. */
  754. /* Old stuff from original releases
  755. xtemplate class 0.3pre
  756. !!! {FILE {VAR}} file variable interpolation may still be buggy !!!
  757. */
  758. ?>