评估PHP表达式逻辑 - 但没有eval()?

时间:2016-08-20 15:21:45

标签: php regex eval

对于我正在处理的复杂项目,我希望允许管理员使用布尔表达式为事件附加条件。

示例:

if (1 > 2 || (1 == 1 && 3 > 2)) [...]

以上将返回TRUE。

eval()似乎是一个简单的解决方案,但我很清楚它带来的安全风险。 PHP是否提供了一种在不实际评估其他任意PHP代码的情况下评估上述表达式的方法?选项只能评估数学表达式,或者可能是接受函数白名单的eval()清洁剂。

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

最好的方法是使用token_get_all

作为你的建议“清洁剂”

下面(不完整)代码段,以便您可以明白

function evalExpression ($expression)
{
    $code = "return $expression;";
    $token = token_get_all($code,TOKEN_PARSE);

    # return
    unset($token[1]);

    foreach ($token as $key=>$value) {

        if(is_array($value)) {

            # white list token
            $allow = [T_WHITESPACE,T_LNUMBER,/* add more token*/];

            # remove white list token
            if(in_array($value[0],$allow,true)) {
                unset($token[$key]);
            }

        } else {

            # white list string
            $allow = [';','>'/* add more element*/];

            # remove white list string
            if(in_array($value,$allow,true)) {
                unset($token[$key]);
            }

        }

    }

    # if token contain only white listed, $token should empty
    if(!$token) {
        return eval($code);
    } else {
        throw new \InvalidArgumentException('err'); 
    }

};

# return bool
var_dump(evalExpression('2 > 1'));

# should error
var_dump(evalExpression('function(){}'));

由于eval构造很危险,因此在进入生产之前应该尝试使用恶意代码进行注入/测试