PHP 7.0.6 Released

eval

(PHP 4, PHP 5, PHP 7)

evalEvaluate a string as PHP code

Description

mixed eval ( string $code )

Evaluates the given code as PHP.

Caution

The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.

Parameters

code

Valid PHP code to be evaluated.

The code must not be wrapped in opening and closing PHP tags, i.e. 'echo "Hi!";' must be passed instead of '<?php echo "Hi!"; ?>'. It is still possible to leave and re-enter PHP mode though using the appropriate PHP tags, e.g. 'echo "In PHP mode!"; ?>In HTML mode!<?php echo "Back in PHP mode!";'.

Apart from that the passed code must be valid PHP. This includes that all statements must be properly terminated using a semicolon. 'echo "Hi!"' for example will cause a parse error, whereas 'echo "Hi!";' will work.

A return statement will immediately terminate the evaluation of the code.

The code will be executed in the scope of the code calling eval(). Thus any variables defined or changed in the eval() call will remain visible after it terminates.

Return Values

eval() returns NULL unless return is called in the evaluated code, in which case the value passed to return is returned. As of PHP 7, if there is a parse error in the evaluated code, eval() throws a ParseError exception. Before PHP 7, in this case eval() returned FALSE and execution of the following code continued normally. It is not possible to catch a parse error in eval() using set_error_handler().

Examples

Example #1 eval() example - simple text merge

<?php
$string 
'cup';
$name 'coffee';
$str 'This is a $string with my $name in it.';
echo 
$str"\n";
eval(
"\$str = \"$str\";");
echo 
$str"\n";
?>

The above example will output:

This is a $string with my $name in it.
This is a cup with my coffee in it.

Notes

Note: Because this is a language construct and not a function, it cannot be called using variable functions.

Tip

As with anything that outputs its result directly to the browser, the output-control functions can be used to capture the output of this function, and save it in a string (for example).

Note:

In case of a fatal error in the evaluated code, the whole script exits.

See Also

User Contributed Notes

Anonymous
11 years ago
Kepp the following Quote in mind:

If eval() is the answer, you're almost certainly asking the
wrong question. -- Rasmus Lerdorf, BDFL of PHP
jg estiot at gmail dot com
2 years ago
Eval() is no more dangerous than allowing SQL injection or other security flaws within your scripts. I feel it is unfair to single out eval() as "dangerous" when it is as dangerous as many other features of the PHP language if misused.

I am writing a powerful PHP Framework and without eval() I could not implement some of its very best features.

With power comes responsibility and it is up to each of us to ensure that no unfiltered user input ever ends up in eval().
thomas at not dot my dot real dot domain dot com
2 years ago
eval() can easily be used in if-statements (in contrast to jkuckartz1984 at hotmail dot com): simply put a "return()" around the statement: if(eval('return($total'.$i.');')) ...

And in answer to the top-comment: I use eval() for my personal bug-fixes in e.g. open-source-software, where a function gets old code and new code as strings, so it can produce a bugreport (with some more added information) and the new code is evaled by eval(). Just a little overhead, but a nice way to keep all my changes together. So I think, there are some "right" questions where eval() is the (proper) answer.

At least I think, if you say "The eval() language construct is very dangerous because it allows execution of arbitrary PHP code." you just as well can say "PHP is very dangerous because it allows execution of arbitrary PHP code." The point is not to use any user provided data - that's all.
turboflash
8 months ago
Sharing a code which might be useful to someone. my_eval() is useful if
- You don't want to introduce new variables like what eval() would do.
- You just want to execute some calculations or some file/database retrieval and return the result.
- By returning the result in an array, you can differentiate a FALSE between a parse error or a result returned by the $code.

function my_eval($code) {
  $my_code = '$my_function = function () {' . $code . '}; return array($my_function());';

  return eval($my_code);
}
lord dot dracon at gmail dot com
9 months ago
Inception with eval()

<pre>
Inception Start:
<?php
eval("echo 'Inception lvl 1...\n'; eval('echo \"Inception lvl 2...\n\"; eval(\"echo \'Inception lvl 3...\n\'; eval(\'echo \\\"Limbo!\\\";\');\");');");
?>
Karel
1 year ago
For them who are facing syntax error when try execute code in eval,


<?php

$str
'<?php echo "test"; ?>';

eval(
'?>'.$str.'<?php;'); // outputs test
eval('?>'.$str.'<?'); // outputs test
eval('?>'.$str.'<?php');// throws syntax error - unexpected $end

?>
Experienced programmer
11 months ago
I have coding experience since 1980 since I was 13 years old (have programmed ALL/Most languages from Z80/6502/8080 upwards). I have owned technology and IT businesses since 1989.

eval is NO MORE dangerous than a 'user' having access to root  deleting the partition with fdisk (or any other command/statement/function).

It is all about proper design and engineering, and, control/policy. But we live in a 'freelance' world where anybody who can 'cut-and-paste' is a programmer working for the cheapest bidder (aka outsourcing).
bohwaz
4 years ago
If you want to allow math input and make sure that the input is proper mathematics and not some hacking code, you can try this:

<?php

$test
= '2+3*pi';

// Remove whitespaces
$test = preg_replace('/\s+/', '', $test);

$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
$functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|deg2rad|rad2deg|sqrt|ceil|floor|round)'; // Allowed PHP functions
$operators = '[+\/*\^%-]'; // Allowed math operators
$regexp = '/^(('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?2))?)+$/'; // Final regexp, heavily using recursive patterns

if (preg_match($regexp, $q))
{
   
$test = preg_replace('!pi|π!', 'pi()', $test); // Replace pi with pi function
   
eval('$result = '.$test.';');
}
else
{
   
$result = false;
}

?>

I can't guarantee you absolutely that this will block every possible malicious code nor that it will block malformed code, but that's better than the matheval function below which will allow malformed code like '2+2+' which will throw an error.
andrea at donboscoland dot it
2 years ago
Sorry, some corrections to my note... I've:
* removed the minus sign -? at the beginning and readded the |pi|π at the end like in previous examples;
* added some math functions;
* added the , in the operators: now it is possible to calculate pow(1,3) or rand(1,10);
* changed the $number definition to accept scientific notation like in:
http://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly

<?php
function calc($equation)
{
   
// Remove whitespaces
   
$equation = preg_replace('/\s+/', '', $equation);
    echo
"$equation\n";

   
$number = '((?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?|pi|π)'; // What is a number

   
$functions = '(?:sinh?|cosh?|tanh?|acosh?|asinh?|atanh?|exp|log(10)?|deg2rad|rad2deg
|sqrt|pow|abs|intval|ceil|floor|round|(mt_)?rand|gmp_fact)'
; // Allowed PHP functions
   
$operators = '[\/*\^\+-,]'; // Allowed math operators
   
$regexp = '/^([+-]?('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?1))?)+$/'; // Final regexp, heavily using recursive patterns

   
if (preg_match($regexp, $equation))
    {
       
$equation = preg_replace('!pi|π!', 'pi()', $equation); // Replace pi with pi function
       
echo "$equation\n";
        eval(
'$result = '.$equation.';');
    }
    else
    {
       
$result = false;
    }
    return
$result;
}
?>
1413 at blargh dot com
10 years ago
Just a note when using eval and expecting return values - the eval()'ed string must do the returning.  Take the following example script:

<?php

function ReturnArray()
{
  return array(
"foo"=>1, "bar"=>2);
}

$test = eval("ReturnArray();");
print(
"Got back $test (".count($test).")\n");

$test = eval("return ReturnArray();");
print(
"Got back $test (".count($test).")\n");

?>

You will get back:

Got back  (0)
Got back Array (2)

This ran me afoul for a little bit, but is the way eval() is supposed to work (eval is evaluating a new PHP script).
php at rijkvanwel dot nl
5 years ago
To catch a parse error in eval()'ed code with a custom error handler, use error_get_last() (PHP >= 5.2.0).

<?php
$return
= eval( 'parse error' );

if (
$return === false && ( $error = error_get_last() ) ) {
   
myErrorHandler( $error['type'], $error['message'], $error['file'], $error['line'], null );

   
// Since the "execution of the following code continues normally", as stated in the manual,
    // we still have to exit explicitly in case of an error
   
exit;
}
?>
evildictaitor at hotmail dot com
11 years ago
Be careful when using eval() on heavy usage sites in PHP 4.0+ as it takes vastly longer to activate due to the limitations of the Zend engine.

The Zend engine changes the PHP to a binary structure at the START of the file, and then parses it. Every time an eval is called, however, it has to reactivate the parsing procedure and convert the eval()'d code into usable binary format again.

Basically, if you eval() code, it takes as long as calling a new php page with the same code inside.
php at stock-consulting dot com
7 years ago
Magic constants like __FILE__ may not return what you expect if used inside eval()'d code. Instead, it'll answer something like "c:\directory\filename.php(123) : eval()'d code" (under Windows, obviously, checked with PHP5.2.6) - which can still be processed with a function like preg_replace to receive the filename of the file containing the eval().

Example:

<?php
$filename
= preg_replace('@\(.*\(.*$@', '', __FILE__);
echo
$filename;
?>
darkhogg (foo) gmail (bar) com
6 years ago
The following code

<?php
   
eval( '?> foo <?php' );
?>

does not throw any error, but prints the opening tag.
Adding a space after the open tag fixes it:

<?php
   
eval( '?> foo <?php ' );
?>
mahaixing at hotmail dot com
11 years ago
When using Dynamic Proxy design pattern we must create a class automaticly. Here is a sample code.

<?php
$clazz
= "class SomeClass { var \$value = 'somevalue'; function show() { echo get_class(\$this);}}";

eval(
$clazz);

$instance = new SomeClass;

// Here output 'somevalue';
echo $instance->value;

echo
"<br>";

//Here output 'someclass'
$instance->show();
?>
maurice at chandoo dot de
7 years ago
<?php
function safe_eval($code,&$status) { //status 0=failed,1=all clear
    //Signs
        //Can't assign stuff
   
$bl_signs = array("=");

   
//Language constructs
   
$bl_constructs = array("print","echo","require","include","if","else",
"while","for","switch","exit","break");   

   
//Functions
   
$funcs = get_defined_functions();
   
$funcs = array_merge($funcs['internal'],$funcs['user']);

   
//Functions allowed       
        //Math cant be evil, can it?
   
$whitelist = array("pow","exp","abs","sin","cos","tan");
   
   
//Remove whitelist elements
   
foreach($whitelist as $f) {
        unset(
$funcs[array_search($f,$funcs)]);   
    }
   
//Append '(' to prevent confusion (e.g. array() and array_fill())
   
foreach($funcs as $key => $val) {
       
$funcs[$key] = $val."(";
    }
   
$blacklist = array_merge($bl_signs,$bl_constructs,$funcs);
   
   
//Check
   
$status=1;
    foreach(
$blacklist as $nono) {
        if(
strpos($code,$nono) !== false) {
           
$status = 0;
            return
0;
        }
    }

   
//Eval
   
return @eval($code);
}
?>

Note: Try to include this after all of your other self-defined functions and consider whether the blacklist is appropriate for your purpose

I wouldn't recommend this function if you're going to use eval extensively in your script. However, it's worth a try if you are going to put user input into eval
jkuckartz1984 at hotmail dot com
10 years ago
Might you have to do eval in if statements, you will find it's quite some task to make it work.

The only way to make it work is to make a reference to the eval'd variable. This example will show the different usage of eval in if-statements. It simply becomes clear that an eval() in an if() is not working as you want to.

<?php
$total2
=5;
$total3=0;
$i=2;
if (eval(
"\$total".$i.";")) {
    echo
"eval: total2 is full<br>";
} else {
    echo
"eval: total2 is empty<br>";
}
// returns "empty"
// eval without the ";" will generate a warning

$str="\$refer=&\$total".$i.";";
eval(
$str);
if (
$refer) {
    echo
"eval: total2 is full<br>";
} else {
    echo
"eval: total2 is empty<br>";
}
// returns "full"
?>
Uther
2 months ago
eval'd code within namespaces which contain class and/or function definitions will be defined in the global namespace... not incredibly obvious :/
mickael at kodiom dot com
3 months ago
Runkit_Sandbox

Sandboxing class may be what you look for, but you need to compile your php with a special flag :
Sandboxing support requires that PHP (not just the extension mind you, but the main PHP bundle) be compiled with ZTS support enabled.
The configure switch would be --enable-maintainer-zts, not sure what gentoo calls this within it's USE flags.

Is there no native function like this one that can let programmer specify security context without having to compile back php ?

http://php.net/manual/en/runkit.sandbox.php
andrea at donboscoland dot it
2 years ago
with reference to the problem of mathematic equations validation
, as an operator is not a good idea... i've removed the comma from operators and added the optional group (,(?1))? to validate functions like pow(2,3)

$operators = '[\/*\^\+-]'; // Allowed math operators

$regexp = '/^([+-]?('.$number.'|'.$functions.'\s*\((?1)+(,(?1))?\)|\((?1)+\))(?:'.$operators.'(?1))?)+$/'; // Final regexp, heavily using recursive patterns
sc1n at yahoo dot com
4 years ago
If you would like to handle doing an eval on a string with mixed PHP and other stuff such as HTML, you can use the following:

Example:

<?php
$test_string
= 'A friendly llama <?php 1 == 1 ? "spit on" : "hugged"; ?> me';

$p = new PhpStringParser();
echo
$p->parse($mixed_string);
?>

Result:

A friendly llama spit on me

You can optionally make variables that are outside of the string you are parsing available to the eval level scope by passing them into the constructor.

Example:

<?php
$llama_action
= 'hugged';
$test_string = 'A friendly llama <?=$llama_action?> me';

$p = new PhpStringParser(array('llama_action', $llama_action));
echo
$p->parse($mixed_string);
?>

Result:

A friendly llama hugged me

<?php

class PhpStringParser
{
    protected
$variables;

    public function
__construct($variables = array())
    {
       
$this->variables = $variables;
    }

    protected function
eval_block($matches)
    {
        if(
is_array($this->variables) && count($this->variables) )
        {
            foreach(
$this->variables as $var_name => $var_value)
            {
                $
$var_name = $var_value;
            }
        }

       
$eval_end = '';

        if(
$matches[1] == '<?=' || $matches[1] == '<?php=' )
        {
            if(
$matches[2][count($matches[2]-1)] !== ';' )
            {
               
$eval_end = ';';
            }
        }

       
$return_block = '';

        eval(
'$return_block = ' . $matches[2] . $eval_end);

        return
$return_block;
    }

    public function
parse($string)
    {
        return
preg_replace_callback('/(\<\?=|\<\?php=|\<\?php)(.*?)\?\>/', array(&$this, 'eval_block'), $string);
    }
}

?>
socram8888 at gmail dot com
4 years ago
It may be a bit obvious, but if you don't want eval'd code to interfere with main code variables, all you have to do is to call an eval from another function like this:

<?php
function localeval($code) {
    return eval(
$code);
};

$a = "a";
echo
'$a before eval code: ' . $a . "\n"; // prints "a"
localeval('$a = \'b\';');
echo
'$a after localeval: ' . $a . "\n"; // still prints "a"
eval('$a = \'b\';');
echo
'$a after eval: ' . $a . "\n"; // prints "b"
?>
Mark Simon
5 years ago
I have looked for a simple way of forcing PHP to interpolate strings after the event (that is, after they have already been assigned, say from a text file).

The following seems to work:

<?php
    $text
='$a + $b = $c';
   
$a=2; $b=3; $c=$a+$b;
    print eval(
"return<<<END\n$text\nEND;\n");
?>

I have even tried it with some potentially evil code, but the context seems to preclude interpreting it as anything other than a string.

Mark
cmr at expansys dot com
6 years ago
Fixed matheval function when percentage is less than 10:

<?php
function matheval($equation)
  {
   
$equation = preg_replace("/[^0-9+\-.*\/()%]/","",$equation);
   
// fix percentage calcul when percentage value < 10
   
$equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation);
   
// calc percentage
   
$equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation);
   
// you could use str_replace on this next line
    // if you really, really want to fine-tune this equation
   
$equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation);
    if (
$equation == "" )
    {
     
$return = 0;
    }
    else
    {
      eval(
"\$return=" . $equation . ";" );
    }
    return
$return;
  }
?>
marco at harddisk dot is-a-geek dot org
7 years ago
eval does not work reliably in conjunction with global, at least not in the cygwin port version.

So:
<?PHP
class foo {
 
//my class...
}
function
load_module($module) {
  eval(
"global \$".$module."_var;");
  eval(
"\$".$module."_var=&new foo();");
 
//various stuff ... ...
}
load_module("foo");
?>

becomes to working:

<?PHP
class foo {
 
//my class...
}
function
load_module($module) {
  eval(
'$GLOBALS["'.$module.'_var"]=&new foo();');
 
//various stuff ... ...
}
load_module("foo");
?>

Note in the 2nd example, you _always_ need to use $GLOBALS[$module] to access the variable!
Ipseno at yahoo dot com
8 years ago
If you attempt to call a user defined function in eval() and .php files are obfuscated by Zend encoder, it will result in a fatal error.

Use a call_user_func() inside eval() to call your personal hand made functions.

This is user function
<?php

function square_it($nmb)
{
    return
$nmb * $nmb;
}

?>

//Checking if eval sees it?
<?php

$code
= var_export( function_exists('square_it') );

eval(
$code );    //returns TRUE - so yes it does!

?>

This will result in a fatal error:
PHP Fatal error:  Call to undefined function square_it()
<?php

$code
= 'echo square_it(55);' ;

eval(
$code );

?>

This will work
<?php

$code
= 'echo call_user_func(\'square_it\', 55);' ;

eval(
$code );

?>
udo dot schroeter at gmail dot com
8 years ago
Safer Eval

eval() is used way to often. It slows down code, makes it harder to maintain and it created security risks. However, sometimes, I found myself wishing I could allow some user-controlled scripting in my software, without giving access to dangerous functions.

That's what the following class does: it uses PHP's tokenizer to parse a script, compares every function call against a list of allowed functions. Only if the script is "clean", it gets eval'd.

<?php
 
class SaferScript {
    var
$source, $allowedCalls;
   
    function
SaferScript($scriptText) {
     
$this->source = $scriptText;
     
$this->allowedCalls = array();     
    }
 
    function
allowHarmlessCalls() {
     
$this->allowedCalls = explode(',',
       
'explode,implode,date,time,round,trunc,rand,ceil,floor,srand,'.
       
'strtolower,strtoupper,substr,stristr,strpos,print,print_r');   
    }
   
    function
parse() {
     
$this->parseErrors = array();
     
$tokens = token_get_all('<?'.'php '.$this->source.' ?'.'>');   
     
$vcall = '';
     
      foreach (
$tokens as $token) {
        if (
is_array($token)) {
         
$id = $token[0];
          switch (
$id) {
            case(
T_VARIABLE): { $vcall .= 'v'; break; }
            case(
T_STRING): { $vcall .= 's'; }
            case(
T_REQUIRE_ONCE): case(T_REQUIRE): case(T_NEW): case(T_RETURN):
            case(
T_BREAK): case(T_CATCH): case(T_CLONE): case(T_EXIT):
            case(
T_PRINT): case(T_GLOBAL): case(T_ECHO): case(T_INCLUDE_ONCE):
            case(
T_INCLUDE): case(T_EVAL): case(T_FUNCTION): {
              if (
array_search($token[1], $this->allowedCalls) === false)
               
$this->parseErrors[] = 'illegal call: '.$token[1];
            }           
          }
        }    
        else
         
$vcall .= $token;
      }
     
      if (
stristr($vcall, 'v(') != '')
       
$this->parseErrors[] = array('illegal dynamic function call');
     
      return(
$this->parseErrors);
    }
 
    function
execute($parameters = array()) {
      foreach (
$parameters as $k => $v)
        $
$k = $v;
      if (
sizeof($this->parseErrors) == 0)
        eval(
$this->source);
      else
        print(
'cannot execute, script contains errors');
    } 
  }
?>

Usage example:
<?php
  $ls
= new SaferScript('horribleCode();');
 
$ls->allowHarmlessCalls();
 
print_r($ls->parse());
 
$ls->execute();
?>

Of course it is not entirely safe, but it's a start ;-)
Daniele Mams
2 years ago
This is another function that return true if $formula is a syntactically valid Math function, false otherwise.

NDR.
1) It not allows %, pi|π.
2) It allows this Math functions:
abs, atan, ceil, cot, cos, exp, gmp_fact, intval, sin, sqrt, tan, log, log10, rand, round.

I write it on pastebin.com because php.net not allow me to post long code.
enjoy it! :-)
http://pastebin.com/EgwV7QdK
Daniele Mams
2 years ago
Modified version of sooncj answer: your regex not allow something like this: 1-(1). So I modified your code: I change the 'Allowed PHP functions':

<?php
function calc($equation)
{
   
// Remove whitespaces
   
$equation = preg_replace('/\s+/', '', $equation);
    echo
"$equation\n";

   
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
   
$functions = '(?:abs|atan|ceil|cos|exp|gmp_fact|intval|log(10)?|rand|round|sin|sqrt|tan)'; // Allowed PHP functions
   
$operators = '[\/*\^\+-]'; // Allowed math operators
   
$regexp = '/^([+-]?('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?1))?)+$/'; // Final regexp, heavily using recursive patterns

   
if (preg_match($regexp, $equation))
    {
       
$equation = preg_replace('!pi|π!', 'pi()', $equation); // Replace pi with pi function
       
echo "$equation\n";
        eval(
'$result = '.$equation.';');
    }
    else
    {
       
$result = false;
    }
    return
$result;
}
?>

This function allow also this 'strange' math function:
1) a-+b
2) a+-b
3) a++b   << PHP not allow this
4) a--b.   << PHP not allow this

But not allow with 3 '+' or '-':
1) a---b, a+++b, a-++b, a+--b, a+-+b, a-+-b.

Allow other Math functions.

For a++b or a--b i write another function that block that!
andrea at donboscoland dot it
2 years ago
Modified version of Daniele Mams's answer: I change the $number definition to accept scientific notation like in:
http://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly

<?php
function calc($equation)
{
   
// Remove whitespaces
   
$equation = preg_replace('/\s+/', '', $equation);
    echo
"$equation\n";

   
$number = '(-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)'; // What is a number

   
$functions = '(?:abs|atan|ceil|cos|exp|gmp_fact|intval|log(10)?|rand|round|sin|sqrt|tan)'; // Allowed PHP functions
   
$operators = '[\/*\^\+-]'; // Allowed math operators
   
$regexp = '/^([+-]?('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?1))?)+$/'; // Final regexp, heavily using recursive patterns

   
if (preg_match($regexp, $equation))
    {
       
$equation = preg_replace('!pi|π!', 'pi()', $equation); // Replace pi with pi function
       
echo "$equation\n";
        eval(
'$result = '.$equation.';');
    }
    else
    {
       
$result = false;
    }
    return
$result;
}
?>
francois at bonzon dot com
11 years ago
An obvious security reminder, which I think wasn't yet mentioned here. Special care is required when variables entered by the user are passed to the eval() function. You should validate those user inputs, and really make sure they have the format you expect.

E.g., if you evaluate math expressions with something like

<?php
 
eval("\$result = $equation;");
?>

without any check on the $equation variable, a bad user could enter in the $equation field

""; echo file_get_contents('/etc/passwd')

- or whatever PHP code he wants! - which would evaluate to

<?php
  $result
= ""; echo file_get_contents('/etc/passwd');
?>

and seriously compromising your security!
burninleo at gmx dot net
9 years ago
The only way to retreive information on parse errors in eval'd code seems to be the output buffering.

<?PHP
// Append a return true to php-code to check on errors
$code.= "\nreturn true;";
// Send any output to buffer
ob_start();
// Do eval()
$check = eval($code);
$output = ob_get_contents();
ob_end_clean();
// Send output or report errors
if ($check === true) {
  echo
$output;
} else {
 
// Manually parse output for errors and
  // generate usable information for the user
  // especially content of error-lines.
 
$pattern = '/^\s*Parse error\s*:(.+) in (.+) on line (\d+)\s*$/m';
 
etc ...
}
sooncj
2 years ago
Modified version of bohwaz's answer: with negative number support and removes the requirement of properly grouped (bracketed) expressions.

<?php
function calc($equation)
{
   
// Remove whitespaces
   
$equation = preg_replace('/\s+/', '', $equation);
    echo
"$equation\n";

   
$number = '(?:-?\d+(?:[,.]\d+)?|pi|π)'; // What is a number
   
$functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|deg2rad|rad2deg|sqrt|ceil|floor|round)'; // Allowed PHP functions
   
$operators = '[+\/*\^%-]'; // Allowed math operators
   
$regexp = '/^(('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?1))?)+$/'; // Final regexp, heavily using recursive patterns

   
if (preg_match($regexp, $equation))
    {
       
$equation = preg_replace('!pi|π!', 'pi()', $equation); // Replace pi with pi function
       
echo "$equation\n";
        eval(
'$result = '.$equation.';');
    }
    else
    {
       
$result = false;
    }
    return
$result;
}
?>
To Top