smolo
smolo

Reputation: 869

PHP eval() - just one function

There's some PHP code assigned to one variable ($phpCode) that may contain a function called runjustthis() or/and any other php code.

I'm looking for a possibility to run just that function runjustthis() with eval().

In other words, how do I extract (with a regex?) the function runjustthis() from the string $phpCode and then call eval() on the extracted string?

Pseudo code:

$phpCode = "
 function runjustthis() {
   // some code here...
 }
 
 // maybe some more code here...
  // Don't execute that: 
  $something = '123'; 
  somethingElse();
";

$runjustthis = extractFunction("runjustthis", $phpCode); 
eval($runjustthis);

Upvotes: 3

Views: 214

Answers (2)

NineBerry
NineBerry

Reputation: 28499

The cleanest approach would be to use a PHP parser written in PHP to parse the text, then extract the function from the syntax tree created by the parser and execute it.

One example of a php parser writtein in php is https://github.com/nikic/PHP-Parser


Sample code:

<?php

$phpCode = <<<'CODE'
 <?php
 // Bla Bla
 $else = 'something';
 function donRunThis() {
   echo "Zonk";
 }

 function runjustthis() {
   // some code here...
   echo 42;
 }

 class X {

 }

  // maybe some more code here...
  // Don't execute that: 
  $something = '123'; 
  echo "Zonk";
  somethingElse();

  ?>
CODE;

// Function to extract the code from a function with the given name from the given php code.
function extractFunction($name, $phpCode)
{
    // Create parser and parse php code
    $parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
    $ast = $parser->parse($phpCode);

    // Find first function with the given name
    $nodeFinder = new PhpParser\NodeFinder;
    $func = $nodeFinder->findFirst($ast, function(PhpParser\Node $node) use ($name) 
    {
        // Node must be a function
        if($node instanceof PhpParser\Node\Stmt\Function_)
        {
            // and have the correct name
            if($node->name->toString() === $name)
            {
                return true;
            }
        }
        return false;
    });

    // If function was found
    if($func)
    {
        // Use pretty printer to get text representation of the statements in the function
        $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
        $funcCode = $prettyPrinter->prettyPrint($func->stmts);

        return $funcCode;
    }
}


$runjustthis = extractFunction("runjustthis", $phpCode); 
eval($runjustthis);

?>

Try it out at PHP Sandbox:

https://phpsandbox.io/n/super-base-mgkn-nbiyn

Upvotes: 0

TheFaultInOurStars
TheFaultInOurStars

Reputation: 3608

You do not need anything else. as the doc says:

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.

So you just need:

<?php
$phpCode = "
 function runjustthis() {
    return 'Hi';
 }
 
 function runjustthis2(){
     return 'working?';
 }
";

eval($phpCode);
echo runjustthis(). PHP_EOL;
echo runjustthis2();

Output

Hi
working?

But if you insists on getting only the function you want(part of $phpCode), so you can do this:

<?php
$phpCode = "
 function runjustthis() {
    return 'Hi';
 }
 
 function runjustthis2(){
     return 'working?';
 }
";
function extractFunction($functionName, $code){
    $pattern = "/function (?<functionName>$functionName+)\(\)(\s+)?\{[^\}]+\}/m";
    preg_match_all($pattern, $code, $matches);
    return($matches[0][0]);
}

$runjustthis = extractFunction("runjustthis", $phpCode); 
eval($runjustthis);
echo runjustthis();

This would only execute the runjustthis() function not other codes which wrote in $phpCode, so if we try runjustthis2() it will get this error:

PHP Fatal error:  Uncaught Error: Call to undefined function runjustthis2() in your/file/directory/file_name.php

Upvotes: 2

Related Questions