1

I have some code that looks like this.

eval('$ruleTrue = '."{$value} {$operator} {$value2};");

I am pulling mostly numeric values from a database and comparing them with other numeric values. The operator comes from a database as well. Possible operators are <,>,==.

Well when comparing ints and floats this works perfectly. BUT when comparing strings it breaks. For instance..

WORKS: 5 > 4 $ruleTrue = true

Doesn't Work Right: John-Adams == Alice $ruleTrue = true <--- WHY? Because John is not == to Alice.

For some reason my $ruleTrue variable is being returned as true when comparing strings.

3 Answers 3

4

You're trying to evaluate this code:

$ruleTrue = John == Alice;

John and Alice aren't strings, they're undefined constants. You want to put quotes around them. But be careful, because if your users are able to edit those fields in your database, they could find a way of unquoting the strings and executing their own php code, which could be disastrous. Eval is very unsecure that way, and you probably shouldn't be using it.

Sign up to request clarification or add additional context in comments.

5 Comments

Undefined constants evaluate to strings containing their names, which obviously aren't equal. At least stringwise...
Believe me I have made my argument against this type of usage of eval, but I am not winning. So I am stuck adapting.
Think I know why I am getting true...My String has a dash. For example string one let's say is John-Adams and string2 is "Alice". John-Adams == Alice returns true.
Ah yes, the minus sign makes it interpret the strings as 0, and then Alice is interpreted as 0 as well. 0 - 0 == 0
@allencoded: Check my updated answer for a safer and more robust alternative to eval.
2

The expression John-Adams == Alice parses somewhat like (John - Adams) == Alice. The left side is trying to subtract two strings (undefined constants are considered 'barewords', and are equal to a stringification of their names; John === 'John', for example), and in order to make sense of such an odd operation, PHP turns both strings into numbers. As integers, both strings have a value of 0, so the left side equates to 0.

An int.

Now, when PHP wants to compare with ==, it wants to coerce both sides into the same type. In this case, it's converting to int. Alice also converts to 0. Both sides being 0, they're "obviously" equal.

In order to prevent this from happening, you should probably put quotes around your values. You might also consider using the strict equals operator (===), unless you really want that type coercion magic.

Alternatively, if you have a known set of operators, you can eliminate eval and make this safer and more robust all around, by making a comparison function that has sub-functions for the operators. Like so:

function compare($value1, $op, $value2) {
    static $known_ops = array(
        '==' => function($a, $b) { return $a == $b; },
        '!=' => function($a, $b) { return $a != $b; },
        ...

        # you can even make up your own operators.  For example, Perl's 'eq':
        'eq' => function($a, $b) { return "$a" === "$b"; }

        ...
    );
    $func = $known_ops[$op];
    return $func($value1, $value2);
}

...

$ruleTrue = compare($value, $operator, $value2);

Now you don't have to worry about your values. You do have to worry about $operator, but that's only an issue if you let a user input it without you validating it. In which case, you may want to throw an exception or something if $op wasn't in $known_ops, cause if you leave PHP to handle it, you'll likely get a fatal error when it tries to call null.

Comments

1

Make sure, if the value are strings, they are surrounded with "quotes"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.