在分析输入文件时删除eval()以保护代码段


Securing snippet with dropping eval() in input-file parsing

我有一个模板式系统,可以加载批量模板(一个文件中有多个模板条目)并相应地存储它们。问题是当前的方法使用preg_replace()eval,并且它确实容易出错。这个错误的一个例子可能是一个放置不正确的字符,它破坏了正则表达式并创建了一个解析错误:

Parse error: syntax error, unexpected '<' in tsys.php: eval()'d code

完成上述加载的代码如下:

// Escaping
$this->_buffer = str_replace( array('''', '''', "'n"), array('''''', '''''', ''), $this->_buffer);
// Regular-expression chunk up the input string to evaluative code
$this->_buffer = preg_replace('#<!--- BEGIN (.*?) -->(.*?)<!--- END (.*?) -->#', "'n" . '$this->_tstack[''''1''] = ''''2'';', $this->_buffer);
// Run the previously created PHP code
eval($this->_buffer);

批量模板的示例文件如下所示:

<!--- BEGIN foo -->
<p>Some HTML code</p>
<!--- END foo -->
<!--- BEGIN bar -->
<h1>Some other HTML code</h1>
<!--- END bar -->

当代码在此输入上运行时,$this->_tstack将被赋予两个元素:

array (
  'foo' => "<p>Some HTML code</p>",
  'bar' => "<h1>Some other HTML code</h1>",
);

这是预期的行为,但我正在寻找一种方法,我们可以放弃对eval的需求。

好吧,开始吧。给定$template包含:

<!--- BEGIN foo -->
    <p>Some HTML code</p>
<!--- END foo -->
<!--- BEGIN bar -->
    <h1>Some other HTML code</h1>
<!--- END bar -->

然后:

$values = array();
$pattern = '#<!--- BEGIN (?P<key>'S+) -->(?P<value>.+?)<!--- END (?P=key) -->#si';
if ( preg_match_all($pattern, $template, $matches, PREG_SET_ORDER) ) {
    foreach ($matches as $match) {
        $values[$match['key']] = trim($match['value']);
    }
}
var_dump($values);

结果:

array(2) {
  ["foo"]=>
  string(21) "<p>Some HTML code</p>"
  ["bar"]=>
  string(29) "<h1>Some other HTML code</h1>"
}

如果保留空白很重要,请删除trim()

您可以使用preg_match_all来实现这一点:

// Remove CR and NL
$buffer = str_replace(array("'r", "'n"), '', $this->_buffer);
// Grab interesting parts
$matches = array();
preg_match_all('/'?'?'? BOT (?P<group>[^ ]+) '?'?'?(?P<content>.*)!!! EOT '1 !!!/', $buffer, $matches);
// Build the stack
$stack = array_combine(array_values($matches['group']), array_values($matches['content']));

将输出:

Array
(
    [foo] => <p>Some HTML code</p>
    [bar] => <h1>Some other HTML code</h1>
)