eval() is insecure, but what are the alternatives?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • werner

    #1

    eval() is insecure, but what are the alternatives?

    Hi!

    I don't want to use eval() in order to parse a user-supplied formula.
    What alternatives do I have? PHP has no standard functionality for
    tokenizing or parsing expressions in this regard.

    Here is a simple example: The user supplies the following formula in
    string format,
    "a = (6+10)/4",
    and the script needs to find out what the value of 'a' is.

    How can I go about it without using eval(), since using eval in this
    case could be very risky! (The user can supply *any* expression, as
    there is no function that can determine the meaning of the string as an
    expression).

    Thank you for taking the time t read my question.

  • Sjoerd

    #2
    Re: eval() is insecure, but what are the alternatives?

    There are several options:
    1. Check the user input to only contain number, operators and
    parenthesis and then supply it to eval. This would be safer than using
    eval without checking, but it may still be insecure and it is not the
    right option. If you need to accept variables and functions in the
    expression, making this secure becomes close to impossible.
    2. You may parse the expression and compute the result using PHP code.
    This is a better option, but may not be worth the time it takes to
    write a parser.

    I tried searching the web for a math expression parser, but I did not
    found one. I have written something to get you started:

    It is not complete. It does not check parenthesis and does not give
    precendence to * over + (for example). It converts the expression to
    Reverse Polish notation and than computes it.

    If you want to extend my file, you may find
    http://en.wikipedia.org/wiki/Reverse_Polish_Notation interesting.
    Please send any new version to me.

    Good luck.

    Comment

    • Pedro Graca

      #3
      Re: eval() is insecure, but what are the alternatives?

      werner wrote:[color=blue]
      > I don't want to use eval() in order to parse a user-supplied formula.
      > What alternatives do I have? PHP has no standard functionality for
      > tokenizing or parsing expressions in this regard.[/color]

      Other than writing your own parser (or using one already done), I don't
      think you have any alternatives.
      [color=blue]
      > Here is a simple example: The user supplies the following formula in
      > string format,
      > "a = (6+10)/4",
      > and the script needs to find out what the value of 'a' is.
      >
      > How can I go about it without using eval(), since using eval in this
      > case could be very risky! (The user can supply *any* expression, as
      > there is no function that can determine the meaning of the string as an
      > expression).[/color]

      Example using an already done parser (bc):

      <?php
      /* needs error checking */
      $formula = 'a = (6+10)/4';

      /* remove the left part of assignment */
      $value = trim(substr($fo rmula, strpos($formula , '=')+1));
      $value = escapeshellarg( $value);

      $calculated = `echo $value | bc`; /* backticks! */
      echo $calculated, "\n";
      ?>

      tmp$ php foo.php
      4



      "bc" is "an arbitrary precision numeric processing language"


      But, even so, I wouldn't pass input from the user directly to bc without
      checking/validating it first (at least not until I've read thoroughly
      bc's documentation).

      --
      If you're posting through Google read <http://cfaj.freeshell. org/google>

      Comment

      • Chung Leong

        #4
        Re: eval() is insecure, but what are the alternatives?

        There is bc under Unix. Although inserting user-supplied data into a
        shell command might be even more dangerous.

        Comment

        • Pedro Graca

          #5
          Re: eval() is insecure, but what are the alternatives?

          Chung Leong wrote:[color=blue]
          > There is bc under Unix. Although inserting user-supplied data into a
          > shell command might be even more dangerous.[/color]

          There's also bc for Windows:


          And I agree that passing user data to a shell command is dangerous.
          but maybe this is enough protection:

          $formula = 'user data';
          if preg_match('/^[-+*/^()\s0-9]+$/', $formula) {
          /* do shell command with properly escaped data */
          } else {
          /* bad entry */
          }

          --
          If you're posting through Google read <http://cfaj.freeshell. org/google>

          Comment

          • werner

            #6
            Re: eval() is insecure, but what are the alternatives?

            Thanks for the input, this topic has had me wrestling with PHP for
            quite some time.

            Pedro Graca wrote:[color=blue]
            > $formula = 'user data';
            > if preg_match('/^[-+*/^()\s0-9]+$/', $formula) {
            > /* do shell command with properly escaped data */
            > } else {
            > /* bad entry */
            > }[/color]

            Well, since the user should be able to supply arbitrary variables in
            the expression (which will then make the whitelist filtering approach a
            bit hard to accomplish, e.g. we'll need to add a "[a-z]+" in there as
            well), some innocent-looking "expression s" like 'rm -rf *' might still
            slip through.
            [color=blue]
            > I have written something to get you started:
            > http://svn.linuxonly.nl/filedetails....uxonly.nl&path...
            > It is not complete. It does not check parenthesis and does not give
            > precendence to * over + (for example). It converts the expression to
            > Reverse Polish notation and than computes it.[/color]

            Thanks for the help! I agree with the parser suggestion and have also
            previously searched for an expression parser, as this would be the best
            approach. I just can't *believe* that there isn't one yet, considering
            the complexity of classes found in Pear, Pecl and those made for
            academic and educational purposes.

            I am also looking at maybe porting an existing Java solution, what do
            you think? It's just going to take some time, and I sadly don't have
            much of that left.
            [color=blue]
            > There is bc under Unix. Although inserting user-supplied data into a
            > shell command might be even more dangerous.[/color]

            That is also an interesting approach, but I do feel that I would like
            to keep it a native php solution.

            Funny thing, though, that there is no native parser function available,
            since PHP is after all an interpreted language. Something like eval()
            that could return tokens, instead of the evaluated value would be
            *extremely* helpful in this regard. What do you think?

            Thanks again, everyone.

            Comment

            • Pedro Graca

              #7
              Re: eval() is insecure, but what are the alternatives?

              werner wrote:[color=blue]
              > I agree with the parser suggestion and have also
              > previously searched for an expression parser, as this would be the best
              > approach.
              >
              > I am also looking at maybe porting an existing Java solution, what do
              > you think? It's just going to take some time, and I sadly don't have
              > much of that left.[/color]

              Use bc! :-)
              [color=blue][color=green]
              >> There is bc under Unix. Although inserting user-supplied data into a
              >> shell command might be even more dangerous.[/color][/color]

              My example (below) looks safe. It could be made tighter by checking for
              long lines, disabling single quotes and "strange" characters (ESC, NUL,
              ....), and whatever else you might think of.

              .... but bc is, perhaps, best discussed on gnu.utils.help.
              [color=blue]
              > That is also an interesting approach, but I do feel that I would like
              > to keep it a native php solution.[/color]


              <?php
              $formula = <<<FORMULA
              /*
              * find the hypotenuse of a right triangle
              * with height = 5 and area = 25
              */

              /* !!!! ATTENTION !!! */
              rm -rf * ## I tried it!!
              ## it seems perfectly safe (???)
              /* !!! ATTENTION !!! */

              scale = 8 ## work with 8 decimals

              /* area = h * w / 2 */
              h = 5 ## height
              area = 25 ## area
              w = 2*area / h ## compute width

              /* hypotenuse = sqrt(h*h + w*w) */
              hyp = sqrt(h*h + w*w) ## compute hypotenuse
              hyp ## print (and return) it
              FORMULA;

              $value = escapeshellarg( $formula);
              $calculated = `echo $value | bc`; /* backticks! */

              // with "rm" in the formula, $calculated will have the error message
              // from bc; it might be possible to remove all messages with a
              // simple regular expression, I didn't look into that.
              echo $calculated;
              ?>

              --
              If you're posting through Google read <http://cfaj.freeshell. org/google>

              Comment

              • R. Rajesh Jeba Anbiah

                #8
                Re: eval() is insecure, but what are the alternatives?

                werner wrote:[color=blue]
                > Hi!
                >
                > I don't want to use eval() in order to parse a user-supplied formula.
                > What alternatives do I have? PHP has no standard functionality for
                > tokenizing or parsing expressions in this regard.[/color]
                <snip>

                You may do sand boxing with <http://in2.php.net/runkit>

                --
                <?php echo 'Just another PHP saint'; ?>
                Email: rrjanbiah-at-Y!com Blog: http://rajeshanbiah.blogspot.com/

                Comment

                • Jim Michaels

                  #9
                  Re: eval() is insecure, but what are the alternatives?

                  Download muParser - A fast math parser library for free. This project no longer resides at sourceforge. The new home page is: http://muparser.beltoforion.de

                  if you want to convert the code. fairly complex. better make this one a DLL
                  extension of PHP.

                  "Pedro Graca" <hexkid@dodgeit .com> wrote in message
                  news:slrndt3300 .h04.hexkid@ID-203069.user.ind ividual.net...[color=blue]
                  > werner wrote:[color=green]
                  >> I agree with the parser suggestion and have also
                  >> previously searched for an expression parser, as this would be the best
                  >> approach.
                  >>
                  >> I am also looking at maybe porting an existing Java solution, what do
                  >> you think? It's just going to take some time, and I sadly don't have
                  >> much of that left.[/color]
                  >
                  > Use bc! :-)[/color]

                  http://us2.php.net/manual/en/ref.bc.php (does not have eval-like function)
                  instead of using backticks, use the library?

                  http://www.bestcode.com/html/bcparserx.html COM control that evals math,
                  co$t$ money.
                  http://www.freevbcode.com/ShowCode.asp?ID=2090 vree vb parser, not too
                  complicated. I am converting it now. here.

                  <?php
                  //Attribute VB_Name = "Module1"
                  /*
                  ' Acclaimer and Disclaimer!
                  '************** *************** *************** *************** *************** *************** ****
                  '* This code is written by Jonathan Adamit (c) 20th in December
                  2000. *
                  '* I Am in no way responsible for anything that occures as a result of
                  implementing *
                  '* this code or by using it in any way.
                  *
                  '* This code is given to you for free to do whatever you want to do with
                  it. *
                  '* My only request is that if you use it - you give me the credit for it.
                  *
                  '* I will also be very greatful if you E-mail me any improvements or
                  changes you made to it.*
                  '* Any comments or changes are to be sent to:
                  adamit@bgumail. bgu.ac.il *
                  '************** *************** *************** *************** *************** *************** ****
                  version 1.0

                  '
                  ' Example of use and remarks!
                  '************** *************** *************** *************** *************** *************** *************** *********
                  '* On Error Resume Next
                  *
                  '* Dim X As Double
                  *
                  '* X = Parse("2+3*4^2* 2*cos[3]+2")
                  *
                  '* if Err.Number = 11 Then MsgBox "Division by Zero", , "Uncalculatable "
                  *
                  '* if Err.Number = vbObjectError + 555 Then MsgBox "Specified Text Sequence
                  Not Allowed!", , "Invalid Equation" *
                  '*---------------------------------------------------------------------------------------------------------------*
                  '* cos/sin/tan/atn must be enclosed with [] as the example shows.
                  *
                  '* Use of absolute signs (|) is allowed.
                  *
                  '************** *************** *************** *************** *************** *************** *************** *********
                  */

                  function RemSpaces($Exp) {
                  return str_replace(" ","",$Exp);
                  }

                  function RemPlusMinus($E xp) {
                  $NewExp="";
                  $RPM = $Exp;
                  $Place = strpos($Exp, "+-");
                  if ($Place === false) { } else {
                  $NewExp = substr($Exp, 0, ($Place - 1)+1) . "-" . substr($Exp, -1,
                  (strlen($Exp) - $Place - 1)+1);
                  if (strpos($NewExp , "+-") === false) { } else {
                  $NewExp = RemPlusMinus($N ewExp);
                  }
                  $RPM = $NewExp;
                  }
                  $Place = strpos($NewExp, "--");
                  if ($Place === false) { } else {
                  $NewExp = substr($NewExp, 0, ($Place - 1)+1) . "+" . substr($NewExp, -1,
                  (strlen($NewExp ) - $Place - 1)+1);
                  if (strpos($NewExp , "--") === false) { } else {
                  $NewExp = RemPlusMinus($N ewExp);
                  }
                  return $NewExp;
                  }
                  return $RPM;
                  }

                  function isnumeric($x) {
                  return 1==preg_match("/[\deE\.]/", $x);
                  }

                  function IsValid($Exp) {
                  for ($X = 0; $X < strlen($Exp); $X++) {
                  switch ($Exp{$X}) {
                  case "[": case "]": case "(": case ")": case "*": case "/": case "+": case
                  "-": case "^":
                  break;
                  case "|":
                  if (substr($Exp, $X, 2) == "||") {
                  echo "mdlParse: Specified Text Sequence Not Allowed";
                  return false;
                  }
                  break;
                  default:
                  switch(isnumeri c($Exp{$X})) {
                  case false:
                  switch($X) {
                  case 0://1:
                  $Temp = substr($Exp, $X, 3);
                  if (($Temp != "tan") && ($Temp != "cos") && ($Temp != "sin") && ($Temp
                  != "atn")) {
                  echo "mdlParse: Specified Text Sequence Not Allowed";
                  return false;
                  }
                  break;
                  case 1://2:
                  $Temp = substr($Exp, $X - 1, 3);
                  if (($Temp != "tan") && ($Temp != "cos") && ($Temp != "sin") && ($Temp
                  != "atn")) {
                  echo "mdlParse: Specified Text Sequence Not Allowed";
                  return false;
                  }
                  break;
                  default://case Is > 2
                  $Temp = substr($Exp, $X - 2, 6);
                  if ((strpos($Temp, "cos[") === false) && (strpos($Temp, "sin[") ===
                  false) && (strpos($Temp, "tan[") === false) && (strpos($Temp, "atn[") ===
                  false)) {
                  echo "mdlParse: Specified Text Sequence Not Allowed";
                  return false;
                  }
                  break;
                  }
                  break;
                  case true:
                  $Temp = substr($Exp, $X, 2);
                  //if ((strpos($Temp, "[") >= 0) || (strpos($Temp, "(") >= 0) ||
                  (strpos($Temp, "s") >= 0) || (strpos($Temp, "c") >= 0) || (strpos($Temp,
                  "t") >= 0) || (strpos($Temp, "a") >= 0)) {
                  if ((strpos($Temp, "[") === false) && (strpos($Temp, "(") === false) &&
                  (strpos($Temp, "s") === false) && (strpos($Temp, "c") === false) &&
                  (strpos($Temp, "t") === false) && (strpos($Temp, "a") === false)) { } else {
                  echo "mdlParse: Specified Text Sequence Not Allowed";
                  return false;
                  }
                  break;
                  } //end switch $X
                  //Ok:
                  } //end switch $Exp{$X}
                  } //end for
                  return true;
                  }



                  function Mul($Exp) {
                  //Dim Place As Integer //'Where the sign is found
                  //Dim X As Integer //'Travel backward and forward on the string
                  //Dim Y As Integer //'Counter
                  //Dim Before As String //'What number goes before the sign
                  //Dim After As String //'What number goes after the sign
                  //Dim NewExp As String
                  //Dim BeforeStr As String //'Used to save the text that goes before our
                  calculation
                  $Exp = RemPlusMinus($E xp); //'Make sure previous calculation didn't leave
                  +- or --
                  $M = $Exp; //'Incase there's nothing to do, make sure the
                  function returns correct information
                  $Place = strpos($Exp, "*");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do {//'loop backwards on the string to find out the number before the sign
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-" || $Y == 1) && ($Exp{$X} !=
                  "/")) {
                  $Before = substr($Exp, $X, $Y);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-" && $Y != 1) || ($Exp{$X}
                  == "/"))); //'As Long as we didn't get to the start or to another sign -
                  continue traveling backwards.
                  $BeforeStr = substr($Exp, 0, $X+1);
                  $Y = 0;
                  $X = $Place;
                  do {
                  $Y++;
                  $X++;
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-" || $Y == 1) && ($Exp{$X} !=
                  "*") && ($Exp{$X} != "/")) {
                  $After = substr($Exp, $Place + 1, $Y+1); //+1 or -1? I think it's +1.
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-" && $Y != 1) || ($Exp{$X}
                  == "*") || ($Exp{$X} == "/") || ($X >= strlen($Exp)-1))); //'As long as we
                  didn't get to the end or to another sign - continue traveling forward.
                  $NewExp = $BeforeStr . ((double)$Befor e * (double)$After) . substr($Exp,
                  $X+1);
                  if (strpos($NewExp , "*") === false) { } else {
                  $NewExp = Mul($NewExp); //'Recurse incase there are *'s left
                  }
                  return $NewExp;
                  } //end if
                  return $M;
                  }

                  function Add($Exp) {
                  $Exp = RemPlusMinus($E xp);
                  $A = $Exp;
                  $Place = strpos($Exp, "+");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do { //'loop backwards on the string to find out the number before the
                  sign
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if (($Exp{$X} != "-" || $X == 0) && ($Exp{$X} != "*") && ($Exp{$X} !=
                  "/")) {
                  $Before = substr($Exp, $X, $Y);
                  }
                  } while (!(($Exp{$X} == "*") Or ($Exp{$X} == "-" && $X != 0) || ($Exp{$X}
                  == "/")));
                  $BeforeStr = substr($Exp, 0, $X+1);
                  $Y = 0;
                  $X = $Place;
                  do {
                  $Y++;
                  $X++;
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-") && ($Exp{$X} != "*") &&
                  ($Exp{$X} != "/")) {
                  $After = substr($Exp, $Place + 1, $Y);
                  }
                  } while (($Exp{$X} != "+") && ($Exp{$X} != "-") && ($Exp{$X} != "*") &&
                  ($Exp{$X} != "/") && ($X < strlen($Exp)-1));
                  $NewExp = $BeforeStr . ((double)$Befor e + (double)$After) . substr($Exp,
                  $X+1);
                  if (strpos($NewExp , "+") === false) { } else {
                  $NewExp = Add($NewExp); //'Recurse incase there are +'s left
                  }
                  return $NewExp;
                  } //end if
                  return $A;
                  }

                  function Subt($Exp) {
                  $Exp = RemPlusMinus($E xp);
                  $S = $Exp;
                  $Place = strpos($Exp, "-");
                  if ($Place === 0) $Place = strpos($Exp, "-", 1);
                  if ($Place > 0) {
                  $Y = 0;
                  $X = $Place;
                  do { //'loop backwards on the string to find out the number before the
                  sign
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if (($Exp{$X} != "+") && ($Exp{$X} != "*") && ($Exp{$X} != "/")) {
                  $Before = substr($Exp, $X, $Y);
                  }
                  } while (!(($Exp{$X} == "*") || ($Exp{$X} == "+") || ($Exp{$X} == "/")));
                  $BeforeStr = substr($Exp, 0, $X+1); //+1 added afterwards by Jim
                  $Y = 0;
                  $X = $Place;
                  do {
                  $Y++;
                  $X++;
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-") && ($Exp{$X} != "*") &&
                  ($Exp{$X} != "/")) {
                  $After = substr($Exp, $Place + 1, $Y+1);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-") || ($Exp{$X} == "*") ||
                  ($Exp{$X} = "/") || ($X >= strlen(Exp)-1)));
                  $NewExp = $BeforeStr . ((double)$Befor e - (double)$After) . substr($Exp,
                  $X+1);
                  if (strpos($NewExp , "-") === false) { } else {
                  $NewExp = Subt($NewExp); //'Recurse incase there are -'s left
                  }
                  return $NewExp;
                  }
                  return $S;
                  }

                  function Parentheses($Ex p) {
                  $Exp = RemPlusMinus($E xp);
                  $P = $Exp;
                  $MiddleStr="";
                  $Place = strpos($Exp, ")");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do { //'loop to find the inside of the parentheses
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if ($Exp{$X} != "(") {
                  $MiddleStr = substr($Exp, $X, $Y);
                  }
                  } while ($Exp{$X} != "(");
                  $BeforeStr = ""; //'if it's the beginning of the string - there is nothing
                  before.
                  if ($X >= 0) $BeforeStr = substr($Exp, 0, ($X - 1)+1);
                  $NewExp = $BeforeStr . Parse($MiddleSt r) . substr($Exp, $Place + 1);
                  if (strpos($Exp, ")") === false) { } else {
                  $NewExp = Parentheses($Ne wExp); //'Recurse incase there are more
                  parentheses
                  }
                  return $NewExp;
                  }
                  return $P;
                  }

                  function Div($Exp) {
                  //On Error Resume Next
                  $Exp = RemPlusMinus($E xp);
                  $D = $Exp;
                  $Place = strpos($Exp, "/");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do {//'loop backwards on the string to find out the number before the sign
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if (($Exp{$X} != "+") && ($Exp{$X} && "-" || $Y == 1) && ($Exp{$X} !=
                  "*")) {
                  $Before = substr($Exp, $X, $Y);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-" && $Y != 1) || ($Exp{$X}
                  == "*")));
                  $BeforeStr = substr($Exp, 0, $X+1);
                  $Y = 0;
                  $X = $Place;
                  do {
                  $Y++;
                  $X++;
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-" Or Y == 1) && ($Exp{$X} != "*")
                  && ($Exp{$X} != "/")) {
                  $After = substr($Exp, $Place + 1, $Y+1);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-" && $Y != 1) || ($Exp{$X}
                  == "*") || ($Exp{$X} == "/") || ($X >= strlen($Exp)-1)));
                  if ((double)$After ==0.0) {
                  return "Impossible ";
                  }
                  $NewExp = $BeforeStr . ((double)$Befor e / (double)$After) . substr($Exp,
                  $X+1);
                  if (strpos($NewExp , "/") === false) { } else {
                  $NewExp = Div($NewExp); //'Recurse incase there are /'s left
                  }
                  return $NewExp;
                  }
                  return $D;
                  }

                  function Power($Exp) {
                  $Exp = RemPlusMinus($E xp);
                  $P = $Exp;
                  $Place = strpos($Exp, "^");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do { //'loop backwards on the string to find out the number before the
                  sign
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-" || X == 0) && ($Exp{$X} != "*")
                  && ($Exp{$X} != "/")) {
                  $Before = substr($Exp, $X, $Y);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-" && X != 0) || ($Exp{$X}
                  == "*") || ($Exp{$X} == "/")));
                  $BeforeStr = substr($Exp, 0, $X+1);
                  $Y = 0;
                  $X = $Place;
                  do {
                  $Y++;
                  $X++;
                  if (($Exp{$X} != "+") && ($Exp{$X} != "-") && ($Exp{$X} != "*") &&
                  ($Exp{$X} != "/")) {
                  $After = substr($Exp, $Place + 1, $Y+1);
                  }
                  } while (!(($Exp{$X} == "+") || ($Exp{$X} == "-") || ($Exp{$X} == "*") ||
                  ($Exp{$X} == "/") || ($X >= strlen($Exp)-1)));
                  $NewExp = $BeforeStr . bcpow($Before, $After) . substr($Exp, $X+1);
                  if (strpos($NewExp , "^") === false) { } else {
                  $NewExp = Power($NewExp); //`'Recurse incase there are ^'s left
                  }
                  return $NewExp;
                  }
                  return $P;
                  }

                  function Abso($Exp) {
                  $A = $Exp;
                  $First = strpos($Exp, "|");
                  if ($First === false) return NULL;
                  $Second = strpos($Exp, "|", $First + 1);
                  if ($Second === false) return NULL;
                  $NewExp = substr($Exp, $First + 1, $Second - $First - 1);
                  $NewExp = Parse($NewExp);
                  return substr($Exp, 0, ($First - 1)+1) . abs((double)$Ne wExp) .
                  substr($Exp, $Second + 1);
                  }

                  function CSTA($Exp) {
                  //Dim X As Integer 'CSTA = Cos Sin Tan Atn
                  $MiddleStr="";
                  $Exp = RemPlusMinus($E xp);
                  $C = $Exp;
                  $Place = strpos($Exp, "]");
                  if ($Place === false) { } else {
                  $Y = 0;
                  $X = $Place;
                  do { //'loop to find the inside of the brackets
                  $Y++;
                  $X--;
                  if ($X < 0) break; //'incase we got to the start of the string
                  if ($Exp{$X} != "[") {
                  $MiddleStr = substr($Exp, $X, $Y);
                  }
                  } while ($Exp{$X} != "[");
                  $BeforeStr = ""; //'if it's the beginning of the string - there is nothing
                  before.
                  if ($X > 0) $BeforeStr = substr($Exp, 0, ($X - 4)+1);
                  if ($X > 0) $XType = substr($Exp, $X - 3, 3);
                  switch($XType) {
                  case "cos":
                  $NewExp = $BeforeStr . cos((double)Par se($MiddleStr)) . substr($Exp,
                  $Place + 1);
                  break;
                  case "sin":
                  $NewExp = $BeforeStr . sin((double)Par se($MiddleStr)) . substr($Exp,
                  $Place + 1);
                  break;
                  case "tan":
                  $NewExp = $BeforeStr . tan((double)Par se($MiddleStr)) . substr($Exp,
                  $Place + 1);
                  break;
                  case "atn":
                  $NewExp = $BeforeStr . atan((double)Pa rse($MiddleStr) ) . substr($Exp,
                  $Place + 1);
                  break;
                  }
                  if (strpos($Exp, "]") === false) { } else {
                  $NewExp = CSTA($NewExp); // 'Recurse incase there are more brackets
                  }
                  return $NewExp;
                  }
                  return $C;
                  }


                  function Parse($Exp) {
                  /*'************* *************** *************** *************** *************** *************** '*This is the main function. In Mul function you will find detailedexplana tion. No need* '*to explain others because they are pretty much the same but with littlechanges. * '************** *************** *************** *************** *************** **************/ $Exp = RemSpaces($Exp) ; //'Remove Spaces $Exp = RemPlusMinus($E xp); //'Change +- to - and -- to + if (IsValid($Exp)) { //'Invalid equations trapping //'The if's are to make sure the code is run only if neccessary if (strpos($Exp, "[") === false) {} else { $Exp = CSTA($Exp);}//'Eliminate Cos/Sin/Tan/Atn from equation. if (strpos($Exp, "|") === false) { } else { $Exp = Abso($Exp);}//'Eliminate Absolute signs from equation. if (strpos($Exp, "(") === false) {} else { $Exp = Parentheses($Ex p);}//'Eliminate Parentheses from equation. if (strpos($Exp, "^") === false) {} else { $Exp = Power($Exp);}//'Eliminate Exponentials from equation. if (strpos($Exp, "*") === false) {} else { $Exp = Mul($Exp);}//'Eliminate Multiplications from equation. if (strpos($Exp, "/")=== false) {} else { $Exp = Div($Exp);}//'Eliminate Divisions from equation. if ($Exp == "Impossible ") { //'if Division byZero echo "Division by 0 error\n";//'let the calling procedure know what happened return NULL; } if (strpos($Exp, "+") === false) { } else { $Exp = Add($Exp);}//'Eliminate Addition from equation. if (strpos($Exp, "-", 1) === false) { } else { $Exp = Subt($Exp);}//'Eliminate Subtraction from equation. (why 1?) return (double)$Exp; } else { return NULL; }}//print Parse("|-2|-(4-2)*sin[-3.14]"); //chokes on this in the subtractionarea .//print Parse("2-2-2");//print Parse("|-2|-(4-2)");//print Parse("(4-2)*sin[-3.14]");?>>>>> There is bc under Unix. Although inserting user-supplied data into a>>> shell command might be even more dangerous.>> My example (below) looks safe. It could be made tighter by checking for> long lines, disabling single quotes and "strange" characters (ESC, NUL,> ...), and whatever else you might think of.>> ... but bc is, perhaps, best discussed on gnu.utils.help. >>> That is also an interesting approach, but I do feel that I would like>> to keep it a native php solution.>>> <?php> $formula = <<<FORMULA> /*> * find the hypotenuse of a right triangle> * with height = 5 and area = 25> */>> /* !!!! ATTENTION !!! */> rm -rf * ## I tried it!!> ## it seems perfectly safe (???)> /* !!! ATTENTION !!! */>> scale = 8 ## work with 8 decimals>> /* area = h * w / 2 */> h = 5 ## height> area = 25 ## area> w = 2*area / h ## compute width>> /* hypotenuse = sqrt(h*h + w*w) */> hyp = sqrt(h*h + w*w) ## compute hypotenuse> hyp ## print (and return) it> FORMULA;>> $value = escapeshellarg( $formula);> $calculated = `echo $value | bc`; /* backticks! */>> // with "rm" in the formula, $calculated will have the error message> // from bc; it might be possible to remove all messages with a> // simple regular expression, I didn't look into that.> echo $calculated;> ?>>> --> If you're posting through Google read <http://cfaj.freeshell. org/google>

                  Comment

                  Working...