2010-10-25 22 views
8

un usuario está autorizado a entrar en cualquier ecuación matemática que les gusta (con una variable):Proceso de ecuaciones matemáticas en php

x + 5

1 - x/2

(x/3) * (56/13)

Estos se almacenan como cadenas en la base de datos. Cuando se recuperan, necesito sustituir 'x' por un número y verificar el valor de la ecuación.

¿Cómo podría hacer esto?

Estaba pensando en escribir un analizador para deconstruir las cadenas y convertirlas en ecuaciones, sin embargo, esto parece costoso y problemático. La otra opción es pasarlos a través de eval (pero no soy muy fanático de usar eval si puedo evitarlo).

¿Alguna idea?

ACTUALIZACIÓN: También necesito poder obtener el valor booleano de algo así como "(x> 5)". Esto no es posible con evalMath

UPDATE 2: Necesito disparar lotes de estos por segundo. He estado buscando en eval en php pero no puedo obtener un booleano para (5> 4), pero noté que js lo haría ... quizás debería investigar node.js ...

UPDATE 3: Después de tener un poco de diversión de probar Node.js (y conseguir que funcione) volví y me eval para trabajar en PHP ver: Can php eval return a boolean value?

así que voy a ir con eval con un filtro muy, muy duro en la entrada del usuario.

+0

Si necesita hacer cosas más complejas, WolframAlpha offers an API para desarrolladores. – TheMagician

+0

@TheMagician Buena idea, pero desafortunadamente estos necesitan ser disparados muy a menudo (miles de ellos por segundo) por lo que una API externa no va a funcionar. –

Respuesta

4

Eval no es Evil !!!!!

Sí, puede rellenar completamente el sistema si escribe código incorrecto, pero las versiones recientes de PHP pueden analizar una expresión no válida sin colapsar todo el script. Y hay muchas otras maneras de exponer su sistema al escribir código incorrecto.

Eso simplemente deja la posibilidad de ataques de inyección de código, que pueden evitarse fácilmente haciendo un preg_replace en everythnig que no es un carácter seguro (es decir, 0 .... 9, (,), +, -, *, /, ^,.)

+1

preg_replace para hacer que la expresión "seguro" se vuelva más incómoda si la expresión puede contener funciones como log(), sin() ... OP no indica si este es o no el caso. –

+0

De acuerdo, es más incómodo, pero está lejos de ser imposible de implementar. Lo importante es utilizar listas blancas en lugar de listas negras. – symcbean

+0

Gracias por una evaluación no es respuesta mal :) –

0

Incluso si pasa a través de eval, tendrá que reemplazar x con un número. El tipo de estrategia que tendría es pasarle valor a x, y ver cuál es el valor evaluado. Si es más de 0, entonces probaría un número más pequeño, y si es menor que 0, probaría un número mayor recursivamente hasta que satisfaga un margen de error (<> 0.001%).

-1

eval()

Depende de lo que tiene que hacer, pero de todos modos, la forma más barata de hacerlo está utilizando una función substituye para las variables y luego ejecutar la expresión mediante el uso de la función eval().
Por supuesto, primero necesita asegurarse de que sus fórmulas estén en sintaxis php.
Lo bueno es que se puede utilizar cualquier función matemática con el apoyo de PHP, lo malo es, nunca es agradable de usar la función eval() :)

PHPClasses

La otra buena opción que es el surf la web hasta que encuentre un programa de análisis: P
http://www.phpclasses.org/package/2695-PHP-Safely-evaluate-mathematical-expressions.html

+2

-1 para sugerir el uso de eval() en la entrada del usuario – Hammerite

+2

-1 nice !!! Es francamente peligroso con la entrada del usuario, como se ha establecido como requisito en esta pregunta. –

+0

@Hammerite, @Mark Baker: hey, escribo que nunca es bueno usar el eval ... – Cesar

0

Depende ...

Cuál es la complejidad que aceptará? Debido a las ecuaciones matemáticas comunes (como las que publicaste), no veo demasiados problemas al escribir un analizador.La principal pregunta problemática sería redondear los números y colocar el paréntesis correcto.

Pero si las ecuaciones van a aceptar entradas "avanzadas", como {[()]}, o X², X³, o ir más allá, cálculos diferenciales y matemática universitaria, entonces las cosas pueden volverse locas.

Si la complejidad llega a un manejo simbólico, intente leer y buscar algo sobre CAS (Calcular sistemas de álgebra).

Por supuesto, le recomiendo encarecidamente que haga su propio sistema de entradas, valide en su contra y evangelice a los usuarios para que atan las entradas. Nada demasiado complejo, pero suficiente para que usted (y otros) se sientan cómodos y seguros para llegar a lo que necesita.

12

Mi respuesta estándar a esta pregunta cada vez que surge:

No utilizar eval (especialmente en lo que usted está indicando que esta es la entrada del usuario) o reinventar la rueda escribiendo su propia fórmula analizador.

Eche un vistazo a la clase evalMath en PHPClasses. Debería hacer todo lo que ha enumerado aquí.

EDITAR

re: Por desgracia evalMath no maneja las cosas como (x> 5)

líneas de cambio de 177-179 a

$ops = array('+', '-', '*', '/', '^', '_', '>', '<', '='); 
$ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>0, '>' => 0, '<' => 0, '=' => 0); // right-associative operator? 
$ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2, '>' => 0, '<' => 0, '=' => 0); // operator precedence 

cambiar la línea 184 a

if (preg_match("/[^\w\s+*^\/()\.,-<>=]/", $expr, $matches)) { // make sure the characters are all good 

agregar

case '>': 
    $stack->push($op1 > $op2); break; 
case '<': 
    $stack->push($op1 < $op2); break; 
case '=': 
    $stack->push($op1 == $op2); break; 

después de la línea 321

y evalMath ahora manejará (x> 5), (x < 5) o (x = 5)

// instantiate a new EvalMath 
$m = new EvalMath; 
$m->suppress_errors = true; 
// set the value of x 
$m->evaluate('x = 3'); 
var_dump($m->evaluate('y = (x > 5)')); 

Además Editar

Línea perdida 307 que debe modificarse para que lea:

if (in_array($token, array('+', '-', '*', '/', '^', '>', '<', '='))) { 
+0

Desafortunadamente evalMath no maneja cosas como (x > 5) –

+1

@ae - no hay mucho trabajo involucrado para que evalMath maneje (x> 5), etc. Parecería que prefieres usar eval() a pesar de los peligros, pero mira mi edición para los cambios involucrado. –

+0

¡Eso es genial! Voy a darle un tiempo y ver cómo va. –

1

Si está tratando con la entrada del usuario, me mantendría alejado de eval. Escribe un analizador y divide la fórmula en matrices anidadas.

1 - x/2 

convierte

Array 
(
    [0] => - 
    [1] => 1 
    [2] => Array 
     (
      [0] =>/
      [1] => x 
      [2] => 2 
     ) 
) 

Es un poco difícil de escribir el analizador, pero es muy fácil de evaluar una fórmula analizada.

1

posibilidad algo arriesgada si estaba ejecutando su código en una caja de linux es usar el comando bc (asegúrese de escapar sus entradas correctamente antes de dársela al cmd del sistema). No puedo decir que utilizar el sistema sea mucho mejor que los riesgos de la evaluación, así que estoy esperando algunos votos a favor aquí.

-1

El uso de la función eval es muy peligroso cuando no se puede controlar el argumento de cadena.

Pruebe Matex para el cálculo seguro de fórmulas matemáticas. Admite también variables y funciones personalizadas.

Cuestiones relacionadas