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