Introduction

This tutorial extends on the previous tutorial of the Fully Functional Simple Template Engine. There would be some functions edited and I would finally provide you with the caching capabilities here.

Before I start on this, let me confess... the caching class I'm about to unleash is not written by me... I found it somewhere here on OZZU and assumed it was ok for me to use... since it works just like I need it to, I didn't find any need to recode myself another one, even though I could (I promise... I really can 🤣 )

This tutorial is not, by any means, the last tutorial based on this Fully Functional Simple Template Engine... when I make enough edits to the class to fill up a big page with edits and if it teaches you with something... then I'll post another one here... but it could be the last 🤣

Added

Let's start by adding some more functions here: The function is called include_file.

<?php
function include_file($file)
{

}
?>

The reason for it being is that sometimes you want to put in a filename to be set to a variable, but you don't want to actually include the contents of it into the template... so I made a simple solution here... for every file that you DON'T want to include into the file, just add a '' in front of it... the '' is perfect because it isn't allowed in the filename to be set when you create a file and it lets us create this functionality 🙂

<?php
function include_file($file)
{
    // Taking the first character from the filename
    $find = substr($file, 0, 1);

    // Checking if * exists in $filename
    if($find != '*')
    {
        return true;
    }
    return false;
}
?>

What this function does is check the very first character of the filename provided for '*'. If you don't like this method, you can substitute the function with the following.

<?php
function include_file($file)
{
    // Checking if * exists in $filename
    if(strpos($file, '*') != false)
    {
        return true;
    }
    return false;
}
?>

That way is using a smaller amount of code, but this time, you can put the asterisk '*' anywhere in the filename... it's not limited to being at the front.

The next function is what I named to be unclude_file. It generally does what the above function does, but it also removes the asterisk for sanitation.

<?php
function unclude_file($file, $perform = false)
{
    // Checking if the file was passed as an un-includeable
    if($this->include_file($file) === false)
    {
        // Checking if we should actually remove the first character (It being the '*')
        if($perform == true)
        {
            // Counting the number of letters $file consists of
            $ltrs = strlen($file);

            // Returning the trimmed $file
            return substr($file, 1, $ltrs);
        }
        return true;
    }
    return false;
}
?>

I guess you could put all of this into one function if I really think about it, but I'll break it up into to... why? Because I'm too lazy to edit this tutorial to accommodate the change 🙄 🤣

Also, I add a variable to the whole class called include_files. It holds true if you want the files that are passed into the variable def. to be included into the template (As in their contents) or not included into the templates (Only the file names would be included... not the source).

<?php
class tpl {

    // Various variables used throughout the class
    public $vari, $template, $page, $vstart, $vend, $include_files;

}
?>

The variables in blue is what I just put into there to make it more correct (?). I set them in the function start and use them in a few functions... in the class

Edited

Right, I said I edited some functions, so let's get on it 🙂

The first function I edited was the svariable to accommodate the include_file() function and the unclude_file() function. Here it is in it's full glory 😁

<?php
function svariable($return = false)
{
    // Converting set variables to the text defined in the parent PHP file
    foreach($this->vari as $key => $value)
    {
        // Checking if the value is a file and if it exists if it is a file
        if(is_file($value) && file_exists($value))
        {
            if($this->include_files === true  && ($this->include_file($value) === true))
            {
                // Getting the contents of the file
                $value = file_get_contents($value);

                // Replacing the KEY variable with the contents of the file
                $this->text = str_replace($this->vstart . $key . $this->vend, $value, $this->text);
            }
            else
            {
                // Replacing the KEY variable with the value
                $this->text = str_replace($this->vstart . $key . $this->vend, $value,$this->text);
            }
        }
        else
        {
            if($this->unclude_file($value) === true)
            {
                $value = $this->unclude_file($value, true);
            }

            // Replacing the KEY variable with the value
            $this->text = str_replace($this->vstart . $key . $this->vend, $value,$this->text);
        }
    }

    // Checking if we need to return the result
    if($return)
    {
        return $this->text;
    }
}
?>

That is it for this one 🙂

The cache

Alright, since I took this class from someone on this forum, I'll just post the whole entire class here (Without coloring it red... I have to color every line separately... ).

What it does though, is creates a file with the variables NOT replaced... it includes all the files first and then caches it. The id (or the name it would be saved on) is the file name... so if you are using a template more then once on different PHP files... don't cache it 😁 Otherwise it will mess you up.

<?php
class fcache {
    var $name = NULL; // private members only >= PHP 5
    var $value = array();
    var $ttl;

    function __construct($name, $ttl = 3600) { // Default $ttl is 3600 (60 minutes until expiry)
        $this->name = $name;
        $this->ttl = $ttl;
    }

    function check() {
        $cached = false;
        $file_name = './cache/' . $this->name . ".cache";
        if(file_exists($file_name))
        {
            $modified = filemtime($file_name);
            if(time() - $this->ttl < $modified)
            {
                $fp = fopen($file_name, "rt");
                if($fp)
                {
                    $temp_value = fread($fp, filesize($file_name));
                    fclose($fp);
                    $this->value = unserialize($temp_value);
                    $cached = true;
                }
            }
            else
            {
                $this->del_value($this->name);
                $this->set_value($this->name, $this->value);
                $this->save();
            }
        }
        return $cached;
    }

    function save() {
        $file_name = './cache/' . $this->name . ".cache";
        $fp = fopen($file_name, "wt");
        if($fp)
        {
            fwrite($fp, serialize($this->value));
            fclose($fp);
        }
    }

    function set_value($key, $value) {
        $this->value[$key] = $value;
    }

    function get_value($key) {
        if(isset($this->value[$key]))
        {
            return $this->value[$key];
        }
        else
        {
            return null;
        }
    }

    function del_value($key)
    {
        $file_name = './cache/' . $this->name . ".cache";
        if(file_exists($file_name))
        {
            unset($this->value[$key]);
            return unlink($file_name);
        }
        return false;
    }
}
?>

Now we have to put that into our gentemp.

<?php
function gentemp($cache = false, $return = false)
{
    // Converting simple function variables to function
    $this->sfvariable();

    // Checking if the page needs to be cached... if so, cache it.
    if($cache)
    {
        // Setting the cache class object
        $cache = new fcache($this->page);

        // Checking if the cache is available for the current page
        if($cache->check())
        {
            // Retrieving the cached contents of the page
            $this->text = $cache->get_value($this->page);
        }
        else
        {
            // Setting the cache with the contents of the current page
            $cache->set_value($cache->name, $this->text);

            // Saving the cache
            $cache->save();

            // Retrieving the cached contents of the page
            $this->text = $cache->get_value($this->page);
        }
    }

    // Converting simple variables to variables
    $this->svariable();

    // Checking if we need to echo or return the page
    if($return)
    {
        // Returning the page
        return $this->text;
    }
    else
    {
        // Echoing the page
        echo $this->text;
    }
}
?>

Example usage

Now, an example use of this whole thing would be:

process.php

<?php
require('includes/globals.php');

$db->connect();
$db->last_sql = $db->build_query(array('*', 'forum_a'));
$result = $db->last_sql_data(false, 'SQL Results Data', true);
$db->close();

$tpl->template = 'default';
$tpl->page = 'index';
$tpl->start();

include('includes/global_vars.php');

$tpl->vari = array_merge($tpl->vari, array(
    'SQL_QUERY' => $result,
    'MEMBER_STUFF' => ((isset($_SESSION['uid'])) ? 'members.html' : 'non_members.html'),
    'USERNAME' => $username,
    'LAST_VISIT' => date(MM/DD/YYYY hh:mm:ss, $last_visit) 
    'NOW_DATE' => date(MM/DD/YYYY hh:mm:ss)
));

$tpl->gentemp(true);
?>

That true in the gentemp( in the piece of code above tells the code to cache it as well.

And the template file could look like

<!-- INCLUDE header.html -->
<div id="content">
     <h6 id="header">Welcome {USERNAME} your last visit was {LAST_VISIT} from today ({NOW)DATE})</h6>
     <p>{MEMBER_STUFF}</p>
     <p>{SQL_QUERY}</p>
</div>
<!-- INCLUDE footer.html -->

Hope that made sense 😁

Conclusion

Well, this is it for now. Hope you enjoyed it and would find a good use for it 😁

cache.php

<?php

class fcache {
    var $name = NULL; // private members only >= PHP 5
    var $value = array();
    var $ttl;

    function __construct($name, $ttl = 3600) { // Default $ttl is 3600 (60 minutes until expiry)
        $this->name = $name;
        $this->ttl = $ttl;
    }

    function check() {
        $cached = false;
        $file_name = './cache/' . $this->name . ".cache";
        if(file_exists($file_name))
        {
            $modified = filemtime($file_name);
            if(time() - $this->ttl < $modified)
            {
                $fp = fopen($file_name, "rt");
                if($fp)
                {
                    $temp_value = fread($fp, filesize($file_name));
                    fclose($fp);
                    $this->value = unserialize($temp_value);
                    $cached = true;
                }
            }
            else
            {
                $this->del_value($this->name);
                $this->set_value($this->name, $this->value);
                $this->save();
            }
        }
        return $cached;
    }

    function save() {
        $file_name = './cache/' . $this->name . ".cache";
        $fp = fopen($file_name, "wt");
        if($fp)
        {
            fwrite($fp, serialize($this->value));
            fclose($fp);
        }
    }

    function set_value($key, $value) {
        $this->value[$key] = $value;
    }

    function get_value($key) {
        if(isset($this->value[$key]))
        {
            return $this->value[$key];
        }
        else
        {
            return null;
        }
    }

    function del_value($key)
    {
        $file_name = './cache/' . $this->name . ".cache";
        if(file_exists($file_name))
        {
            unset($this->value[$key]);
            return unlink($file_name);
        }
        return false;
    }
}

?>

templates.php

<?php
/* (class) templates.php
 *      Class defining the templating engine used throughout the site.
 *
 */

class tpl {

    // Various variables used throughout the class
    public $vari, $template, $page, $vstart, $vend, $include_files;

    // The directory where the template is located
    var $dir = 'templates';

    // The extension of the template files
    var $ext = 'html';

    /*
     * FUNCTION start( void )
     *      Starts template processing... must be called AFTER $tamplate and $page has being defined.
     */

    function start()
    {
        // Storing the contents of the template file into the $this->text variable
        $this->text = @file_get_contents($this->dir . '/' . $this->template . '/' . $this->page . '.' . $this->ext);

        // Defining certain configurable variables used in the template class
        $this->vstart = '{';        // Variable replacement start delimiter
        $this->vend = '}';          // Variable replacement end delimiter
        $this->include_files = true;
    }

    /*
     * function set_var($key, $value)
     *      @string $key - The name of the variable that would be replaced in the template file
     *      @string $value - The value that would replace the key ($key)
     * 
     * To be used when setting one variable
     */

    function set_var($key, $value)
    {
        $this->vari[$key] = $value;
    }

    /*
     * FUNCTION svariable ( void )
     *      Converts simple variables to defined text... defined in $vari
     */

    function svariable($return = false)
    {
        // Converting set variables to the text defined in the parent PHP file
        foreach($this->vari as $key => $value)
        {
            // Checking if the value is a file and if it exists if it is a file
            if(is_file($value) && file_exists($value))
            {
                if($this->include_files === true  && ($this->include_file($value) === true))
                {
                    // Getting the contents of the file
                    $value = file_get_contents($value);

                    // Replacing the KEY variable with the contents of the file
                    $this->text = str_replace($this->vstart . $key . $this->vend, $value, $this->text);
                }
                else
                {
                    // Replacing the KEY variable with the value
                    $this->text = str_replace($this->vstart . $key . $this->vend, $value,$this->text);
                }
            }
            else
            {
                if($this->unclude_file($value) === true)
                {
                    $value = $this->unclude_file($value, true);
                }

                // Replacing the KEY variable with the value
                $this->text = str_replace($this->vstart . $key . $this->vend, $value,$this->text);
            }
        }

        // Checking if we need to return the result
        if($return)
        {
            return $this->text;
        }
    }

    /*
     * FUNCTION sfvariable ( void )
     *      Converts simple function variables to functions... defined in the HTML template file
     */

    function sfvariable($return = false)
    {
        // Converting simple functions variables to their PHP equivalents
        $this->text = preg_replace("/\<\!-- INCLUDE (.+?) --\>/e", "@file_get_contents('templates/{$this->template}/\1')", $this->text);

        // Checking if we need to return the result
        if($return)
        {
            return $this->text;
        }
    }

    /*
     * FUNCTION include_file( string $file)
     *      @string $file - The filename you want to check if it needs to be included.
     * 
     * Checks if a file needs to be included. If it doens't need inclusion, than it would
     *  have * in front.
     */

    function include_file($file)
    {
        // Taking the first character from the filename
        $find = substr($file, 0, 1);

        // Checking if * exists in $filename
        if($find != '*')
        {
            return true;
        }
        return false;
    }

    /*
     * FUNCTION unclude_file( string $file [, bool $perform])
     *      @string $file - The filename to remove the first * from.
     *      @boolean $perform - If we should actually remove the * from
     *          the $file or if we should just check if the * exists in
     *          there.
     * 
     * A function that checks for the * in a filename and removes the first one.
     */

    function unclude_file($file, $perform = false)
    {
        // Checking if the file was passed as an un-includeable
        if($this->include_file($file) === false)
        {
            // Checking if we should actually remove the first character (It being the '*')
            if($perform == true)
            {
                // Counting the number of letters $file consists of
                $ltrs = strlen($file);

                // Returning the trimmed $file
                return substr($file, 1, $ltrs);
            }
            return true;
        }
        return false;
    }

    /*
     * FUNCTION gentemp (  [ bool $cached [, bool $return]]  )
     *      @boolean $cached (Default: false) if set to true, would cache the template file before parsing the file.
     *      @boolean $return (Default: false) if set to true, the output would be returned rather then echoed.
     *      Completes the generation of the template into HTML and spits it out
     */

    function gentemp($cache = false, $return = false)
    {
        // Converting simple function variables to function
        $this->sfvariable();

        // Checking if the page needs to be cached... if so, cache it.
        if($cache)
        {
            // Setting the cache class object
            $cache = new fcache($this->page);

            // Checking if the cache is available for the current page
            if($cache->check())
            {
                // Retrieving the cached contents of the page
                $this->text = $cache->get_value($this->page);
            }
            else
            {
                // Setting the cache with the contents of the current page
                $cache->set_value($cache->name, $this->text);

                // Saving the cache
                $cache->save();

                // Retrieving the cached contents of the page
                $this->text = $cache->get_value($this->page);
            }
        }

        // Converting simple variables to variables
        $this->svariable();

        // Checking if we need to echo or return the page
        if($return)
        {
            // Returning the page
            return $this->text;
        }
        else
        {
            // Echoing the page
            echo $this->text;
        }
    }

    /*
     * function list_styles( void )
     * 
     * Function that lists all of the available styles in the templates directory
     */

    function list_styles($array = false)
    {
        // Checking if the result should be an array or a SELECT form element
        if(!$array)
        {
            // Starting the SELECT form element
            $result = "<select name=\"style\">\n";

            // Iterating through the ./templates directory looking for directories in there
            foreach(new DirectoryIterator('./templates/') as $file)
            {
                // Making sure that we got a directory that is not the current page (would never be the case but, better be safe)
                if ((!$file->isDot()) && ($file->getFilename() != basename($_SERVER['PHP_SELF'])))
                {
                    // Making sure that the current file the pointer is on is actually a directory
                    if($file->isDir())
                    {
                        // Setting the options tag to the form element
                        $result .= "<option value=\"{$file->getFilename()}\">{$file->getFilename()}</option>\n";
                    }
                }
            }

            // Finishing the SELECT form element
            $result .= "</select>\n";
        }
        else
        {
            // Iterating through the ./templates directory looking for directories in there
            foreach(new DirectoryIterator('./templates/') as $file)
            {
                // Making sure that we got a directory that is not the current page (would never be the case but, better be safe)
                if ((!$file->isDot()) && ($file->getFilename() != basename($_SERVER['PHP_SELF'])))
                {
                    // Making sure that the current file the pointer is on is actually a directory
                    if($file->isDir())
                    {
                        // Creating the array
                        $result[] = $file->getFilename();
                    }
                }
            }
        }

        // Returning the result
        return $result;
    }
}
?>

This page was published on It was last revised on

Contributing Authors

0

2 Comments

  • Votes
  • Oldest
  • Latest
BO
441 9
Commented
Updated

The usage tutorial has being Created. Check it out to find out the usability of the class. I hope I was descriptive in it... if I wasn't, feel free to reply to the usage tutorial with any questions you may have.

add a comment
0
BO
441 9
Commented
Updated

An even simpler template class was created by Rabid Dog

add a comment
0