TL Tech Logo
We Solve Your Problems. Seriously, we actually do.
Home
About Us
Services
Stories
Contact Us
Tools
Info Center
  • Sections

    • Code
    • Howto
    • Tips
  • Recent Entries

    • Recovering from a Broken Partition Table
    • RewriteRule in htaccess vs httpd.conf
    • Running PHP through mod_fcgid
    • How They Got Your Password
    • Installing mod_reqtimeout on cPanel
    • Following the Hacker — passwords
    • Using Nginx as a reverse-proxy
    • Dead-simple templates in PHP
    • Tell-a-friend SPAM
    • PHP mail via SMTP

Dead-simple templates in PHP

I cringe every time a client starts a call with: “So, we decided to write our own in-house CMS.” Building a CMS is easy; building one correctly is hard.

First of all, if WordPress will do what you’re looking for, the don’t re-invent the wheel. It’s a decent piece of software, it’s well-supported, and as long as you avoid third-party plugins and pay attention to updates, it’s reasonably secure.

However, often what the client is really looking for is just a simple master template inclusion system. Often what they end up with is a mess of good intentions, RewriteRules, and somewhere something that looks like this:

    <? include($BASEDIR . "/" . $_GET['page'] . ".php");?>

Without going into how terrible an idea this is, allow me to introduce an alternative. It’s simple, it’s intuitive, and it’s easier to work with than whatever mess you narrowly avoided making.

We start out with the pages themselves. They look pretty simple. The important bits are the require bit at the top, any page-specific variables you’d like to set, and then all the HTML content you want to have in the page.

    <? require_once("/var/www/lib/template.php")?>
    <?
        $TITLE = "My Page";
        $DESC  = "A simple page about nothing";
    ?>

    <h1>Hello world</h1>
    <p>Pages are easy!</p>

Next let’s write up that template.php file. It’s where the magic happens. I’d recommend putting this file outside your document root. Same goes for your template files and any other files that shouldn’t be browsed directly.

    <? 
    function __template_shutdown_function_1() {
        global $TEMPLATE;
        if (empty($TEMPLATE)) $TEMPLATE="main.tpl.php";
        $CONTENT = ob_get_clean();
        $TEMPLATE_DIR=realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
        require($TEMPLATE_DIR.$TEMPLATE);
    }
    register_shutdown_function('__template_shutdown_function_1');
    ob_start();

See what we did there? That was clever. We call ob_start() and register a shutdown function that calls ob_get_clean() and then includes our master template. So when the template gets included, the output of the page file will end up in the $CONTENT variable.

We’re calling the main templage main.tpl.php and sticking it in the same folder as template.php, but that’s totally up to you. Also note that we allow the page to specify an alternate template file by setting a variable called $TEMPLATE. Cool. Note that we’re relying on $TEMPLATE to be empty if not explicitly set in your code, so if you have register_globals turned on (and you shouldn’t), this can seriously bite you.

Finally, note the lack of any closing ?> tag. This should be reasonably obvious, but if your file doesn’t contain any output, then don’t include the closing tag so you don’t accidentally output something.

OK, so let’s look at this template file.

    <?
        if (empty($TITLE)) $TITLE="My Site";
        if (empty($DESC)) $DESC="";
    ?><!doctype html>
    <html>
      <head>
        <title><?= $TITLE ?></title>
        <meta name="description" content="<?= $DESC ?>"/>
      </head>
      <body style="background:black;color:green;">
        <?= $CONTENT ?>
      </body>
    </html>

“Wait,” you say, “Is it really that easy?”

Yup. That’s all there is to it. Just plunk that one single include at the top of your pages, and all the styling will be handled by your template file. Most importantly, there’s no need to split up the header and footer, or include the content indirectly from the template, any of those shenanigans.

If you want to specify multiple text blocks in your page file, it’s pretty simple since ob_start() can be nested. Like so:

    <? require_once("/var/www/lib/template.php") ?>
    <? $TITLE="Page Two"; ?>

    <h1>Second Page</h1>
    <p>Now with a sidebar!</p>


    <?  ob_start(); ################# BEGIN SIDEBAR ### ?>
    <ul>
     <li>First</li>
     <li>Second</li>
     <li>Etc</li>
    </ul>
    <? $SIDEBAR = ob_get_clean(); ##### END SIDEBAR ### ?>

See there? Now you have this nifty $SIDEBAR variable with content you can insert elsewhere in your template. And best of all, you didn’t have to compose it as a PHP string.

If all you’re looking for is a simple way to keep a consistent style on all of your pages, then it doesn’t get any easier than this. The more code you have, the greater your chances of a security exploit. So do yourself a favor and use the simplest solution available to you.

© 2006-2014 TL Tech Services LLC. All rights reserved. Contact us to inquire about republishing rights.