PageRenderTime 22ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/campsite/src/include/phorum/include/templates.php

https://github.com/joechrysler/Campsite
PHP | 380 lines | 228 code | 73 blank | 79 comment | 49 complexity | 1464a075e513531562ad20e266ac055b MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, LGPL-2.1, Apache-2.0
  1. <?php
  2. ////////////////////////////////////////////////////////////////////////////////
  3. // //
  4. // Copyright (C) 2006 Phorum Development Team //
  5. // http://www.phorum.org //
  6. // //
  7. // This program is free software. You can redistribute it and/or modify //
  8. // it under the terms of either the current Phorum License (viewable at //
  9. // phorum.org) or the Phorum License that was distributed with this file //
  10. // //
  11. // This program is distributed in the hope that it will be useful, //
  12. // but WITHOUT ANY WARRANTY, without even the implied warranty of //
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
  14. // //
  15. // You should have received a copy of the Phorum License //
  16. // along with this program. //
  17. ////////////////////////////////////////////////////////////////////////////////
  18. if(!defined("PHORUM")) return;
  19. // For keeping track of include dependancies, which
  20. // are used to let templates automatically rebuild
  21. // in case an included subtemplate has been changed.
  22. $include_level = 0;
  23. $include_deps = array();
  24. function phorum_import_template($tplfile, $outfile)
  25. {
  26. global $include_level, $include_deps;
  27. $include_level++;
  28. // Remember that we used this template.
  29. $include_deps[$tplfile] = $outfile;
  30. // In case we're handling 0 byte large files, we set $page
  31. // directly. Running fread($fp, 0) gives a PHP warning.
  32. if (filesize($tplfile)) {
  33. $fp=fopen($tplfile, "r");
  34. $page=fread($fp, filesize($tplfile));
  35. fclose($fp);
  36. } else {
  37. $page = '';
  38. }
  39. preg_match_all("/\{[\!\/A-Za-z].+?\}/s", $page, $matches);
  40. settype($oldloopvar, "string");
  41. settype($loopvar, "string");
  42. settype($olddatavar, "string");
  43. settype($datavar, "string");
  44. $loopvars = array();
  45. foreach($matches[0] as $match){
  46. unset($parts);
  47. $string=substr($match, 1, -1);
  48. $string = trim($string);
  49. // pre-parse pointer variables
  50. if(strstr($string, "->")){
  51. $string=str_replace("->", "']['", $string);
  52. }
  53. $parts=explode(" ", $string);
  54. switch(strtolower($parts[0])){
  55. // Comment
  56. case "!":
  57. $repl="<?php // ".implode(" ", $parts)." ?>";
  58. break;
  59. case "include":
  60. $repl = file_get_contents(phorum_get_template($parts[1],1));
  61. break;
  62. case "include_once":
  63. $repl="<?php include_once phorum_get_template('$parts[1]'); ?>";
  64. break;
  65. case "include_var": // include a file given by a variable
  66. $repl="<?php include_once phorum_get_template( \$PHORUM[\"DATA\"]['$parts[1]']); ?>";
  67. break;
  68. // A define is used to create vars for the engine to use.
  69. case "define":
  70. $repl="<?php \$PHORUM[\"TMP\"]['$parts[1]']='";
  71. array_shift($parts);
  72. array_shift($parts);
  73. foreach($parts as $part){
  74. $repl.=str_replace("'", "\\'", $part)." ";
  75. }
  76. $repl=trim($repl)."'; ?>";
  77. break;
  78. // A var is used to create vars for the template.
  79. case "var":
  80. $repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']='";
  81. array_shift($parts);
  82. array_shift($parts);
  83. foreach($parts as $part){
  84. $repl.=str_replace("'", "\\'", $part)." ";
  85. }
  86. $repl=trim($repl)."'; ?>";
  87. break;
  88. // Run a Phorum hook. The first parameter is the name of the
  89. // hook. Other parameters will be passed on as arguments for
  90. // the hook function. On argument will be passed directly to
  91. // the hook. Multiple arguments will be passed in an array.
  92. case "hook":
  93. // Setup hook arguments.
  94. $hookargs = array();
  95. for($i = 2; !empty($parts[$i]); $i++) {
  96. // For supporting the following construct, where the
  97. // loopvar is passed to the hook in full:
  98. // {LOOP SOMELIST}
  99. // {HOOK some_hook SOMELIST}
  100. // {/LOOP SOMELIST}
  101. if (isset($loopvars[$parts[$i]])) {
  102. $hookargs[] = "\$PHORUM['TMP']['".addslashes($parts[$i])."']";
  103. } else {
  104. $index = phorum_determine_index($loopvars, $parts[$i]);
  105. $hookargs[] = "\$PHORUM['$index']['".addslashes($parts[$i])."']";
  106. }
  107. }
  108. // Build the replacement string.
  109. $repl = "<?php if(isset(\$PHORUM['hooks']['".addslashes($parts[1])."'])) phorum_hook('".addslashes($parts[1])."'";
  110. if (count($hookargs) == 1) {
  111. $repl .= "," . $hookargs[0];
  112. } elseif (count($hookargs) > 1) {
  113. $repl .= ",array(" . implode(",", $hookargs) . ")";
  114. }
  115. $repl .= ");?>";
  116. break;
  117. // starts a loop
  118. case "loop":
  119. $loopvars[$parts[1]]=true;
  120. $index=phorum_determine_index($loopvars, $parts[1]);
  121. $repl="<?php \$phorum_loopstack[] = isset(\$PHORUM['TMP']['$parts[1]']) ? \$PHORUM['TMP']['$parts[1]']:NULL; if(isset(\$PHORUM['$index']['$parts[1]']) && is_array(\$PHORUM['$index']['$parts[1]'])) foreach(\$PHORUM['$index']['$parts[1]'] as \$PHORUM['TMP']['$parts[1]']){ ?>";
  122. break;
  123. // ends a loop
  124. case "/loop":
  125. if (!isset($parts[1])) print "<h3>Template warning: Missing argument for /loop statement in file '" . htmlspecialchars($tplfile) . "'</h3>";
  126. $repl="<?php } if(isset(\$PHORUM['TMP']) && isset(\$PHORUM['TMP']['$parts[1]'])) unset(\$PHORUM['TMP']['$parts[1]']); \$phorum_loopstackitem=array_pop(\$phorum_loopstack); if (isset(\$phorum_loopstackitem)) \$PHORUM['TMP']['$parts[1]'] = \$phorum_loopstackitem;?>";
  127. unset($loopvars[$parts[1]]);
  128. break;
  129. // if and elseif are the same accept how the line starts
  130. case "if":
  131. case "elseif":
  132. // determine if or elseif
  133. $prefix = (strtolower($parts[0])=="if") ? "if" : "} elseif";
  134. // are we wanting == or !=
  135. if(strtolower($parts[1])=="not"){
  136. $operator="!=";
  137. $parts[1]=$parts[2];
  138. if(isset($parts[3])){
  139. $parts[2]=$parts[3];
  140. unset($parts[3]);
  141. } else {
  142. unset($parts[2]);
  143. }
  144. } else {
  145. $operator="==";
  146. }
  147. $index=phorum_determine_index($loopvars, $parts[1]);
  148. // if there is no part 2, check that the value is set and not empty
  149. if(!isset($parts[2])){
  150. if($operator=="=="){
  151. $repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && !empty(\$PHORUM['$index']['$parts[1]'])){ ?>";
  152. } else {
  153. $repl="<?php $prefix(!isset(\$PHORUM['$index']['$parts[1]']) || empty(\$PHORUM['$index']['$parts[1]'])){ ?>";
  154. }
  155. // if it is numeric, a constant or a string, simply set it as is
  156. } elseif(is_numeric($parts[2]) || defined($parts[2]) || preg_match('!"[^"]*"!', $parts[2])) {
  157. $repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && \$PHORUM['$index']['$parts[1]']$operator$parts[2]){ ?>";
  158. // we must have a template var
  159. } else {
  160. $index_part2=phorum_determine_index($loopvars, $parts[2]);
  161. // this is a really complicated IF we are building.
  162. $repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && isset(\$PHORUM['$index_part2']['$parts[2]']) && \$PHORUM['$index']['$parts[1]']$operator\$PHORUM['$index_part2']['$parts[2]']) { ?>";
  163. }
  164. // reset $prefix
  165. $prefix="";
  166. break;
  167. // create an else
  168. case "else":
  169. $repl="<?php } else { ?>";
  170. break;
  171. // close an if
  172. case "/if":
  173. $repl="<?php } ?>";
  174. break;
  175. case "assign":
  176. if(defined($parts[2]) || is_numeric($parts[2])){
  177. $repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']=$parts[2]; ?>";
  178. } else {
  179. $index=phorum_determine_index($loopvars, $parts[2]);
  180. $repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']=\$PHORUM['$index']['$parts[2]']; ?>";
  181. }
  182. break;
  183. // this is just for echoing vars from DATA or TMP if it is a loopvar
  184. default:
  185. if(defined($parts[0])){
  186. $repl="<?php echo $parts[0]; ?>";
  187. } else {
  188. $index=phorum_determine_index($loopvars, $parts[0]);
  189. $repl="<?php echo \$PHORUM['$index']['$parts[0]']; ?>";
  190. }
  191. }
  192. $page=str_replace($match, $repl, $page);
  193. }
  194. $include_level--;
  195. // Did we finish processing our top level template? Then write out
  196. // the compiled template to the cache.
  197. //
  198. // For storing the compiled template, we use two files. The first one
  199. // has some code for checking if one of the dependant files has been
  200. // updated and for rebuilding the template if this is the case.
  201. // This one loads the second file, which is the template itself.
  202. //
  203. // This two-stage loading is needed to make sure that syntax
  204. // errors in a template file won't break the depancy checking process.
  205. // If both were in the same file, the complete file would not be run
  206. // at all and the user would have to clean out the template cache to
  207. // reload the template once it was fixed. This way user intervention
  208. // is never needed.
  209. if ($include_level == 0)
  210. {
  211. // Find the template name for the top level template.
  212. $pathparts = preg_split('[\\/]', $outfile);
  213. $fileparts = explode('-', preg_replace('/^.*\//', '', $pathparts[count($pathparts)-1]));
  214. $this_template = addslashes($fileparts[2]);
  215. // Determine first and second stage cache filenames.
  216. $stage1_file = $outfile;
  217. $fileparts[3] = "toplevel_stage2";
  218. unset($pathparts[count($pathparts)-1]);
  219. $stage2_file = implode('/', $pathparts) . '/' . implode('-', $fileparts);
  220. // Create code for automatic rebuilding of rendered templates
  221. // in case of changes. This is done by checking if one of the
  222. // templates in the dependancy list has been updated. If this
  223. // is the case, all dependant rendered subtemplates are deleted.
  224. // After that phorum_get_template() is called on the top level
  225. // template to rebuild all needed templates.
  226. $check_deps =
  227. "<?php\n" .
  228. '$mymtime = @filemtime("' . addslashes($stage1_file) . '");' . "\n" .
  229. "\$update_count = 0;\n" .
  230. "\$need_update = (\n";
  231. foreach ($include_deps as $tpl => $out) {
  232. $qtpl = addslashes($tpl);
  233. $check_deps .= " @filemtime(\"$qtpl\") > \$mymtime ||\n";
  234. }
  235. $check_deps = substr($check_deps, 0, -4); // strip trailing " ||\n"
  236. $check_deps .=
  237. "\n" .
  238. ");\n" .
  239. "if (\$need_update) {\n";
  240. foreach ($include_deps as $tpl => $out) {
  241. $qout = addslashes($out);
  242. $check_deps .= " @unlink(\"$qout\");\n";
  243. }
  244. $check_deps .=
  245. " \$tplfile = phorum_get_template(\"$this_template\");\n" .
  246. "}\n" .
  247. "include(\"" . addslashes($stage2_file) . "\");\n" .
  248. "?>\n";
  249. // Reset dependancy list for the next phorum_import_template() call.
  250. $include_deps = array();
  251. // Write out data to the cache.
  252. phorum_write_templatefile($stage1_file, $check_deps);
  253. phorum_write_templatefile($stage2_file, $page, true);
  254. }
  255. else
  256. {
  257. // Write out subtemplate to the cache.
  258. phorum_write_templatefile($outfile, $page);
  259. }
  260. }
  261. function phorum_write_templatefile($filename, $content, $is_toplevel = false)
  262. {
  263. if($fp=fopen($filename, "w")) {
  264. fputs($fp, "<?php if(!defined(\"PHORUM\")) return; ?>\n");
  265. if ($is_toplevel) {
  266. fputs($fp, "<?php \$phorum_loopstack = array() ?>\n");
  267. }
  268. fputs($fp, $content);
  269. if (! fclose($fp)) {
  270. die("Error on closing $filename. Is your disk full?");
  271. }
  272. // Some very unusual thing might happen. On Windows2000 we have seen
  273. // that the webserver can write a message to the cache directory,
  274. // but that it cannot read it afterwards. Probably due to
  275. // specific NTFS file permission settings. So here we have to make
  276. // sure that we can open the file that we just wrote.
  277. $checkfp = fopen($filename, "r");
  278. if (! $checkfp) {
  279. die("Failed to write a usable compiled template to $filename. " .
  280. "The file was was created successfully, but it could not " .
  281. "be read by the webserver afterwards. This is probably " .
  282. "caused by the file permissions on your cache directory.");
  283. }
  284. fclose($checkfp);
  285. } else {
  286. die("Failed to write a compiled template to $filename. This is " .
  287. "probably caused by the file permissions on your cache " .
  288. "directory.");
  289. }
  290. }
  291. function phorum_determine_index($loopvars, $varname)
  292. {
  293. if(isset($loopvars) && count($loopvars)){
  294. while(strstr($varname, "]")){
  295. $varname=substr($varname, 0, strrpos($varname, "]")-1);
  296. if(isset($loopvars[$varname])){
  297. return "TMP";
  298. break;
  299. }
  300. }
  301. }
  302. return "DATA";
  303. }
  304. ?>