PHP 中的超轻型模板系统,不允许在模板内使用 php 代码或使用 eval

发布于 2024-11-02 19:34:50 字数 933 浏览 5 评论 0原文

我正在寻找一个非常基本的 PHP 模板系统。现在我正在使用:(

/**
 * 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);
}

从这里:PHP - 极轻模板系统

但我只能分配和显示变量。我还需要一种使用 IF 和循环数组等条件的方法。

我找到了 Rain TPL - http://www.raintpl.com/Quick-Start/#if - 这与我正在寻找的非常接近,但有一些我不喜欢它的地方:

  • 它允许编写模板的人运行 PHP 函数(在 IF 条件内) )。
  • 它写入缓存和 php 文件,这是我不想要的

那么,有没有类似的东西,但更“基本”,严格,更安全?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

小猫一只 2024-11-09 19:34:50

Twig 可能适合您。

它可以执行条件操作,并且具有针对不受信任代码的沙箱模式。

它进行编译和缓存,但这似乎可以关闭。

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.

笔芯 2024-11-09 19:34:50

还有一个用于 PHP 的 Mustache 端口。 PHP 端口在这里。该语法与您已经执行的操作类似,并且支持简单的 IF 和 FOREACH 类型循环。

并且,无需评估即可完成。

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.

你对谁都笑 2024-11-09 19:34:50

根据您的要求,我猜测您希望网站用户编写一些基本的 php 脚本。您可能找不到可以做到这一点的免费模板引擎。

我认为如果您根据需要更改现有的模板引擎,这对您来说会更好。

您可以更改 Rain TPL 以禁用某些您不需要的功能。例如,您可以执行...

  1. 禁用 IF 语句中的函数使用:
    一个。找到 elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){

    b.将 $this->function_check( $tag ); 替换为新方法,例如 $this->ifcondition_function_check( $tag );

    c.创建将禁用 IF 语句中所有函数的新方法。

    私有函数 ifcondition_function_check($code)
    {
        $preg = '/[a-zA-z0-9]+\((.*?)\)/';
        if (preg_match( $preg, $code, $match ) ){
            // 找到出错的行
            $行= 0;
            $rows=explode("\n",$this->tpl['source']);
            while( !strpos($rows[$line],$code) )
                    $行++;
    
            // 绘制误差线
            $error = str_replace( array('<','>'), array( '<','>' ), array($code,$rows[$line]) );
            $error = str_replace( $code, "$code", $rows[$line] );
    
            // 调试错误并停止脚本的执行
            die( "
    RainTPL Sandbox 模板中出现错误 {$this->tpl['tpl_filename']} 在 $line 行:$error< ;/b>" ); } }

    d.现在功能已禁用。

    1. 删除缓存文件。 (Rain TPL中的缓存文件是一个PHP文件,其中模板标签被PHP代码替换)
      一个。转到方法 draw()
      b.找到 unset( $this->tpl );
      c.在此行之前删除已编译(缓存)文件@unlink($this->tpl['compiled_filename']);
      d.现在缓存文件只是执行 PHP 代码的临时文件。

希望这有帮助

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( '<','>' ), 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

御弟哥哥 2024-11-09 19:34:50

当您想要它非常小且灵活时,也许最好的方法就是保留您自己的东西?我喜欢手工制作;-) 您可以扩展您现有的功能。接下来,您的函数加上 ifloop 语句以及出于安全考虑的变量转义:

<?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'   => '>',
));

此脚本在 PHP 5.3 中进行了测试,您可以将其 1:1 复制到文件中进行播放与它。

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.

南风起 2024-11-09 19:34:50

尝试 PHPTAL: http://phptal.org/

TAL 模板的语法不会破坏 html,因此您 - 并且设计师可以检查它们是否看起来不错。

另请参阅:
http://wiki.zope.org/ZPT/TALSpecification14
http://wiki.zope.org/ZPT/TAL

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文