<?php
/**
* FTemplate class
* Author: Fenrir
* ToDo: Description Finished? Order
* -------------------------------------------------------------------------------------------------
* | - Change recurse to while($var = $block['recurse']->next()) [ ] ++ |
* | - Include files [ ] +++ |
* | - If's [ ] ++ |
* | - Foreach (for recurse) [ ] ++ |
* | - Limit recurse: [RECURSE: DEEPER_LEVEL : 3] [+] - |
* | - Blocks [+] - |
* | - Trees (recurse) [+] - |
* | - Cache [ ] ++ |
* | - Compile [+] - |
* -------------------------------------------------------------------------------------------------
* Copyright by Fenrir 2005
*/
class FT_Node
{
/**
* An array that holds the variables for this node
*/
/**
* An array that holds the children for this node
*/
/**
* Constructor
* Sets the variables for this node that are in $vars
*/
function FT_Node
($vars = array()) {
$this->vars = $vars;
}
/**
* Adds a new child-node to this node
*/
function &addItem(&$item)
{
$this->items[] = &$item;
return $this->items[count($this->items) - 1]; }
function toArray()
{
$arr['VARS'] = $this->vars;
$arr['CHILDREN'] = array();
foreach($this->items as $item)
{
$arr['CHILDREN'][] = $item->toArray();
}
return $arr;
}
}
class FT_Recurse
{
/**
* An array that holds the children for this recurse
*/
function FT_Node()
{
}
function &addItem(&$item)
{
$this->items[] = &$item;
return $this->items[count($this->items) - 1]; }
function toArray()
{
foreach($this->items as $item)
{
$arr[] = $item->toArray();
}
return $arr;
}
}
function recurse($array, $set_begin, $set_end, $item_begin, $item_end, $maxdepth = 99, $currdepth = 0)
{
if($currdepth < $maxdepth)
{
foreach($array as $item)
{
$item_begin2 = $item_begin;
$item_end2 = $item_end;
foreach($item['VARS'] as $var => $content)
{
$item_begin2 = str_replace('{recurse_var: '.$var.'}', $content, $item_begin2); $item_end2 = str_replace('{recurse_var: '.$var.'}', $content, $item_end2); }
$item_begin2 = preg_replace('/\{recurse_var: ([a-zA-Z0-9]*)\}/', '', $item_begin2); $item_end2 = preg_replace('/\{recurse_var: ([a-zA-Z0-9]*)\}/', '', $item_end2);
if(!empty($item['CHILDREN'])) {
recurse($item['CHILDREN'], $set_begin, $set_end, $item_begin, $item_end, $maxdepth, $currdepth + 1);
}
}
}
}
function recurse_arg($str)
{
$str = str_replace('"', '\"', $str);
$str = preg_replace('/\[([a-zA-Z0-9]*)\]/', '" . @\$constants["\\1"] . "', $str);
$str = preg_replace('/\{([a-zA-Z0-9]*)\}/', '{recurse_var: \\1}', $str);
return $str;
}
class FTemplate
{
# The non-compiled templatefile
var $TemplateFile = '';
# The cached (compiled) templatefile
var $CompiledTemplateFile = '';
# The cached config
var $CompiledTemplateConfigFile = '';
# The cache-dir
var $CacheDir = 'cache/';
# The contents of the non-compiled template
var $Template = '';
# The templatedata (blocks and vars)
var $TemplateData = array(
'BLOCKS' => array(),
'VARS' => array()
);
# The constants
var $constants = array();
# The contents of the compiled template
var $CompiledTemplate = '';
# The parsed template
var $ParsedTemplate = '';
# Is the template compiled yet?
var $Compiled = false;
# Is the template parsed yet?
var $Parsed = false;
# The options array
var $Options = array(
'forcecompile' => false
);
# The blocks
var $blocks = array();
# The current block
var $currBlock = array();
# FTemplate($Template):
# Constructor
# $Template contains the path to the templatefile
function FTemplate($Template, $options = array())
{
$this->currBlock = &$this->TemplateData;
foreach($options as $Opt => $OptVal)
{
$this->Options[$Opt] = $OptVal;
}
if(is_file($Template))
{
$this->TemplateFile = $Template;
$this->CompiledTemplateFile = md5($Template) . '_TEMLPATE.ctpl';
$this->CompiledTemplateConfigFile = md5($Template) . '_CONFIG.ctpl';
//echo 'TEMPLATE MOD TIME: ' . filemtime($this->TemplateFile) . '<br />';
//echo 'CTEMPLATE MOD TIME: ' . filemtime($this->CacheDir . $this->CompiledTemplateFile) . '<br />';
if(!is_file($this->CacheDir . $this->CompiledTemplateConfigFile) ||
filemtime($this->CacheDir . $this->CompiledTemplateConfigFile) < filemtime($this->TemplateFile) ||
!is_file($this->CacheDir . $this->CompiledTemplateFile) ||
filemtime($this->CacheDir . $this->CompiledTemplateFile) < filemtime($this->TemplateFile) ||
$this->Options['forcecompile'])
{
#The template isn't compiled yet, compile it now
$this->Template = file_get_contents($this->TemplateFile);
$this->Compile();
$this->CacheCompiled();
}else
{
# The template is already compiled
$this->CompiledTemplate = file_get_contents($this->CacheDir . $this->CompiledTemplateFile);
$this->blocks = unserialize(file_get_contents($this->CacheDir . $this->CompiledTemplateConfigFile));
$this->Compiled = true;
}
}else
{
$this->Error('The Templatefile doesn\'t exist!');
}
}
function Compile()
{
if(!empty($this->Template))
{
$Template = str_replace('<?', '<?', str_replace('?>', '?>', $this->Template));
preg_match_all('#\[START RECURSE : ([A-Za-z0-9_\-]+)\]
((?s).*)
\[RECURSE : START_ITEM\]((?s).*)\[RECURSE : DEEPER_LEVEL : ([0-9]+)\]((?s).*)\[RECURSE : END_ITEM\]
((?s).*)
\[END RECURSE : \\1\]#i', $Template, $matches);
$search = $matches[0];
$replace = array();
$count = count($matches[0]);
for($i = 0; $i < $count; $i++)
{
$replace[] = '<?php @recurse($block["VARS"]["' . $matches[1][$i] . '"], "'
. recurse_arg($matches[2][$i]) . '", "'
. recurse_arg($matches[6][$i]) . '", "'
. recurse_arg($matches[3][$i]) . '", "'
. recurse_arg($matches[5][$i]) . '", ' .
$matches[4][$i] . '); ?>';
}
$Template = str_replace($search, $replace, $Template);
# The Variables
$Template = preg_replace('/\{([a-zA-Z0-9]*)\}/', '<?=@\$block["VARS"]["\\1"]?>', $Template);
# The constants
$Template = preg_replace('/\[([a-zA-Z0-9]*)\]/', '<?=@\$constants["\\1"]?>', $Template);
# The templatearray
$tplarray = array();
preg_match_all('/\[(START|END) BLOCK : ([A-Za-z0-9_\-]+)\]/', $Template, $parts);
# Array to hold the blocks that are currently open
$openBlocks = array();
# Array that will be stored in the conpiledtemplate_config file
$blocks = array();
# Validate the blocks
$count = count($parts[0]);
for($i = 0; $i < $count; ++$i)
{
$blockName = $parts[2][$i];
$blockType = $parts[1][$i];
if($blockType == 'START')
{
if(!in_array($blockName, $openBlocks))
{
$blocks[$blockName] = $openBlocks;
$openBlocks[] = $blockName;
}else
{
$this->Error('There are two or more blocks with the same name!');
}
}else
{
if($openBlocks[count($openBlocks) - 1] == $blockName)
{
array_pop($openBlocks);
}else
{
$this->Error('The blocks are not properly nested!');
}
}
}
$this->blocks = $blocks;
if(count($openBlocks) != 0)
{
$this->Error('There are blocks that are not closed!', 2);
}
# Compile the template
# The array with the tag-strings
$search = array();
# The array with the php-code strings
$replace = array();
$count = count($parts[0]);
for($i = 0; $i < $count; ++$i)
{
$blockName = $parts[2][$i];
$blockType = $parts[1][$i];
$blockTag = $parts[0][$i];
$search[] = $blockTag;
if($blockType == 'START')
{
$replace[] = '<?php
if(isset($block["BLOCKS"]["' . $blockName . '"])):
foreach($block["BLOCKS"]["' . $blockName . '"] as $block):
?>';
}else
{
$replace[] = '<?php
endforeach;
endif;
?>';
}
}
$Template = str_replace($search, $replace, $Template);
$this->CompiledTemplate = $Template;
$this->Compiled = true;
$this->Config = serialize($blocks);
}else
{
$this->Error('The Template isn\'t set!');
}
}
function CacheCompiled()
{
if($this->Compiled)
{
$h = fopen($this->CacheDir . $this->CompiledTemplateFile, 'w');
fwrite($h, $this->CompiledTemplate);
fclose($h);
$h = fopen($this->CacheDir . $this->CompiledTemplateConfigFile, 'w');
fwrite($h, $this->Config);
fclose($h);
}else
{
$this->Error('The Template isn\'t compiled yet!');
}
}
function GetTemplate()
{
if(empty($this->Template))
{
$this->Error('The Template isn\'t set!');
}else
{
return $this->Template;
}
}
function GetCompiledTemplate()
{
if(empty($this->CompiledTemplate))
{
$this->Error('The Compiled Template isn\'t set!');
}else
{
return $this->CompiledTemplate;
}
}
function GetTemplateData()
{
return $this->blocks;
}
function newBlock($block)
{
$pblock = &$this->TemplateData;
if(isset($this->blocks[$block]))
{
$blockparents = $this->blocks[$block];
}else
{
$this->Error('The block <i>"' . $block . '"</i> doesn\'t exist in the template <i>"' . $this->TemplateFile . '"</i>.');
}
foreach($blockparents as $pname)
{
if(!isset($pblock['BLOCKS'][$pname]))
{
$pblock['BLOCKS'][$pname] = array();
}
$pblock = &$pblock['BLOCKS'][$pname][count($pblock['BLOCKS'][$pname]) - 1];
}
if(!isset($pblock['BLOCKS'][$block]))
{
$pblock['BLOCKS'][$block] = array();
}
$pblock = &$pblock['BLOCKS'][$block][count($pblock['BLOCKS'][$block])];
$this->currBlock = &$pblock;
}
function Assign($var, $content)
{
$this->currBlock['VARS'][$var] = $content;
}
function AssignConstant($var, $content)
{
$this->constants[$var] = $content;
}
function AssignTree($var, $content)
{
$this->currBlock['VARS'][$var] = $content->toArray();
}
function Parse()
{
if($this->Compiled)
{
ob_start();
$block = &$this->TemplateData;
$constants = &$this->constants;
include($this->CacheDir . $this->CompiledTemplateFile);
$this->ParsedTemplate = ob_get_contents();
ob_end_clean();
}else
{
$this->Error('The template isn\'t compiled yet!');
}
$this->Parsed = true;
}
function PrintToScreen()
{
if($this->Parsed)
{
echo $this->ParsedTemplate;
}else
{
if($this->Compiled)
{
$block = &$this->TemplateData;
$constants = &$this->constants;
include($this->CacheDir . $this->CompiledTemplateFile);
}else
{
$this->Error('The template isn\'t compiled yet!');
}
}
}
function GetParsedTemplate()
{
if($this->Parsed)
{
return $this->ParsedTemplate;
}else
{
$this->Parse();
return $this->ParsedTemplate;
}
}
function Error($msg, $eLevel = 1)
{
if($eLevel == 2)
{
die($msg);
}else
{
die($msg);
}
}
}
/**
* Copyright by Fenrir 2005
*/
?>