Forum Moderators: coopster
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl")); Format of template.tpl file:
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{header}</h1>
{text}
</body>
</html> Setting variables:
$title="Example page";
$header="My Examples";
$text="See the placeholders replaced?"; If you're not comfortable with pulling variables out of the global scope, define them as
$values['title']=".."; etc., and use: print preg_replace("/\{([^\{]{1,100}?)\}/e","$values[$1]",file_get_contents("template.tpl"));
"/\{([^\{]{1,100}?)\}/e","$$1" The pattern looks for an opening curly-brace ( \{ ) - the end of the pattern is a closing curly-brace ( \} ).
In between the two braces I look for any character which isn't an opening curly-brace [^\{], avoiding mistaken nesting of tags.
I match between 1 and 100 of these non-{ characters by writing {1,100} and then I make the match non-greedy (try to find the shortest strings between { and }, not the longest) by adding a?. (? after *, + or {a,b} expressions changes them to non-greedy - in other situations? means 0 or 1 of the preceding).
The full string of non-{ characters is matched and stored as string $1 by surrounding that part of the pattern with brackets ().
Finally, the second argument of the preg_replace is "$$1", using variable variables. If the pattern encounters "{title}" then the matched string $1 is "title" and so $$1 is $title.
Multiple string replaces (more than three) tend to be faster done with preg_replace, fewer replaces are quicker with str_replace.
Or so the benchmarks I recall seemed to indicate.
So it all depends how many things you plan to have in your template.
EDIT:
And yes, looking back, I notice the "generic" factor is huge.
[edited by: Gibble at 7:50 pm (utc) on Sep. 11, 2007]
> why not use str_replace
The str_replace would probably be faster for some cases, although it would depend upon the number of tags to be replaced. On the positive side for the str_replace, it would be more secure if you didn't have control over your .tpl file.
One difference in end result is that with the preg_replace method, a tag enclosed in {} but not matched by a variable will be removed ("Hello {name}!" => "Hello!"), whereas the str_replace method would leave that unreplaced tag in place ("Hello {name}!" => "Hello {name}!")
EDIT: Figured it out.
function get_include_contents($filename) {
if (is_file($filename)) {
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
return false;
}
$text = get_include_contents(somefile.php);
1) Inside 'somefile.php', everywhere you see 'print' or 'echo' change it to '$text.=' - this will mean you can just do include('somefile.php'); and $text will be filled with the output:
print "Good morning $name"; ==> $text.= "Good morning $name"; 2) Use a http:// request to file_get_contents(). $text=file_get_contents("http://your.example.com/somefile.php"); - this runs it as a separate Apache instance and you get the full results to variable
Your solution is fine, apart from it being a whole extra function to define. Be careful though as your variable scope is still shared, e.g. if you set $a=7 in somefile.php, $a still equals 7 afterwards.
Dunno why I never brought it up here, good job vince!
<?php
class Template {
var $data = array();
function __construct($directory) {
$this->directory = $directory;
}
function set($key, $value = NULL) {
if (!is_array($key)) {
$this->data[$key] = $value;
} else {
$this->data = array_merge($this->data, $key);
}
}
function fetch($filename, $directory = DIR_TEMPLATE) {
$file = $directory . $this->directory . '/' . $filename;
if (file_exists($file)) {
extract($this->data);
ob_start();
include($file);
$content = ob_get_contents();
ob_end_clean();
return $content;
} else {
exit('Error: Template ' . $file . ' not found!');
}
}
}
?>
Ideally you'd be using it with a database, but you could also just go old-school and make your own pages manually in a couple of different ways.
eg. (building on vince's original example)
Format of template.tpl file:
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{header}</h1>
{text}
</body>
</html>
Your 'main' file, let's call it index.php:
<?php
// Figure out which page to load
$page = 'index';
if(!empty($_GET['page']) && ctype_alnum(trim($_GET['page'])))
$page = trim($_GET['page']);
// Get the variables for the page to be loaded
if($page == 'index')
{
$title = 'Index Title';
$header = 'The Great Header';
$text = '<p>all the page\'s text and info</p>';
}
elseif($page == 'about')
{
$title = 'About Us';
$header = 'Info About Us';
$text = '<p>We are the greatest, yada yada</p>';
}
else
{
$title = 'Error: Page Doesn\'t Exist';
$header = 'Sorry, the page you requested doesn\'t exist';
$text = '';
}
// Run the template engine
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl"));
?>
The first part checks if a page argument exists, and if it's in a valid alpha-numeric format to keep the hackers out.
The next bits define the variables for each page (including an error page which is displayed if the page argument is in a valid format but isn't actually a page), then you include the template and you're done!
You call the pages by going to:
example.com/index.php or example.com/index.php?page=index
example.com/index.php?page=about
The other way to do it is to put each page in it's own file:
index.php
<?php
$title = 'Index Title';
$header = 'The Great Header';
$text = '<p>all the page\'s text and info</p>';
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl"));
?>
<?php
$title = 'About Us';
$header = 'Info About Us';
$text = '<p>We are the greatest, yada yada</p>';
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl"));
?>
Then just load the pages as normal - example.com/index.php, example.com/about.php
HTH
[edited by: MattAU at 1:09 am (utc) on Sep. 14, 2007]
Heh, i don't quite understand the usefulness of templates in PHP.
One template, many pages of content. Similar deal to templates used by Dreamweaver etc. but done server-side. Keep your template free of PHP code and you can edit it by nad, or using Dreamweaver, Frontpage or Microsoft Word etc. Just put {} around the things you want to be dynamic (i.e. titles, text, menu,?).
Your PHP file can then be just about PHP code...
contact.php might be just:
$title="Contact us";
if (!$_POST) $text="<form ....> etc...";
else {
$text="Thanks for your contact";
mail("to@example.com","Contact",......);
}
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl"));
index.php might be just:
$title="Welcome to Widget Site";
$text="All about widgets ....";
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",file_get_contents("template.tpl")); i.e. every page should be setting $variables matching the {placeholders} you put into the HTML template file (named template.tpl in this example). At the bottom of the PHP file, you call the 'one line template engine' and the magic happens.
Front page thread? Wow!
Not that I don't see the use of creating your own templating system. My first 4 years of programming I spent re-inventing the wheel. That's how I cut my teeth. The last 3 years of programming I've spent trying to learn how to use the many wheels that came before me. And boy are there a lot of them. Just Zend, Pear, Cake, can fill your learning plate for months.
For those who are unfamiliar with the notion of templates (not a la dreamweaver) this page might be useful: [smarty.php.net...]
Significantly less elegant, and untested, alternate using MySQL for greater efficiency:
list($tpl) = mysql_fetch_row(mysql_query("SELECT tpl FROM templates WHERE page = '$self'",mysql_connect($dbh,$dbu,$dbp)));
print preg_replace("/\{([^\{]{1,100}?)\}/e","$$1",$tpl)); Non Swahili translation of greater efficiency: More pages served before you have to buy more hardware.
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<h1><?=$header?></h1>
<?=$text?>
</body>
</html>
Setting variables:
$title="Example page";
$header="My Examples";
$text="See the placeholders replaced?";
less code,less files,more understandable and quicker in execution. Or maybe I am missing the "point" of the using template in this particular example? :)
[edited by: JonB at 6:30 am (utc) on Sep. 14, 2007]