New file |
0,0 → 1,380 |
<?php |
|
//////////////////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2006 Phorum Development Team // |
// http://www.phorum.org // |
// // |
// This program is free software. You can redistribute it and/or modify // |
// it under the terms of either the current Phorum License (viewable at // |
// phorum.org) or the Phorum License that was distributed with this file // |
// // |
// This program is distributed in the hope that it will be useful, // |
// but WITHOUT ANY WARRANTY, without even the implied warranty of // |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // |
// // |
// You should have received a copy of the Phorum License // |
// along with this program. // |
//////////////////////////////////////////////////////////////////////////////// |
|
if(!defined("PHORUM")) return; |
|
// For keeping track of include dependancies, which |
// are used to let templates automatically rebuild |
// in case an included subtemplate has been changed. |
$include_level = 0; |
$include_deps = array(); |
|
function phorum_import_template($tplfile, $outfile) |
{ |
global $include_level, $include_deps; |
$include_level++; |
|
// Remember that we used this template. |
$include_deps[$tplfile] = $outfile; |
|
// In case we're handling 0 byte large files, we set $page |
// directly. Running fread($fp, 0) gives a PHP warning. |
if (filesize($tplfile)) { |
$fp=fopen($tplfile, "r"); |
$page=fread($fp, filesize($tplfile)); |
fclose($fp); |
} else { |
$page = ''; |
} |
|
preg_match_all("/\{[\!\/A-Za-z].+?\}/s", $page, $matches); |
|
settype($oldloopvar, "string"); |
settype($loopvar, "string"); |
settype($olddatavar, "string"); |
settype($datavar, "string"); |
$loopvars = array(); |
|
foreach($matches[0] as $match){ |
unset($parts); |
|
$string=substr($match, 1, -1); |
|
$string = trim($string); |
|
// pre-parse pointer variables |
if(strstr($string, "->")){ |
$string=str_replace("->", "']['", $string); |
} |
|
$parts=explode(" ", $string); |
|
switch(strtolower($parts[0])){ |
|
// Comment |
case "!": |
|
$repl="<?php // ".implode(" ", $parts)." ?>"; |
break; |
|
|
case "include": |
|
$repl = file_get_contents(phorum_get_template($parts[1],1)); |
break; |
|
case "include_once": |
|
$repl="<?php include_once phorum_get_template('$parts[1]'); ?>"; |
break; |
|
case "include_var": // include a file given by a variable |
|
$repl="<?php include_once phorum_get_template( \$PHORUM[\"DATA\"]['$parts[1]']); ?>"; |
break; |
|
// A define is used to create vars for the engine to use. |
case "define": |
|
$repl="<?php \$PHORUM[\"TMP\"]['$parts[1]']='"; |
array_shift($parts); |
array_shift($parts); |
foreach($parts as $part){ |
$repl.=str_replace("'", "\\'", $part)." "; |
} |
$repl=trim($repl)."'; ?>"; |
break; |
|
|
// A var is used to create vars for the template. |
case "var": |
|
$repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']='"; |
array_shift($parts); |
array_shift($parts); |
foreach($parts as $part){ |
$repl.=str_replace("'", "\\'", $part)." "; |
} |
$repl=trim($repl)."'; ?>"; |
break; |
|
// Run a Phorum hook. The first parameter is the name of the |
// hook. Other parameters will be passed on as arguments for |
// the hook function. On argument will be passed directly to |
// the hook. Multiple arguments will be passed in an array. |
case "hook": |
|
// Setup hook arguments. |
$hookargs = array(); |
for($i = 2; !empty($parts[$i]); $i++) { |
// For supporting the following construct, where the |
// loopvar is passed to the hook in full: |
// {LOOP SOMELIST} |
// {HOOK some_hook SOMELIST} |
// {/LOOP SOMELIST} |
if (isset($loopvars[$parts[$i]])) { |
$hookargs[] = "\$PHORUM['TMP']['".addslashes($parts[$i])."']"; |
} else { |
$index = phorum_determine_index($loopvars, $parts[$i]); |
$hookargs[] = "\$PHORUM['$index']['".addslashes($parts[$i])."']"; |
} |
} |
|
// Build the replacement string. |
$repl = "<?php if(isset(\$PHORUM['hooks']['".addslashes($parts[1])."'])) phorum_hook('".addslashes($parts[1])."'"; |
if (count($hookargs) == 1) { |
$repl .= "," . $hookargs[0]; |
} elseif (count($hookargs) > 1) { |
$repl .= ",array(" . implode(",", $hookargs) . ")"; |
} |
$repl .= ");?>"; |
break; |
|
// starts a loop |
case "loop": |
|
$loopvars[$parts[1]]=true; |
$index=phorum_determine_index($loopvars, $parts[1]); |
$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]']){ ?>"; |
break; |
|
|
// ends a loop |
case "/loop": |
|
if (!isset($parts[1])) print "<h3>Template warning: Missing argument for /loop statement in file '" . htmlspecialchars($tplfile) . "'</h3>"; |
$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;?>"; |
unset($loopvars[$parts[1]]); |
break; |
|
|
// if and elseif are the same accept how the line starts |
case "if": |
case "elseif": |
|
// determine if or elseif |
$prefix = (strtolower($parts[0])=="if") ? "if" : "} elseif"; |
|
// are we wanting == or != |
if(strtolower($parts[1])=="not"){ |
$operator="!="; |
$parts[1]=$parts[2]; |
if(isset($parts[3])){ |
$parts[2]=$parts[3]; |
unset($parts[3]); |
} else { |
unset($parts[2]); |
} |
} else { |
$operator="=="; |
} |
|
$index=phorum_determine_index($loopvars, $parts[1]); |
|
// if there is no part 2, check that the value is set and not empty |
if(!isset($parts[2])){ |
if($operator=="=="){ |
$repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && !empty(\$PHORUM['$index']['$parts[1]'])){ ?>"; |
} else { |
$repl="<?php $prefix(!isset(\$PHORUM['$index']['$parts[1]']) || empty(\$PHORUM['$index']['$parts[1]'])){ ?>"; |
} |
|
// if it is numeric, a constant or a string, simply set it as is |
} elseif(is_numeric($parts[2]) || defined($parts[2]) || preg_match('!"[^"]*"!', $parts[2])) { |
$repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && \$PHORUM['$index']['$parts[1]']$operator$parts[2]){ ?>"; |
|
// we must have a template var |
} else { |
|
$index_part2=phorum_determine_index($loopvars, $parts[2]); |
|
// this is a really complicated IF we are building. |
|
$repl="<?php $prefix(isset(\$PHORUM['$index']['$parts[1]']) && isset(\$PHORUM['$index_part2']['$parts[2]']) && \$PHORUM['$index']['$parts[1]']$operator\$PHORUM['$index_part2']['$parts[2]']) { ?>"; |
|
} |
|
// reset $prefix |
$prefix=""; |
break; |
|
|
// create an else |
case "else": |
|
$repl="<?php } else { ?>"; |
break; |
|
|
// close an if |
case "/if": |
|
$repl="<?php } ?>"; |
break; |
|
case "assign": |
if(defined($parts[2]) || is_numeric($parts[2])){ |
$repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']=$parts[2]; ?>"; |
} else { |
$index=phorum_determine_index($loopvars, $parts[2]); |
|
$repl="<?php \$PHORUM[\"DATA\"]['$parts[1]']=\$PHORUM['$index']['$parts[2]']; ?>"; |
} |
break; |
|
|
// this is just for echoing vars from DATA or TMP if it is a loopvar |
default: |
|
if(defined($parts[0])){ |
$repl="<?php echo $parts[0]; ?>"; |
} else { |
|
$index=phorum_determine_index($loopvars, $parts[0]); |
|
$repl="<?php echo \$PHORUM['$index']['$parts[0]']; ?>"; |
} |
} |
|
$page=str_replace($match, $repl, $page); |
} |
|
$include_level--; |
|
// Did we finish processing our top level template? Then write out |
// the compiled template to the cache. |
// |
// For storing the compiled template, we use two files. The first one |
// has some code for checking if one of the dependant files has been |
// updated and for rebuilding the template if this is the case. |
// This one loads the second file, which is the template itself. |
// |
// This two-stage loading is needed to make sure that syntax |
// errors in a template file won't break the depancy checking process. |
// If both were in the same file, the complete file would not be run |
// at all and the user would have to clean out the template cache to |
// reload the template once it was fixed. This way user intervention |
// is never needed. |
if ($include_level == 0) |
{ |
// Find the template name for the top level template. |
$pathparts = preg_split('[\\/]', $outfile); |
$fileparts = explode('-', preg_replace('/^.*\//', '', $pathparts[count($pathparts)-1])); |
$this_template = addslashes($fileparts[2]); |
|
// Determine first and second stage cache filenames. |
$stage1_file = $outfile; |
$fileparts[3] = "toplevel_stage2"; |
unset($pathparts[count($pathparts)-1]); |
$stage2_file = implode('/', $pathparts) . '/' . implode('-', $fileparts); |
|
// Create code for automatic rebuilding of rendered templates |
// in case of changes. This is done by checking if one of the |
// templates in the dependancy list has been updated. If this |
// is the case, all dependant rendered subtemplates are deleted. |
// After that phorum_get_template() is called on the top level |
// template to rebuild all needed templates. |
|
$check_deps = |
"<?php\n" . |
'$mymtime = @filemtime("' . addslashes($stage1_file) . '");' . "\n" . |
"\$update_count = 0;\n" . |
"\$need_update = (\n"; |
foreach ($include_deps as $tpl => $out) { |
$qtpl = addslashes($tpl); |
$check_deps .= " @filemtime(\"$qtpl\") > \$mymtime ||\n"; |
} |
$check_deps = substr($check_deps, 0, -4); // strip trailing " ||\n" |
$check_deps .= |
"\n" . |
");\n" . |
"if (\$need_update) {\n"; |
foreach ($include_deps as $tpl => $out) { |
$qout = addslashes($out); |
$check_deps .= " @unlink(\"$qout\");\n"; |
} |
$check_deps .= |
" \$tplfile = phorum_get_template(\"$this_template\");\n" . |
"}\n" . |
"include(\"" . addslashes($stage2_file) . "\");\n" . |
"?>\n"; |
|
// Reset dependancy list for the next phorum_import_template() call. |
$include_deps = array(); |
|
// Write out data to the cache. |
phorum_write_templatefile($stage1_file, $check_deps); |
phorum_write_templatefile($stage2_file, $page, true); |
} |
else |
{ |
// Write out subtemplate to the cache. |
phorum_write_templatefile($outfile, $page); |
} |
|
|
} |
|
function phorum_write_templatefile($filename, $content, $is_toplevel = false) |
{ |
if($fp=fopen($filename, "w")) { |
fputs($fp, "<?php if(!defined(\"PHORUM\")) return; ?>\n"); |
if ($is_toplevel) { |
fputs($fp, "<?php \$phorum_loopstack = array() ?>\n"); |
} |
fputs($fp, $content); |
if (! fclose($fp)) { |
die("Error on closing $filename. Is your disk full?"); |
} |
// Some very unusual thing might happen. On Windows2000 we have seen |
// that the webserver can write a message to the cache directory, |
// but that it cannot read it afterwards. Probably due to |
// specific NTFS file permission settings. So here we have to make |
// sure that we can open the file that we just wrote. |
$checkfp = fopen($filename, "r"); |
if (! $checkfp) { |
die("Failed to write a usable compiled template to $filename. " . |
"The file was was created successfully, but it could not " . |
"be read by the webserver afterwards. This is probably " . |
"caused by the file permissions on your cache directory."); |
} |
fclose($checkfp); |
} else { |
die("Failed to write a compiled template to $filename. This is " . |
"probably caused by the file permissions on your cache " . |
"directory."); |
} |
} |
|
function phorum_determine_index($loopvars, $varname) |
{ |
if(isset($loopvars) && count($loopvars)){ |
while(strstr($varname, "]")){ |
$varname=substr($varname, 0, strrpos($varname, "]")-1); |
if(isset($loopvars[$varname])){ |
return "TMP"; |
break; |
} |
} |
} |
|
return "DATA"; |
} |
|
?> |