• Howdy! Welcome to our community of more than 130.000 members devoted to web hosting. This is a great place to get special offers from web hosts and post your own requests or ads. To start posting sign up here. Cheers! /Peo, FreeWebSpace.net
managed wordpress hosting

Template Engine

iBrightDev

Jay Street
NLC
NLC
OK, now i know i will receive some scrutiny from some people here for "re-inventing the wheel", and they will tell me to just use Smarty, but, I have developed this simple template engine for my own purposes and i would like to share it with others here. Smart is very nice, and i would recommend it to anyone, but, this is a lot more simple, and a lot less bulky than Smarty, and is all i need. Plus, it was a great learning experience for me, so, below you can see how i built this template engine, and see a working demo here...

http://www.mct-hosting.com/template/mct/

go ahead and switch the template from default to mctStyle, and vise versa. i will post the code for both.

index.php
PHP:
<?php #index.php

include ('../../admin/includes/phpconnect.php');
include('quicktemplate.php'); // Class definition

///////////////////// START, SWITCH THEME /////////////////////
// This will live in the admin panel once complete
if (isset($_POST['submitted'])) {

	// Find the name of the theme that you want to change to
	$getTheme = mysql_fetch_array(mysql_query("SELECT * FROM theme WHERE id=$_POST[newTheme] LIMIT 1"));
	// Change the old theme to not active
	$query = mysql_real_escape_string("UPDATE theme SET active=0 WHERE active=1 LIMIT 1");
	// Make the selected theme active
	$query2 = mysql_real_escape_string("UPDATE theme SET active=1 WHERE id=$_POST[newTheme] LIMIT 1");

	// If both themes have been switched, show successful message
	if(mysql_query($query) && mysql_query($query2)) {
		echo "Successfully changed layout to $getTheme[themeName]!";
		echo '<meta http-equiv="refresh" content="1;url='.$_SERVER['PHP_SELF'].'">';

	// If there was an error changing status for the themes, show an error
	} else {
		echo "<strong>Error!</strong> There was a problem changing the layout.";
		echo '<meta http-equiv="refresh" content="1;url='.$_SERVER['PHP_SELF'].'">';
		/*echo "<strong>Error!</strong> There was a problem changing the layout.<br/><br/>MySQL said:<br /><pre>";
		echo mysql_error();
		echo "\n</pre>The query used was:<pre>\n$query</pre>";*/
		die();
	
	}
	
} else {

// find the theme
$findTheme = "SELECT * FROM theme WHERE active=1"; 
$themeResult =  mysql_query ($findTheme);
$themeDefault = mysql_fetch_array ($themeResult, MYSQL_ASSOC);

$theme = 'theme/'.$themeDefault['themeName'].'/index.tpl';

//DELETE OR COMMENT OUT THE FOLLOWING STATEMENT BEFORE LAUNCH
//echo $theme."<br/><br/>\n";

echo "<form action=".$_SERVER['PHP_SELF']." method=\"post\">\n";
	$query1 = mysql_query("SELECT * FROM theme WHERE active=1");
	$rest = mysql_query("SELECT * FROM theme WHERE active=0");
	echo "<select name='newTheme'>
	<optgroup label=\"Current theme\">\n";
	while ($query = mysql_fetch_array($query1)) {
		echo "<option value='$query[id]'>$query[themeName]</option>\n";
	}
	echo "</optgroup>
	<optgroup label=\"Switch to...\">\n";
	while ($option = mysql_fetch_array($rest)) {
		echo "<option value='$option[id]'>$option[themeName]</option>\n";
	}
	echo "</optgroup>
	</select>
	<input type=\"submit\" value=\"Change Template\" name=\"update\" style=\"font-size:10px;\" />
	<input type=\"hidden\" name=\"submitted\" value=\"TRUE\" />
</form>\n";


} // End submitted check
///////////////////// END, SWITCH THEME /////////////////////

// Get the page title from the database for the array
$pT = mysql_fetch_array(mysql_query("SELECT title FROM pageTitle WHERE id=1"));

// Menu function
function menuLink() {

	$limit = mysql_fetch_array(mysql_query("SELECT limitNum FROM menuLimit WHERE id=1"));

	$sql =  "SELECT * FROM Menu ORDER BY id ASC LIMIT 0,$limit[limitNum]";
	$result = mysql_query($sql);
	
	while($menuLink = mysql_fetch_array($result)) {
		$html[] = '<li><a href="index.php?page='.$menuLink["l_name"].'"><strong>'.$menuLink["name"].'</strong></a></li>';
	}
	ob_start();
	for($n = 0; $n <= 7; $n ++) {
		echo $html[$n];
	}
	$data = ob_get_contents();
	ob_end_clean();
	return $data;
} // END menu function

// This is needed in case a link hasnt been selected
// This is for the default home page content
$query = "SELECT * FROM Menu WHERE id=1"; 
$result =  mysql_query ($query);
$row = mysql_fetch_array ($result, MYSQL_ASSOC); 

// This it the code needed for when a links is selected
$get =  mysql_query("SELECT * FROM `Menu` WHERE l_name='$_GET[page]'") OR DIE(mysql_error());
$page = mysql_fetch_assoc($get);

// If a link hasnt been selected yet, default to the home page name
if(empty($_GET['page']) || $page['name'] == NULL){
	$pageTitle = $row['name'];
} else { // If a link was selected, display the page title
	$pageTitle = $page['name'];
}

// If a link hasnt been selected yet, default to the home page content
if(empty($_GET['page']) || $page['content'] == NULL){
	$pageContent = $row['content'];
} else { // This will appear if a link has been selected
	$pageContent = $page['content'];
}

//Build array for Title, Menu, Page Header and Content
$temp_data = array('main' => array('file' => $theme),
				   'title' => array('content' => $pT['title']),
				   'leftnav' => array('content' => menuLink()),
				   'pagetitle' => array('content' => '<strong>'.$pageTitle.':</strong>'),
				   'pagetxt' => array('content' => $pageContent));

$engine = new quick_template($temp_data);
echo $engine -> parse_template();

?>

quicktemplate.php
PHP:
<? #quicktemplate.php

class quick_template {
	
	private $t_def;
	
	public function parse_template($subset = 'main') {
	
		$noparse = false;
		$content = "";
		$temp_file = $this->t_def[$subset]['file'];
		
		if(isset($temp_file)) {
			
			$fr = fopen($temp_file, "r");
			
			if(strlen($temp_file) > 6) {
				substr($temp_file, strlen($temp_file)-6);
			}
			
			if(strcasecmp($ext, ".tpl") != 0) {
				$noparse = true;
			}
			
			if(!$fr) {
				$content = "<!-- Error loading '$temp_file' //-->";
			} else {
				$content = fread($fr, filesize($temp_file));
			}
			
			@fclose($fr);
		
		} else {
		
			if(isset($this->t_def[$subset]['content'])) {
				$content = $this->t_def[$subset]['content'];
			} else {
				$content = "<!-- Content for '$subset' not defined //-->";
			}
			
		}
		
		if($noparse == true) {
		
			$content = preg_replace("/\%([A-Z]*)\%/e", "quick_template::parse_template(strtolower('$1'))", $content);

		}

		return $content;
	
	}
	
	function __construct($temp = '') {
		
		if(is_array($temp)) $this->t_def = $temp;
	
	}
}

?>

/theme/default/index.tpl
HTML:
<html>
<head><title>%TITLE%</title></head>
<style>
ul {margin: 0px; padding: 0px;}
li {display: block; margin: 0px; padding: 0px;}
</style>
<body>
<table border="0" cellpadding="0" cellspacing="0">
	<tr>
		<td colspan="2" valign="top">HEADER IMAGE HERE</td>
	</tr>
	<tr>
		<td valign="top" width="150">
			<ul>%LEFTNAV%</ul>
		</td>
		<td valign="top">
			%PAGETITLE%<br>
			%PAGETXT%
		</td>
	</tr>
	<tr>
		<td colspan="2" valign="top">Method Computer Technologies</td>
	</tr>
</table>
</body>
</html>

/theme/mctSkin/index.tpl
HTML:
<html>
<head><title>%TITLE%</title></head>
<style>
ul {margin: 0px; padding: 0px;}
li {display: inline; margin: 5px 10px 5px 0px; padding: 0px;}
</style>
<body>
<table border="0" cellpadding="0" cellspacing="0">
	<tr>
		<td valign="top">HEADER IMAGE HERE</td>
	</tr>
	<tr>
		<td valign="top">
			<ul>%LEFTNAV%</ul>
		</td>
	</tr>
	<tr>
		<td valign="top">
			%PAGETITLE%<br>
			%PAGETXT%
		</td>
	</tr>
	<tr>
		<td valign="top">Method Computer Technologies</td>
	</tr>
</table>
</body>
</html>

to make this all work, you will need a mysql database. here is mine.
Code:
--
-- Table structure for table `Menu`
--

CREATE TABLE `Menu` (
  `id` int(25) NOT NULL auto_increment,
  `display` int(10) NOT NULL default '0',
  `name` varchar(100) default NULL,
  `l_name` varchar(100) default NULL,
  `menuIcon` varchar(250) default NULL,
  `content` text,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

--
-- Dumping data for table `Menu`
--

INSERT INTO `Menu` VALUES(1, 1, 'Home', 'Home', 'http://www.mct-hosting.com/images/uploads/menuIcons/home.png', '<p><span class="main_txt_head">What we offer:</span><br />MCT-Hosting.com takes the uncertainty out of hosting, and puts service, performance and value back in. No matter which hosting type or plan you choose, your site will receive 24/7 maintenance and protection. You will recieve the expert and friendly service that you deserve, from MCT-Hosting.<br /><br /><span class="main_txt_head">Overview:</span><br />At MCT-Hosting.com, we develop, run, maintain and support our hosting plans 24/7. So for safe, reliable and affordable web site hosting, play it smart. Just scan through the individual plans and choose the one that's right for you! <br /><br /><span class="note_txt">Note: Each month of hosting is paid for in advance and begins upon the purchase of this account. Cancellation of your hosting account will discontinue all future billings. Hosting fees are non-refundable.</span></p>');
INSERT INTO `Menu` VALUES(2, 0, 'Hosting', 'Hosting', 'http://www.mct-hosting.com/images/uploads/menuIcons/hosting.png', 'Put hosting info here.');
INSERT INTO `Menu` VALUES(3, 0, 'Domains', 'Domains', 'http://www.mct-hosting.com/images/uploads/menuIcons/domain.png', '<p>Put domain info here.</p>');
INSERT INTO `Menu` VALUES(4, 0, 'Other Services', 'OtherServices', 'http://www.mct-hosting.com/images/uploads/menuIcons/services.png', 'Put other services stuff here');
INSERT INTO `Menu` VALUES(5, 0, 'F. A. Q.', 'FAQ', 'http://www.mct-hosting.com/images/uploads/menuIcons/faq.png', '<span class="main_txt_head">Frequently Asked Questions</span><br />There are many important things to consider when choosing a hosting provider. Blow you can get the answers to many of your questions. If you do not see an answer to a question you have, please, feel free to <a href="..//">contact</a> our support team. <br /><br /><span class="main_txt_head">You have questions, we have answers.</span> <ol><li><a href="index.php?page=FAQSupport">Support</a></li><li><a href="index.php?page=FAQE-Mail">E-mail</a></li></ol><p>&nbsp;</p>');
INSERT INTO `Menu` VALUES(6, 0, 'About Us', 'AboutUs', 'http://www.mct-hosting.com/images/uploads/menuIcons/about.png', 'Put &quot;about us&quot; info here');
INSERT INTO `Menu` VALUES(7, 0, 'Contact Us', 'ContactUs', 'http://www.mct-hosting.com/images/uploads/menuIcons/contact.png', '<table border="0" cellspacing="5" cellpadding="0"><tbody><tr><td rowspan="2"><img src="../images/uploads/contact.png" border="0" alt=" " width="47" height="42" /></td><td><strong>Office:</strong></td><td>(480) 656-9965</td></tr><tr><td><strong>Cell:</strong></td><td>(480) 233-5006</td></tr></tbody></table>');


-- --------------------------------------------------------

--
-- Table structure for table `menuLimit`
--

CREATE TABLE `menuLimit` (
  `id` int(25) NOT NULL auto_increment,
  `limitNum` int(10) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `menuLimit`
--

INSERT INTO `menuLimit` VALUES(1, 7);

-- --------------------------------------------------------

--
-- Table structure for table `pageTitle`
--

CREATE TABLE `pageTitle` (
  `id` int(25) NOT NULL auto_increment,
  `title` varchar(250) NOT NULL default '',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `pageTitle`
--

INSERT INTO `pageTitle` VALUES(1, 'Test Template Engine');

-- --------------------------------------------------------

--
-- Table structure for table `theme`
--

CREATE TABLE `theme` (
  `id` int(25) NOT NULL auto_increment,
  `themeName` varchar(200) default NULL,
  `active` int(10) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- Dumping data for table `theme`
--

INSERT INTO `theme` VALUES(1, 'default', 1);
INSERT INTO `theme` VALUES(2, 'mctSkin', 0);

if you decide to use this template engine, please put something in the footer giving Method Computer Technologies credit.
 
Last edited:
hmm, a interesting way of going about it:)

I *personally* wouldnt store the raw HTML in the database as it seems a little counter productive, but I really like the theme switcher, works nicely.
 
hmm, a interesting way of going about it:)

I *personally* wouldnt store the raw HTML in the database as it seems a little counter productive, but I really like the theme switcher, works nicely.

the raw html is generated by tinyMCE so that you can still go about using styles. only the admin of the site is able to input info in the database, so, not to worried about someone putting something that could be harmful. you can put simple text with no html in, or, build tables, divs, or pretty much anything else needed. it is also about to make link anchors work. so i get what you are saying, but, for what it is used for, it is nice to have the html there.
 
the raw html is generated by tinyMCE so that you can still go about using styles. only the admin of the site is able to input info in the database, so, not to worried about someone putting something that could be harmful. you can put simple text with no html in, or, build tables, divs, or pretty much anything else needed. it is also about to make link anchors work. so i get what you are saying, but, for what it is used for, it is nice to have the html there.


oh right:) in that case then good job all round!
 
thanks for the support Jonny`. you definitely did your part in helping me get the menu working properly. I really am surprised with how huge Smarty is, and the amount of files it requires to run. I was really determined to make something a hell of a lot more simple, and i think i have accomplished that with this script. there are only 4 things required for running this script. and index.php file, the quicktemplate.php file, a template, and a mysql database. so, Smarty is great and all, but, way more than i need, and probably a lot more than others need too IMO.

So, thanks again Jonny` and thanks to Carl for teaching me a lot of things over the past couple years. If it wasnt for people like Carl, i may have not been able to accomplish this task so easily. you have both shared a plethera of knowledge, and cant thank you enough.

Special thanks to KrakJoe for helping with multiple scripts over the past couple years. If it wasnt for me always trying to stive to get to his level of programming, i would have never been able to write this. you have ripped apart many things in the past, and really helped me grow. thanks Joe.

and last but not least, Colin and Trevor both deserve many thanks for things they have taught me. My books only could take me so far. they have both shown me things that are far more advanced than my books could have ever shown me.

so, to sum it all up, this script is free only because of those that have helped me. I feel i need to really share something that i feel is good. thanks you guys, this was possible because of you. BTW, my CMS will be launched soon, and i will be providing the source for free. this script will be incorporated in to it, along with many other cool features. yes, there are multiple cms systems out there, but, i am certain that the members here will find it more what they need over something like phpcoin or jamoola. thanks again guys.

@JohnN, thanks for the feedback
 
Ok, you asked me on IM about what you could do differently, well .... I dont just say you should use smarty, it's a fact, writing a template engine consists of a lot of code, hence the reason smarty is large, this makes no difference to load times, it compiles templates as php, so NO difference. I have no time today, however 20 minutes in and well ...

PHP:
<?php
/**
 * Dummy, a stupid template engine, never use, I'm proving a point....
 *
 */
class dummy
{
	public static $variables ;
	/**
	 * Set a template variable
	 *
	 * @param string $variable
	 * @param mixed $value
	 */
	function setVariable( $variable, $value )
	{
		$this->variables[ $variable ] = $value ;
	}
	/**
	 * Evaluate some php
	 *
	 * @param string $code
	 * @return string
	 * @access private
	 */
	protected function _eval( $code )
	{
		ob_start( );
		eval( $code );
		$code = ob_get_contents( );
		ob_end_clean( );
		return trim( $code ) ;
	}
	/**
	 * Parse a template
	 *
	 * @param string $raw
	 * @return string
	 */
	function parse( $raw )
	{
		if( strlen( $raw ) )
		{
			/** parse variable placements **/
			if( preg_match_all( '~\{\s?\$(.+[^\}])\s?\}~siU', $raw, $variables ) )
			{
				foreach( $variables[0] as $id => $find )
				{
					$search[ ] = $find ;
					$replace[ ] = $this->variables[$variables[1][$id]];	
				}
				$raw = str_replace( $search, $replace, $raw );
				unset( $search, $replace );
			}
			/** parse if conditions **/
			if( preg_match_all( '~\{\s?if\s?\$(.*[^\}])\\s?}(.+)\{\s?/if\\s?}~siU', $raw, $ifs ) )
			{
				foreach( $ifs[0] as $id => $find )
				{
					$search[ ] = $find ;
					$replace[ ] = $this->variables[$ifs[1][$id]] ? trim( $ifs[2][$id] ) : '' ;
				}
				$raw = str_replace( $search, $replace, $raw );
				unset( $search, $replace );
			}
			/** parse php code **/
			if( preg_match_all( '~\{\s?php\s?\}(.+){\s?\/php\s?}~siU', $raw, $php ) )
			{
				foreach( $php[0] as $id => $find )
				{
					$search[ ] = $find ;
					$replace[ ] = $this->_eval( $php[1][$id] );
				}
				$raw = str_replace( $search, $replace, $raw );
				unset( $search, $replace );
			}
			/** parse includes **/
			if( preg_match_all( "~\{\s?include\s(.+[^\}])\}~siU", $raw, $inc ) )
			{
				foreach( $inc[0] as $id => $include )
				{
					$search[ ] = $include ;
					$replace[ ] = $this->_include( $inc[1][$id], $include );
				}
				$raw = str_replace( $search, $replace, $raw );
				unset( $search, $replace );
			}
			/** return parsed content **/
			return $raw ;
		}
		else die( sprintf( "%s cannot read %s", __METHOD__, $file ) );
	}
	/**
	 * Include a template inside another template
	 *
	 * @param string $file
	 * @param string $code
	 * @return string
	 */
	protected function _include( $file, $code )
	{
		return $this->parse( str_replace( $code, "", @file_get_contents( $file ) ) );
	}
	/**
	 * Display a template file
	 *
	 * @param string $file
	 */
	function display( $file )
	{
		echo $this->parse( @file_get_contents( $file ) );
	}
}
/** initialize object of type dummy **/
$dummy = new dummy( );
/** set a template variable named title with the value "My Page Title" **/
$dummy->setVariable( 'title', "My Page Title" );
/** display a template named index.htpl **/
$dummy->display( 'index.htpl' );
?>

header.htpl

HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{$title}</title>
</head>

index.htpl

HTML:
<!-- We include a header -->
{include header.htpl}
<body>
<!-- a test condition -->
{if $title}
	The title of this page should be {$title}<br />
{/if}
<!-- some raw php -->
{php}
	echo "Hello World<br />\n";
{/php}
<!-- some conditioned php -->
{if $title}
	{php}
		for( $i = 0; $i < 10; $i++ )
		{
			echo "Another message depending on title and a for loop<Br />\n";
		}
	{/php}
{/if}
<!-- nothing, another condition -->
{if $none}
	I will not display
{/if}
<!-- embedded php -->
{php}
	echo "Next I will display: {$title}<br />\n";
{/php}
<!-- include footer -->
{include footer.htpl}

footer.htpl

HTML:
</body>
</html>

You should actually use smarty, it's not something "I say" ....
 
Last edited:
interesting code Joe. and i still am considering Smarty, just not sure i really want to use it. oh, and i just said you say to use Smarty, because i alwasy see you saying it to people. and yes, i agree that it is nice, just not what i need right now. :D
 
All web applications need to interact in some way with html, and so Smarty is actually what you need.

You could waste months trying to emulate what they have done, but there is no point, it's not a good use of time, nor a good use of ( your own ) software.

You're correct, smarty is large, however once you get to know smarty, you will see that all of it is useful, it gives the end users of your code far more control over the code you produce because all designers worth their salt have had experience with smarty, if the new designer has to learn a new template engine it will cost your end user more to utilize the code you produce. Plus often it puts less pressure on the framework you produce because Smarty functions can do a lot of the hard work that would normally call for messy hard to maintain code snippets.
 
mct - if it helps, after hearing what krak said I'm having a look at smarty now, it seems very logical and I really like it. I'm thinking that I'll probably go about building a framework around it. Its very powerful and saves a lot of work.

krak - thats some fantastic code you posted by the way, I learned quite a bit from that.
 
It wasn't supposed to be fantastic code, it was supposed to illustrate that even though it's possible to write your own template engine akin to smarty, it's a waste of time, because smarty has already been written and there really isn't anything that you might want to do with an html datasource that smarty cannot do, and do it better ... glad you learnt from it, but never use it ... please ....
 
yeah, i have smarty, and been looking at it for a couple weeks now, just thought it would be nice to make something myself. that was the main reason for making this. thanks for the feedback guys.
 
Back
Top