<?php
/********* Simple Template Class ********/

// Author: slave@codegrunt.com / http://codegrunt.com
// This is a simple template class which can be easily expanded
// and supports multiple templates (which is useful for having headers
// and footers for example).
//
// templates are rendered in the order they are loaded
// templates can be rendered to the browser or returned as a string
// (which is useful for generating email messages)
//
// if you would like help expanding this template class to fulfill
// your needs drop me a note (the one I use for production purposes
// supports loops, formatting flags, etc.).

/*
usage:  

To make use of this template class you need to first create a template. A template file 
is just a plain text file which has placeholders for variables you would like filled in. 
The template class supports "built ins" which means that you can reference internal template 
functions (to do things such as display environment variables) as well as user defined 
variables.  This specific class only supports scalar variables but it is simple to 
expand it to support objects and other placeholder types (I am not doing so here to keep
things relatively simple).

example:

"template.html"

---------
<h1>This is a template</h1>

<p>Hello ^name_first^, is your favourite colour ^fave_colour^?</p>

<p>Your IP address is ^T@getenv@REMOTE_ADDR^.
---------

The above template has two placeholders in it - "^name_first^" which references a variable 
in the cargo hold and the built in "^T@getenv@REMOTE_ADDR^".  The built in reference is 
denoted by a leading "T" and the syntax for these is:

T@<built in function>@[argument]

The function name is mandatory, the argument is optional depending 
on the built in you are referencing. Current built ins are:

T@self - prints $_SERVER['PHP_SELF']
T@getenv@var - prints the environment variable "var"

To use the above template you need to first instantiate the class, place any variables
you want the template to have access to into the cargo hold (i.e. $this->cargo), load the template you want 
to parse and then render the template:

<?php

$tpl=new Template;

// load header
$tpl->load_tpl('header.html');

// load page body
$tpl->load_tpl('template.html');

// place stuff we need in cargo hold
$tpl->cargo['name_first']=strip_tags($_POST['name_first']);

// you can use references instead of copies where appropriate
$fave_colour='red';
$tpl->cargo['fave_colour']=&$fave_colour;

// load footer
$tpl->load_tpl('footer.html');

// render template
$tpl->render_tpl();

?>
*/

/******* beginning of class and associated functions *********/

// first define template placeholder delimiters
define('_tpl_delim_left','^');
define('_tpl_delim_right','^');

class 
Template
{
    var 
$tpl// code for file or filename template
    
var $cargo;
    
        
// initialize template
    
function Template()
    {
        
$this->tpl=array(); 
        
$this->cargo=array();
    }

    
// render template to the browser
    
function render_tpl()
    {
        
$this->parse_template();
    }

    
// render the template and return a string value
    
function render_tpl_to_string()
    {
        
$str='';
        if(
ob_start())
        {
            
$this->parse_template();
            
$str=ob_get_contents();
            
ob_end_clean();
        }
        return(
$str);
    }
    
    function 
load_tpl($filename="")
    {
        if(
$filename=="")
        {
            return(
0);
        }
        if(@
$fp=fopen($filename,'r'))
        {
            
$x=count($this->tpl);
            while(!
feof($fp))
            {
                
$this->tpl[$x].=fgets($fp,4096);
            }
            
fclose($fp);
        }
        else
        {
            echo 
'<h1>Could not open template "'.$filename.'"</h1>';
        }
    }

    function 
parse_template()
    {
        if(!
defined('_tpl_delim_left') || !defined('_tpl_delim_right')) return(0);
        
        for(
$y=0;isset($this->tpl[$y]);$y++)
        {
            
$x=strlen($this->tpl[$y]);
            for(
$pos=0;$pos<$x;$pos++)
            {
                
//check if we are at a delimiter and that it isn't escaped with a backslash
                
if($this->tpl[$y][$pos]==_tpl_delim_left && $this->tpl[$y][max($x-1,0)]!='\\')
                {
                    
$pos++;
                    
$var="";
                    while(
$this->tpl[$y][$pos]!=_tpl_delim_right && $pos<$x)
                    {
                        
$var.=$this->tpl[$y][$pos++];
                    }
                    
$var=explode('@',$var);
                    if(
$var[0]=='T' && method_exists($this,$var[1])) // builtins
                    
{
                        if(isset(
$var[2]))
                        {
                            
$this->{$var[1]}($var[2]);
                        }
                        else
                        {
                            
$this->{$var[1]}();
                        }
                    }
                    else if(isset(
$this->cargo[($var[0])])) 
                    {
                        if(
is_array($this->cargo[($var[0])]))
                        {
                            
display_array($this->cargo[($var[0])]);
                        }
                        else
                        {
                            echo 
$this->cargo[($var[0])];
                        }
                    }
                }
                else
                {
                    echo 
$this->tpl[$y][$pos];
                }
            }
        }
    }
    
    
    
/*********** built in display functions ***********/
    
    
function self()
    {
        echo 
$_SERVER['PHP_SELF'];
    }
    
    
// display an environment variable    
    
function env($var='')
    {
        if(
strlen($var)>0)
        {
            echo 
getenv($var);
        }
    }
}

/* extra functions */

// walk through an array to display all values
function display_array(&$var)
{
    if(
is_array($var))
    {
        
array_walk($var,'display_array');
    }
    else
    {
        echo 
$var;
    }
}
?>