1

For a complex project I'm working on, I want administrators to be allowed to attach conditions to events using boolean expressions.

Example:

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

The above would return TRUE.

eval() seems like an easy solution, but I am well aware of the security risks it presents. Does PHP provide a way to evaluate expressions like the above without actually evaluating other arbitrary PHP code? Options would be something that only evaluates mathematical expressions, or perhaps an eval() sanitizer that accepts a whitelist of functions.

Thanks for your help!

Nathanael
  • 6,893
  • 5
  • 33
  • 54
  • 1
    I wouldn't use regexp to try and sanitise data for calculation; I'd look at writing a calculator, perhaps based on [this](http://stackoverflow.com/questions/12692727/how-to-make-a-calculator-in-php) – Mark Baker Aug 20 '16 at 17:53
  • Mark's proposal is excellent. Otherwise you could build a recursive parser ([here is a nice example](http://stackoverflow.com/questions/35426793/parsing-a-string-with-recursive-parentheses)) – Geo Halkiadakis Aug 20 '16 at 18:25

1 Answers1

1

The best thing is as your suggestion "sanitizer", by using token_get_all

below (incomplete) snippet so you might get the idea

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(){}'));

since eval construct are dangerous you should try to inject/test with malicious code, before run into production

Andikac
  • 384
  • 2
  • 13
  • 1
    OP asked without eval – Steve Moretz Oct 11 '20 at 18:20
  • @stevemoretz yes I know, sorry to say this but i think who ask question like this does not really understand what they ask for. at this point you need to re-invent some kind of interpreter/compiler/parser/etc or use external one, PHP is interpreter, "if you really know what your doing" eval is pretty save . – Andikac Jun 10 '21 at 22:59
  • I agree that is all true, but I guess you should have mentioned in your answer that this needs a compiler if not using eval therfore using eval makes more sense. – Steve Moretz Jun 11 '21 at 06:50