class.smarttemplateparser.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. /**
  3. * SmartTemplateParser Class
  4. * Used by SmartTemplate Class
  5. *
  6. * @desc Used by SmartTemplate Class
  7. * @author Philipp v. Criegern philipp@criegern.com
  8. * @author Manuel 'EndelWar' Dalla Lana endelwar@aregar.it
  9. * @version 1.2.1 03.07.2006
  10. *
  11. * CVS ID: $Id: class.smarttemplateparser.php 2504 2011-12-28 07:35:29Z liu21st $
  12. */
  13. class SmartTemplateParser
  14. {
  15. /**
  16. * The template itself
  17. *
  18. * @access private
  19. */
  20. var $template;
  21. /**
  22. * The template filename used to extract the dirname for subtemplates
  23. *
  24. * @access private
  25. */
  26. var $template_dir;
  27. /**
  28. * List of used SmartTemplate Extensions
  29. *
  30. * @access private
  31. */
  32. var $extension_tagged = array();
  33. /**
  34. * Error messages
  35. *
  36. * @access public
  37. */
  38. var $error;
  39. /**
  40. * SmartTemplateParser Constructor
  41. *
  42. * @param string $template_filename HTML Template Filename
  43. */
  44. function SmartTemplateParser ( $template_filename )
  45. {
  46. // Load Template
  47. if ($hd = @fopen($template_filename, "r"))
  48. {
  49. if (filesize($template_filename))
  50. {
  51. $this->template = fread($hd, filesize($template_filename));
  52. }
  53. else
  54. {
  55. $this->template = "SmartTemplate Parser Error: File size is zero byte: '$template_filename'";
  56. }
  57. fclose($hd);
  58. // Extract the name of the template directory
  59. $this->template_dir = dirname($template_filename);
  60. }
  61. else
  62. {
  63. $this->template = "SmartTemplate Parser Error: File not found: '$template_filename'";
  64. }
  65. }
  66. /**
  67. * Main Template Parser
  68. *
  69. * @param string $compiled_template_filename Compiled Template Filename
  70. * @desc Creates Compiled PHP Template
  71. */
  72. function compile( $compiled_template_filename = '' )
  73. {
  74. if (empty($this->template))
  75. {
  76. return;
  77. }
  78. /* Quick hack to allow subtemplates */
  79. if(eregi("<!-- INCLUDE", $this->template))
  80. {
  81. while ($this->count_subtemplates() > 0)
  82. {
  83. preg_match_all('/<!-- INCLUDE ([a-zA-Z0-9_.]+) -->/', $this->template, $tvar);
  84. foreach($tvar[1] as $subfile)
  85. {
  86. if(file_exists($this->template_dir . "/$subfile"))
  87. {
  88. $subst = implode('',file($this->template_dir . "/$subfile"));
  89. }
  90. else
  91. {
  92. $subst = 'SmartTemplate Parser Error: Subtemplate not found: \''.$subfile.'\'';
  93. }
  94. $this->template = str_replace("<!-- INCLUDE $subfile -->", $subst, $this->template);
  95. }
  96. }
  97. }
  98. // END, ELSE Blocks
  99. $page = preg_replace("/<!-- ENDIF.+?-->/", "<?php\n}\n?>", $this->template);
  100. $page = preg_replace("/<!-- END[ a-zA-Z0-9_.]* -->/", "<?php\n}\n\$_obj=\$_stack[--\$_stack_cnt];}\n?>", $page);
  101. $page = str_replace("<!-- ELSE -->", "<?php\n} else {\n?>", $page);
  102. // 'BEGIN - END' Blocks
  103. if (preg_match_all('/<!-- BEGIN ([a-zA-Z0-9_.]+) -->/', $page, $var))
  104. {
  105. foreach ($var[1] as $tag)
  106. {
  107. list($parent, $block) = $this->var_name($tag);
  108. $code = "<?php\n"
  109. . "if (!empty(\$$parent"."['$block'])){\n"
  110. . "if (!is_array(\$$parent"."['$block']))\n"
  111. . "\$$parent"."['$block']=array(array('$block'=>\$$parent"."['$block']));\n"
  112. . "\$_tmp_arr_keys=array_keys(\$$parent"."['$block']);\n"
  113. . "if (\$_tmp_arr_keys[0]!='0')\n"
  114. . "\$$parent"."['$block']=array(0=>\$$parent"."['$block']);\n"
  115. . "\$_stack[\$_stack_cnt++]=\$_obj;\n"
  116. . "foreach (\$$parent"."['$block'] as \$rowcnt=>\$$block) {\n"
  117. . "\$$block"."['ROWCNT']=\$rowcnt;\n"
  118. . "\$$block"."['ALTROW']=\$rowcnt%2;\n"
  119. . "\$$block"."['ROWBIT']=\$rowcnt%2;\n"
  120. . "\$_obj=&\$$block;\n?>";
  121. $page = str_replace("<!-- BEGIN $tag -->", $code, $page);
  122. }
  123. }
  124. // 'IF nnn=mmm' Blocks
  125. if (preg_match_all('/<!-- (ELSE)?IF ([a-zA-Z0-9_.]+)[ ]*([!=<>]+)[ ]*(["]?[^"]*["]?) -->/', $page, $var))
  126. {
  127. foreach ($var[2] as $cnt => $tag)
  128. {
  129. list($parent, $block) = $this->var_name($tag);
  130. $cmp = $var[3][$cnt];
  131. $val = $var[4][$cnt];
  132. $else = ($var[1][$cnt] == 'ELSE') ? '} else' : '';
  133. if ($cmp == '=')
  134. {
  135. $cmp = '==';
  136. }
  137. if (preg_match('/"([^"]*)"/',$val,$matches))
  138. {
  139. $code = "<?php\n$else"."if (\$$parent"."['$block'] $cmp \"".$matches[1]."\"){\n?>";
  140. }
  141. elseif (preg_match('/([^"]*)/',$val,$matches))
  142. {
  143. list($parent_right, $block_right) = $this->var_name($matches[1]);
  144. $code = "<?php\n$else"."if (\$$parent"."['$block'] $cmp \$$parent_right"."['$block_right']){\n?>";
  145. }
  146. $page = str_replace($var[0][$cnt], $code, $page);
  147. }
  148. }
  149. // 'IF nnn' Blocks
  150. if (preg_match_all('/<!-- (ELSE)?IF ([a-zA-Z0-9_.]+) -->/', $page, $var))
  151. {
  152. foreach ($var[2] as $cnt => $tag)
  153. {
  154. $else = ($var[1][$cnt] == 'ELSE') ? '} else' : '';
  155. list($parent, $block) = $this->var_name($tag);
  156. $code = "<?php\n$else"."if (!empty(\$$parent"."['$block'])){\n?>";
  157. $page = str_replace($var[0][$cnt], $code, $page);
  158. }
  159. }
  160. // Replace Scalars
  161. if (preg_match_all('/{([a-zA-Z0-9_. >]+)}/', $page, $var))
  162. {
  163. foreach ($var[1] as $fulltag)
  164. {
  165. // Determin Command (echo / $obj[n]=)
  166. list($cmd, $tag) = $this->cmd_name($fulltag);
  167. list($block, $skalar) = $this->var_name($tag);
  168. $code = "<?php\n$cmd \$$block"."['$skalar'];\n?>\n";
  169. $page = str_replace('{'.$fulltag.'}', $code, $page);
  170. }
  171. }
  172. // ROSI Special: Replace Translations
  173. if (preg_match_all('/<"([a-zA-Z0-9_.]+)">/', $page, $var))
  174. {
  175. foreach ($var[1] as $tag)
  176. {
  177. list($block, $skalar) = $this->var_name($tag);
  178. $code = "<?php\necho gettext('$skalar');\n?>\n";
  179. $page = str_replace('<"'.$tag.'">', $code, $page);
  180. }
  181. }
  182. // Include Extensions
  183. $header = '';
  184. if (preg_match_all('/{([a-zA-Z0-9_]+):([^}]*)}/', $page, $var))
  185. {
  186. foreach ($var[2] as $cnt => $tag)
  187. {
  188. // Determin Command (echo / $obj[n]=)
  189. list($cmd, $tag) = $this->cmd_name($tag);
  190. $extension = $var[1][$cnt];
  191. if (!isset($this->extension_tagged[$extension]))
  192. {
  193. $header .= "include_once \"smarttemplate_extensions/smarttemplate_extension_$extension.php\";\n";
  194. $this->extension_tagged[$extension] = true;
  195. }
  196. if (!strlen($tag))
  197. {
  198. $code = "<?php\n$cmd smarttemplate_extension_$extension();\n?>\n";
  199. }
  200. elseif (substr($tag, 0, 1) == '"')
  201. {
  202. $code = "<?php\n$cmd smarttemplate_extension_$extension($tag);\n?>\n";
  203. }
  204. elseif (strpos($tag, ','))
  205. {
  206. list($tag, $addparam) = explode(',', $tag, 2);
  207. list($block, $skalar) = $this->var_name($tag);
  208. if (preg_match('/^([a-zA-Z_]+)/', $addparam, $match))
  209. {
  210. $nexttag = $match[1];
  211. list($nextblock, $nextskalar) = $this->var_name($nexttag);
  212. $addparam = substr($addparam, strlen($nexttag));
  213. $code = "<?php\n$cmd smarttemplate_extension_$extension(\$$block"."['$skalar'],\$$nextblock"."['$nextskalar']"."$addparam);\n?>\n";
  214. }
  215. else
  216. {
  217. $code = "<?php\n$cmd smarttemplate_extension_$extension(\$$block"."['$skalar'],$addparam);\n?>\n";
  218. }
  219. }
  220. else
  221. {
  222. list($block, $skalar) = $this->var_name($tag);
  223. $code = "<?php\n$cmd smarttemplate_extension_$extension(\$$block"."['$skalar']);\n?>\n";
  224. }
  225. $page = str_replace($var[0][$cnt], $code, $page);
  226. }
  227. }
  228. // Add Include Header
  229. if (isset($header) && !empty($header))
  230. {
  231. $page = "<?php\n$header\n?>$page";
  232. }
  233. // Store Code to Temp Dir
  234. if (strlen($compiled_template_filename))
  235. {
  236. if ($hd = fopen($compiled_template_filename, "w"))
  237. {
  238. fwrite($hd, $page);
  239. fclose($hd);
  240. return true;
  241. }
  242. else
  243. {
  244. $this->error = "Could not write compiled file.";
  245. return false;
  246. }
  247. }
  248. else
  249. {
  250. return $page;
  251. }
  252. }
  253. /**
  254. * Splits Template-Style Variable Names into an Array-Name/Key-Name Components
  255. * {example} : array( "_obj", "example" ) -> $_obj['example']
  256. * {example.value} : array( "_obj['example']", "value" ) -> $_obj['example']['value']
  257. * {example.0.value} : array( "_obj['example'][0]", "value" ) -> $_obj['example'][0]['value']
  258. * {top.example} : array( "_stack[0]", "example" ) -> $_stack[0]['example']
  259. * {parent.example} : array( "_stack[$_stack_cnt-1]", "example" ) -> $_stack[$_stack_cnt-1]['example']
  260. * {parent.parent.example} : array( "_stack[$_stack_cnt-2]", "example" ) -> $_stack[$_stack_cnt-2]['example']
  261. *
  262. * @param string $tag Variale Name used in Template
  263. * @return array Array Name, Key Name
  264. * @access private
  265. * @desc Splits Template-Style Variable Names into an Array-Name/Key-Name Components
  266. */
  267. function var_name($tag)
  268. {
  269. $parent_level = 0;
  270. while (substr($tag, 0, 7) == 'parent.')
  271. {
  272. $tag = substr($tag, 7);
  273. $parent_level++;
  274. }
  275. if (substr($tag, 0, 4) == 'top.')
  276. {
  277. $obj = '_stack[0]';
  278. $tag = substr($tag,4);
  279. }
  280. elseif ($parent_level)
  281. {
  282. $obj = '_stack[$_stack_cnt-'.$parent_level.']';
  283. }
  284. else
  285. {
  286. $obj = '_obj';
  287. }
  288. while (is_int(strpos($tag, '.')))
  289. {
  290. list($parent, $tag) = explode('.', $tag, 2);
  291. if (is_numeric($parent))
  292. {
  293. $obj .= "[" . $parent . "]";
  294. }
  295. else
  296. {
  297. $obj .= "['" . $parent . "']";
  298. }
  299. }
  300. $ret = array($obj, $tag);
  301. return $ret;
  302. }
  303. /**
  304. * Determine Template Command from Variable Name
  305. * {variable} : array( "echo", "variable" ) -> echo $_obj['variable']
  306. * {variable > new_name} : array( "_obj['new_name']=", "variable" ) -> $_obj['new_name']= $_obj['variable']
  307. *
  308. * @param string $tag Variale Name used in Template
  309. * @return array Array Command, Variable
  310. * @access private
  311. * @desc Determine Template Command from Variable Name
  312. */
  313. function cmd_name($tag)
  314. {
  315. if (preg_match('/^(.+) > ([a-zA-Z0-9_.]+)$/', $tag, $tagvar))
  316. {
  317. $tag = $tagvar[1];
  318. list($newblock, $newskalar) = $this->var_name($tagvar[2]);
  319. $cmd = "\$$newblock"."['$newskalar']=";
  320. }
  321. else
  322. {
  323. $cmd = "echo";
  324. }
  325. $ret = array($cmd, $tag);
  326. return $ret;
  327. }
  328. /**
  329. * @return int Number of subtemplate included
  330. * @access private
  331. * @desc Count number of subtemplates included in current template
  332. */
  333. function count_subtemplates()
  334. {
  335. preg_match_all('/<!-- INCLUDE ([a-zA-Z0-9_.]+) -->/', $this->template, $tvar);
  336. $count_subtemplates = count($tvar[1]);
  337. $ret = intval($count_subtemplates);
  338. return $ret;
  339. }
  340. }
  341. ?>