I do not disagree with the use of eval, the problem is that if you do not say the data processing can occur problems in the input values which will go from being a mathematical operation to being a code injection.
Yet a simple "parser" can solve, an example with preg_match_all would be so:
preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
var_dump($output[0]);
It extracts all integer values, with floating point and simple operators, of course it is still possible to inject invalid characters, in case do an input check, thus:
if (preg_match('#^(\d|\d\.\d)([\d\+\-\s\/\*]+|\d+\.\d+)(\d|\d\.\d)+$#', $input) > 0) {
preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
var_dump($output[0]);
}
We’ll still have the problem of people doing calculations like this:
2 2 3 + - /
But you can solve by checking in the loop the last value, a complete example I did:
<?php
class SimpleMath
{
private static function subcalc($a, $b, $operator)
{
switch ($operator)
{
case '-':
return $a - $b;
break;
case '+':
return $a + $b;
break;
case '*':
return $a * $b;
break;
case '/':
return $a / $b;
break;
}
}
public static function parse($input)
{
$input = trim($input);
if (preg_match('#^(\d|\d\.\d)([\d\+\-\s\/\*]+|\d+\.\d+)(\d|\d\.\d)+$#', $input) > 0) {
preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
$pre = $output[0];
$j = count($pre);
$operator = null;
$final = null;
for ($i = 0; $i < $j; $i++) {
var_dump($pre[$i]);
switch ($pre[$i]) {
case '-':
case '+':
case '*':
case '/':
if ($op !== null) {
//Se já houver um operador "preparado" e tentar adicionar outro força um erro
throw new Exception('Erro na ordem dos operadores');
}
$op = $pre[$i];
break;
default:
if ($final === null){
$final = $pre[$i];
} else if ($operator === null) {
//Se o anterior não era um operador força um erro
throw new Exception('Erro, falta um operador');
} else if (is_numeric($pre[$i])) {
$final = self::subcalc($final, $pre[$i], $operator);
//Remove operador usado
$operator = null;
} else {
//Se o numero na sequencia for invalido força um erro
throw new Exception('Formato do numero é invalido');
}
}
}
return $final;
} else {
throw new Exception('Input invalido');
}
}
}
var_dump( SimpleMath::parse('2 * 2 - 1') );
It does not work for advanced calculations, but just you adapt and add conditions and or operators, also have the case to use the parentheses as soon as possible I will create an example that supports something like (1 * 2) - (3 /4)
With only
if elseorswitchexample:if($operação === '+')– Leonardo
Yes, it would facilitate a lot if it existed, because there are several calculations and this way will quadruple the number of lines.
– Rodrigo Segatto
The cited Eval is not very recommendable
– Leonardo
Is there any other way to do this @Ivcs?
– user46523
Better a parser than an Eval
– Bacco
http://answall.com/questions/156657/como-retr-um-resultado-v%C3%A1lido-a-from-an-opera%C3%A7%C3%A3o-em-php
– Daniel Omine