This commit is contained in:
Laurent Destailleur 2020-03-13 04:12:42 +01:00
parent 280d77a0d6
commit 6dda972ff5

View File

@ -1,100 +1,110 @@
<?php <?php
/* /*
================================================================================ * ================================================================================
*
EvalMath - PHP Class to safely evaluate math expressions * EvalMath - PHP Class to safely evaluate math expressions
Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/> * Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
*
================================================================================ * ================================================================================
*
NAME * NAME
EvalMath - safely evaluate math expressions * EvalMath - safely evaluate math expressions
*
SYNOPSIS * SYNOPSIS
include('evalmath.class.php'); * include('evalmath.class.php');
$m = new EvalMath; * $m = new EvalMath;
// basic evaluation: * // basic evaluation:
$result = $m->evaluate('2+2'); * $result = $m->evaluate('2+2');
// supports: order of operation; parentheses; negation; built-in functions * // supports: order of operation; parentheses; negation; built-in functions
$result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8'); * $result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
// create your own variables * // create your own variables
$m->evaluate('a = e^(ln(pi))'); * $m->evaluate('a = e^(ln(pi))');
// or functions * // or functions
$m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1'); * $m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
// and then use them * // and then use them
$result = $m->evaluate('3*f(42,a)'); * $result = $m->evaluate('3*f(42,a)');
*
DESCRIPTION * DESCRIPTION
Use the EvalMath class when you want to evaluate mathematical expressions * Use the EvalMath class when you want to evaluate mathematical expressions
from untrusted sources. You can define your own variables and functions, * from untrusted sources. You can define your own variables and functions,
which are stored in the object. Try it, it's fun! * which are stored in the object. Try it, it's fun!
*
METHODS * METHODS
$m->evalute($expr) * $m->evalute($expr)
Evaluates the expression and returns the result. If an error occurs, * Evaluates the expression and returns the result. If an error occurs,
prints a warning and returns false. If $expr is a function assignment, * prints a warning and returns false. If $expr is a function assignment,
returns true on success. * returns true on success.
*
$m->e($expr) * $m->e($expr)
A synonym for $m->evaluate(). * A synonym for $m->evaluate().
*
$m->vars() * $m->vars()
Returns an associative array of all user-defined variables and values. * Returns an associative array of all user-defined variables and values.
*
$m->funcs() * $m->funcs()
Returns an array of all user-defined functions. * Returns an array of all user-defined functions.
*
PARAMETERS * PARAMETERS
$m->suppress_errors * $m->suppress_errors
Set to true to turn off warnings when evaluating expressions * Set to true to turn off warnings when evaluating expressions
*
$m->last_error * $m->last_error
If the last evaluation failed, contains a string describing the error. * If the last evaluation failed, contains a string describing the error.
(Useful when suppress_errors is on). * (Useful when suppress_errors is on).
*
$m->last_error_code * $m->last_error_code
If the last evaluation failed, 2 element array with numeric code and extra info * If the last evaluation failed, 2 element array with numeric code and extra info
*
AUTHOR INFORMATION * AUTHOR INFORMATION
Copyright 2005, Miles Kaufmann. * Copyright 2005, Miles Kaufmann.
*
LICENSE * LICENSE
Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
met: * met:
*
1 Redistributions of source code must retain the above copyright * 1 Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote * 3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written * products derived from this software without specific prior written
permission. * permission.
*
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
/**
* \file core/class/evalmath.class.php
* \ingroup core
* \brief This file for Math evaluation
*/
/**
* Class EvalMath
*/
class EvalMath class EvalMath
{ {
var $suppress_errors = false; public $suppress_errors = false;
var $last_error = null; public $last_error = null;
var $last_error_code = null; public $last_error_code = null;
var $v = array('e'=>2.71,'pi'=>3.14159); // variables (and constants) public $v = array('e'=>2.71,'pi'=>3.14159); // variables (and constants)
var $f = array(); // user-defined functions public $f = array(); // user-defined functions
var $vb = array('e', 'pi'); // constants public $vb = array('e', 'pi'); // constants
var $fb = array( // built-in functions public $fb = array( // built-in functions
'sin','sinh','arcsin','asin','arcsinh','asinh', 'sin','sinh','arcsin','asin','arcsinh','asinh',
'cos','cosh','arccos','acos','arccosh','acosh', 'cos','cosh','arccos','acos','arccosh','acosh',
'tan','tanh','arctan','atan','arctanh','atanh', 'tan','tanh','arctan','atan','arctanh','atanh',
@ -109,10 +119,22 @@ class EvalMath
$this->v['e'] = exp(1); $this->v['e'] = exp(1);
} }
/**
* Evaluate
*
* @param string $expr String
* @return boolean|number|NULL|mixed Result
*/
function e($expr) { function e($expr) {
return $this->evaluate($expr); return $this->evaluate($expr);
} }
/**
* Evaluate
*
* @param string $expr String
* @return boolean|number|NULL|mixed Result
*/
function evaluate($expr) { function evaluate($expr) {
$this->last_error = null; $this->last_error = null;
$this->last_error_code = null; $this->last_error_code = null;
@ -155,6 +177,11 @@ class EvalMath
} }
} }
/**
* vars
*
* @return string Output
*/
function vars() { function vars() {
$output = $this->v; $output = $this->v;
unset($output['pi']); unset($output['pi']);
@ -162,6 +189,11 @@ class EvalMath
return $output; return $output;
} }
/**
* vars
*
* @return string Output
*/
function funcs() { function funcs() {
$output = array(); $output = array();
foreach ($this->f as $fnn=>$dat) foreach ($this->f as $fnn=>$dat)
@ -169,9 +201,15 @@ class EvalMath
return $output; return $output;
} }
//===================== HERE BE INTERNAL METHODS ====================\\ //===================== HERE BE INTERNAL METHODS ====================\\
// Convert infix to postfix notation /**
* Convert infix to postfix notation
*
* @param string $expr Expression
* @return string Output
*/
function nfx($expr) { function nfx($expr) {
$index = 0; $index = 0;
@ -297,7 +335,14 @@ class EvalMath
return $output; return $output;
} }
// evaluate postfix notation
/**
* evaluate postfix notation
*
* @param string $tokens Expression
* @param array $vars Array
* @return string Output
*/
function pfx($tokens, $vars = array()) { function pfx($tokens, $vars = array()) {
if ($tokens == false) return false; if ($tokens == false) return false;
@ -359,7 +404,14 @@ class EvalMath
return $stack->pop(); return $stack->pop();
} }
// trigger an error, but nicely, if need be /**
* trigger an error, but nicely, if need be
*
* @param string $code Code
* @param string $msg Msg
* @param string|null $info sting
* @return boolean False
*/
function trigger($code, $msg, $info = null) { function trigger($code, $msg, $info = null) {
$this->last_error = $msg; $this->last_error = $msg;
$this->last_error_code = array($code, $info); $this->last_error_code = array($code, $info);
@ -376,11 +428,22 @@ class EvalMathStack
var $stack = array(); var $stack = array();
var $count = 0; var $count = 0;
/**
* push
*
* @param string $val Val
* @return void
*/
function push($val) { function push($val) {
$this->stack[$this->count] = $val; $this->stack[$this->count] = $val;
$this->count++; $this->count++;
} }
/**
* pop
*
* @return mixed Stack
*/
function pop() { function pop() {
if ($this->count > 0) { if ($this->count > 0) {
$this->count--; $this->count--;
@ -389,6 +452,12 @@ class EvalMathStack
return null; return null;
} }
/**
* last
*
* @param int $n N
* @return mixed Stack
*/
function last($n=1) { function last($n=1) {
if (isset($this->stack[$this->count-$n])) { if (isset($this->stack[$this->count-$n])) {
return $this->stack[$this->count-$n]; return $this->stack[$this->count-$n];