14

I'm searching for a very basic PHP templating system. Right now I'm using:

/**
 * Renders a single line. Looks for {{ var }}
 *
 * @param string $string
 * @param array $parameters
 *
 * @return string
 */
function renderString($string, array $parameters)
{
    $replacer = function ($match) use ($parameters)
    {
        return isset($parameters[$match[1]]) ? $parameters[$match[1]] : $match[0];
    };

    return preg_replace_callback('/{{\s*(.+?)\s*}}/', $replacer, $string);
}

(from here: PHP - Extremely light templating system)

but I can only assign and display variables. I also need a way to use conditions like IF and loop arrays.

I found Rain TPL - http://www.raintpl.com/Quick-Start/#if - which is very close to what I'm looking for, but there are a few things that I don't like it it:

  • it allows the dude who is writing the template to run PHP functions (inside the IF condition).
  • it writes cache and php files, which I don't want

So, is there anything out there similar to this, but even more "basic", strict, and more secure?

2
  • 1
    Perhaps you can elaborate why you don't want any caching? Your needs are a bit conflicting. Because you want if clauses and stuff, compiling is more or less the way to go, if you want to go fast. Twig as people suggested is a very good alternative for that. Commented Jun 5, 2011 at 20:28
  • For what reason do you want to throw away the speed advantages of caching? Commented Jun 12, 2011 at 9:16

7 Answers 7

15

Twig might be for you.

It can do conditions, and has a sandbox mode for untrusted code.

It does compilation and caching, but that seems to be possible to turn off.

Sign up to request clarification or add additional context in comments.

5 Comments

But in Twig being used eval.
@OZ_: If you turn caching off, yes. Do you have a problem with eval being used?
@nikic, read the title of the question. And I don't like eval too.
@OZ_ Twig has a sandboxed mode that does not allow arbitrary execution of code.
And even in non-sandboxed mode it allows only very limited actions. For example calling normal PHP functions is not possible in a standard configuration.
7
+250

There's also a Mustache port for PHP. The PHP port is here. The syntax is similar to what you're already doing, and supports simple IF and FOREACH-type loops.

And, does it without eval.

1 Comment

Can recommend Mustache, does the job might have sligh whitespace / newline issues but it's easy to deal with when running over.
5

Have a look at Twig or H2O.

Comments

4

From your requirements I am guessing you are wanting your website users to write some basic php scripts. You might not find a free template engine that does that.

I think it's better for you if you change an existing template engine to your needs.

You can change Rain TPL to disable some of its features that you don't want. For example you can do...

  1. Disable function use in IF statements:
    a. Locate elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){

    b. Replace $this->function_check( $tag ); with a new method something like $this->ifcondition_function_check( $tag );

    c. Create the new method that will disable all functions in IF statements.

    private function ifcondition_function_check($code)
    {
        $preg = '/[a-zA-z0-9]+\((.*?)\)/';
        if (preg_match( $preg, $code, $match ) ){
            // find the line of the error
            $line = 0;
            $rows=explode("\n",$this->tpl['source']);
            while( !strpos($rows[$line],$code) )
                    $line++;
    
            // draw the error line
            $error = str_replace( array('<','>'), array( '&lt;','&gt;' ), array($code,$rows[$line]) );
            $error = str_replace( $code, "<font color=red>$code</font>", $rows[$line] );
    
            // debug the error and stop the execution of the script
            die( "<div>RainTPL Sandbox Error in template <b>{$this->tpl['tpl_filename']}</b> at line $line : <i>$error</i></b>" );
        }
    }
    

    d. Now functions are disabled.

    1. Remove the cache file. (The cache file in Rain TPL is a PHP file with the template tags replaced by PHP code)
      a. Go to method draw()
      b. Locate unset( $this->tpl );
      c. Just before this line remove the complied (cache) file @unlink($this->tpl['compiled_filename']);.
      d. Now the cache file is just a temporary file to execute the PHP code.

Hope this helps

Comments

4

very easy to use

http://www.smarty.net/

2 Comments

I've got to give a +1 to Smarty templates. They provide various depths of functionality, but you can treat them very dumb and just use the basic templating needs. It supports conditions and looping and you can turn off caching.
There's a better, faster, more advanced, Smarty-compatible, modern alternative called Dwoo
3

When you want it really small and flexible maybe the best is to stay with your own stuff? I like handcrafting ;-) You can extend your existing function. Following, your function plus if and loop statement and escaping of variables for security:

<?php
function renderString($str, $parms)
{
    // if
    $str = preg_replace_callback('/{{if (?P<name>\w+)}}(?P<inner>.*?){{endif}}/is', function($match) use ($parms) {
        if( isset($parms[$match['name']])) {
            // recursive
            return renderString($match['inner'], $parms);
        }
    }, $str);
    // loop
    $str = preg_replace_callback('/{{loop (?P<name>\w+)}}(?P<inner>.*?){{endloop}}/is', function($match) use ($parms) {
        if( isset($parms[$match['name']]) && is_array($parms[$match['name']])) {
            $str = '';
            foreach ($parms[$match['name']] as $value) {
                $parms['loop'] = $value;
                // recursive
                $str .= renderString($match['inner'], $parms);
            }
            return $str;
        }
    }, $str);
    // var
    $str = preg_replace_callback('/{{(?P<name>\w+)}}/is', function($match) use ($parms) {
        if( isset($parms[$match['name']])) {
            return htmlspecialchars($parms[$match['name']]);
        }
    }, $str);
    return $str;
}

$template = "<h1>{{title}}</h1>

{{if optional}}
<p>Optional: {{optional}}</p>
{{endif}}

{{if noop}}I'm not there{{endif}}

<ul>
{{loop numbers}}
<li>{{symbol}} {{loop}}</li>
{{endloop}}
</ul>";

echo renderString($template, array(
    'title'    => 'The Title',
    'optional' => 'I am optional',
    'numbers'  => array( 'one', 'two', 'three'),
    'symbol'   => '>',
));

This script is tested in PHP 5.3 and you can copy it 1:1 to a file to play with it.

Comments

0

try PHPTAL: http://phptal.org/

the syntax for TAL templates does not break html, so you - and the designers can check if they going to look good.

see also:
http://wiki.zope.org/ZPT/TALSpecification14
http://wiki.zope.org/ZPT/TAL

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.