Using PHP as a template language

Edit: Great points around, a dedicated template language is obviously the way to go. Thank!

I wrote this quick class for creating templates via PHP - I was wondering if it is easy to use if I ever open templates for users (and not right away, but think about the road).

class Template {

private $allowed_methods = array(
    'if', 
    'switch', 
    'foreach',
    'for', 
    'while'
);

private function secure_code($template_code) {
    $php_section_pattern = '/\<\?(.*?)\?\>/';
    $php_method_pattern = '/([a-zA-Z0-9_]+)[\s]*\(/';
    preg_match_all($php_section_pattern, $template_code, $matches);
    foreach (array_unique($matches[1]) as $index => $code_chunk) {
        preg_match_all($php_method_pattern, $code_chunk, $sub_matches);
        $code_allowed = true;
        foreach ($sub_matches[1] as $method_name) {
            if (!in_array($method_name, $this->allowed_methods)) {
                $code_allowed = false;
                break;
            }
        }
        if (!$code_allowed) {
            $template_code = str_replace($matches[0][$index], '', $template_code);
        }
    }
    return $template_code;      
}

public function render($template_code, $params) {
    extract($params);
    ob_start();
    eval('?>'.$this->secure_code($template_code).'<?php ');
    $result = ob_get_contents();
    ob_end_clean();
    return $result;     
}

}

Usage example:

$template_code = '<?= $title ?><? foreach ($photos as $photo): ?><img src="<?= $photo ?>"><? endforeach ?>';
$params = array('title' => 'My Title', 'photos' => array('img1.jpg', 'img2.jpg'));
$template = new Template;
echo $template->render($template_code, $params);

The idea here is that I would store the templates (PHP code) in the database and then run it through a class that uses regular expressions to allow allowed methods (if, for, etc.). Does anyone see an obvious way to use this and run arbitrary PHP? If so, I will probably move on to more standard template language routes such as Smarty ...

+3
5

..

$template_code = '<?= `rm -rf *`; ?>';

Edit:

. , . IF- Template.

, render('<?php $this->allowed_methods[] = "eval"; ?>').. Template eval .;)

+4

. , , , . , , , Smarty, . PHP , , . , , , , .

+4

{} .

$template_code = '<?php $f = "phpinfo"; ${"f"}(); ?>';

, , , . global - , $_SESSION ( , javascript ajax ).

$a = "hello";
$template_code = '<?php global $a; $a = "test"; ?>';
$params = array('title' => 'My Title', 'photos' => array('img1.jpg', 'img2.jpg'));
$template = new Template;
echo $template->render($template_code, $params);
echo $a;

, , , , .

$template_code = '<?php $if="phpinfo"; $if(); ?>';
+3

, , ?

<?php
/* ?> trick your parser by using a comment */
// do whatever unfiltered

- , . . , !

+1

, , , .

For example, consider the Markdown formatting allowed by Stack Overflow. It supports a very short list of formatting options, and everything else is considered a literal. Most users are happier with a simple interface rather than with an interface that says "Write any code you want! But be careful not to break the application!"

My rule: allows users to enter data and content; never let users enter code.

+1
source

Source: https://habr.com/ru/post/1744089/


All Articles