eval

(PHP 4, PHP 5)

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 mustn't be wrapped in opening and closing PHP tags, i.e. 'echo "Hi!";' must be passed instead of '<? echo "Hi!"; >'. It is still possible to leave and reenter PHP mode though using the appropriate PHP tags, e.g. 'echo "In PHP mode!"; ?>In HTML mode!<? 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. If there is a parse error in the evaluated code, eval() returns FALSE and execution of the following code continues 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

add a note add a note

User Contributed Notes 28 notes

up
28
Anonymous
9 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
up
7
thomas at not dot my dot real dot domain dot com
23 days 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.
up
8
bohwaz
2 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.
up
1
Daniele Mams
1 month 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!
up
3
mahaixing at hotmail dot com
9 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();
?>
up
2
darkhogg (foo) gmail (bar) com
4 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 ' );
?>
up
1
php at stock-consulting dot com
5 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;
?>
up
1
jkuckartz1984 at hotmail dot com
8 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"
?>
up
1
Daniele Mams
1 month 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
up
0
xxx
15 days ago
test
up
0
sooncj
2 months 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;
}
?>
up
0
sc1n at yahoo dot com
2 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);
    }
}

?>
up
0
Mark Simon
3 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
up
0
1413 at blargh dot com
8 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).
up
0
francois at bonzon dot com
9 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!
up
0
evildictaitor at hotmail dot com
9 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.
up
-2
udo dot schroeter at gmail dot com
6 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 ;-)
up
-1
socram8888 at gmail dot com
2 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"
?>
up
-1
cmr at expansys dot com
4 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;
  }
?>
up
-1
maurice at chandoo dot de
5 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
up
-1
Anonymous
15 days ago
testing testing testing
up
-1
Anonymous
15 days ago
testing testing testing
up
-1
xxx
15 days ago
test
up
-1
xxx
15 days ago
test
up
-1
php at rijkvanwel dot nl
3 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;
}
?>
up
-1
marco at harddisk dot is-a-geek dot org
5 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!
up
-1
Ipseno at yahoo dot com
6 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 );

?>
up
-3
burninleo at gmx dot net
7 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 ...
}
To Top