preg_replace& preg_replace_callback安全问题

时间:2011-10-18 22:15:33

标签: php security preg-replace preg-replace-callback

好的,我知道这是一个不好的做法,但部分代码是存在的,我必须扩展它以使用一个参数运行自定义函数。

因此,我们的页面存储在数据库中,当它们显示在我们的模板中时,我们目前在整个html页面上使用三个不同的preg_replace函数和e修饰符。

这看起来很慢,所以我想将它更改为只使用一个preg_replace调用,并且能够以bbcode方式提供带有1个参数的自定义函数:示例:

[FUNC:testfunc(test string)]

所以,这就是我想出来的......我不确定哪种方法更安全,preg_rplace与e modifer或preg_replace_callback:

<?php
$str = '
<h2>Title That should Not Be Affected</h2>
<p>[FUNC:linkbox(/somestuff/newpage.html)]</p>
<a href="[FUNC:getvar(url)]">[FUNC:getvar(title)]</a>
<p>Random Html THat should not be affected</p>
<p>[FUNC:linkbox(/somestuff/otherpage.html)]</p>
';

$str2 = preg_replace_callback('~\[FUNC:(.*?)\((.*?)\)\]~', 'callback_caller', $str);

$str = preg_replace('~\[FUNC:(.*?)\((.*?)\)\]~e', 'emodcaller("\\1", "\\2")', $str);

echo $str.'<br><br>'.$str2;

function callback_caller($args){

    if(!isset($args[0], $args[1]))
        return false;

    $func = strip_tags($args[1]);
    $param = isset($args[2]) ? strip_tags($args[2]) : '';

    //Only allow calling of known functions
    switch($func){

        case 'linkbox':
            return linkbox($param);
        break;

        case 'getvar':
            return getvar($param);
        break;

        case 'default':
            return '';
        break;

    }

}

function emodcaller($fun, $arg){
    $arg = strip_tags($arg);

    //Only allow calling of known functions
    switch($fun){
        case 'linkbox':
            return linkbox($arg);
        break;

        case 'getvar':
            return getvar($arg);
        break;

        case 'default':
            return '';
        break;

    }

}

function linkbox($addy){
    return 'Linkbox Called: '.$addy;
}

function getvar($arg) {

    switch($arg){
        case 'url':
            return '/index.html';
        break;

        case 'title':
            return 'This is a test title';
        break;
    }

}
?>

我喜欢使用e修饰符的方法是,如果需要的话,我可以直接在php中将另一个参数添加到函数调用中,如下所示:

preg_replace('~\[FUNC:(.*?)\((.*?)\)\]~e', 'emodcaller("\\1", "\\2", $page->getid())', $str);

一种方法比另一种方法更安全吗?它们都是巨大的安全风险吗?我必须要实现这些......

编辑:我发现你可以使用匿名函数传递回调函数附加参数,如:

$content = preg_replace_callback(
'~(?:\<p\>)?\[FUNC:(.*?)\((.*?)\)\](?:\<\/p\>)?~',
function($matches) use ($article) {
return callback_caller($matches, $article);
}, 
$content);

这会将callback_caller()函数传递给我整个文章类以供使用。 是否为每一场比赛创建了一个像这样的匿名函数,性能方面呢?

1 个答案:

答案 0 :(得分:1)

根据您执行此操作的次数,创建匿名函数可能不好。

您始终可以使用方法调用进行回调,如下所示:

$content = preg_replace_callback($rx, array($obj, 'method_name'), $content);

如果它们已经是对象属性,那么可以避免将任何参数传递给方法。

我倾向于preg_replace_callback()优于preg_replace()和'e',因为它避免了在eval'd代码中正确转义任何模式匹配的缺陷,并避免了必须进行eval的开销(如果你正在使用像APC这样的操作码缓存,那就意味着编译零与每次调用编译的eval相比)。它还使代码更容易阅读 - eval'd代码总是看起来有点丑陋,因为你必须逃避字符串。

也就是说,使用preg_replace()与'e'没有任何内在错误。