super-light templating system in PHP that doesn't allow php code inside templates or use eval
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?
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.
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.
Have a look at Twig or H2O.
- http://www.twig-project.org/
- http://www.h2o-template.org/
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...
Disable function use in IF statements:
a. Locateelseif( 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( '<','>' ), 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.
- 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 methoddraw()
b. Locateunset( $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.
- Remove the cache file. (The cache file in Rain TPL is a PHP file with the template tags replaced by PHP code)
Hope this helps
very easy to use
http://www.smarty.net/
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.
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
精彩评论