Tader
Tader

Reputation: 26862

How find the source code for an eval'd function in PHP?

I am trying to find a way to get the source code for (user defined) PHP functions in a string.

For normal code this is easy, using reflection I can find the file and line numbers where the function is defined; then I can open the file and read the function source code.

This will not work if a function is defined in eval'd code. I do not want to keep record of all eval'd code.

Is this possible? If yes, then how?

Example code:

function myfunction() {
    echo "Test";
}
eval('
  function myevalfunction() {
    echo "Test";
  }
');

$a = new ReflectionFunction('myfunction');
echo $a;

$b = new ReflectionFunction('myevalfunction');
echo $b;

Output:

Function [ <user> <visibility error> function myfunction ] {
  @@ test.php 3 - 5
}
Function [ <user> <visibility error> function myevalfunction ] {
  @@ test.php(11) : eval()'d code 2 - 4
}

Upvotes: 0

Views: 3511

Answers (4)

Black Mantha
Black Mantha

Reputation: 1285

If you want to find the source code, even in a debugger, you can define your own eval() function which works with temporary files:

function my_eval($code) {
  $file = << TEMP-DIR >> . '/' . md5($code) . '.php';
  if (!file_exists($file)) {
    file_put_contents($file, "<?php\n" . $code);
  }
  return require($file);
}

In fact, I think that if you call this function eval and put it in the default namespace, most eval() calls in the code will call this function instead.

Upvotes: 1

rebra
rebra

Reputation: 1078

How about you define your own eval-function, and do the tracking there?

function myeval($code) {
     my_eval_tracking($code, ...);  # use traceback to get more info if necessary
     # (...)
     return eval($code);
}

That said, I do share a lot of Kent Fredric's feelings on eval in this case.

Upvotes: 1

Kent Fredric
Kent Fredric

Reputation: 57374

My initial response is to say there's virtually 0 good reason to create a function in eval.

You can create functions conditionally, ie:

if ( $cond ){ 
   function foo(){ 

   }
}

If you want closure like behaviour I guess eval is the only way to do it until PHP5.3, but its EPIC bad stuff and you should avoid it all cost.

Here is why:


01 <?php
02 
03 function foo ()
04 {
05   eval( '
06     function baz()
07     {
08        eval("throw new Exception();"); 
09     }
10   '); 
11   baz(); 
12 }
13 
14 
15 
16 try{ 
17   foo(); 
18 }catch( Exception $e ){
19   var_dump($e); 
20 }
21 try{ 
22   foo(); 
23 }
24 catch( Exception $e ){
25   var_dump($e);
26 }

Which Emits this:



object(Exception)#1 (6) {
  ["message:protected"]=>
  string(0) ""
  ["string:private"]=>
  string(0) ""
  ["code:protected"]=>
  int(0)
  ["file:protected"]=>
  string(50) "/tmp/xx.php(10) : eval()'d code(4) : eval()'d code"
  ["line:protected"]=>
  int(1)
  ["trace:private"]=>
  array(3) {
    [0]=>
    array(3) {
      ["file"]=>
      string(31) "/tmp/xx.php(10) : eval()'d code"
      ["line"]=>
      int(4)
      ["function"]=>
      string(4) "eval"
    }
    [1]=>
    array(4) {
      ["file"]=>
      string(11) "/tmp/xx.php"
      ["line"]=>
      int(11)
      ["function"]=>
      string(3) "baz"
      ["args"]=>
      array(0) {
      }
    }
    [2]=>
    array(4) {
      ["file"]=>
      string(11) "/tmp/xx.php"
      ["line"]=>
      int(17)
      ["function"]=>
      string(3) "foo"
      ["args"]=>
      array(0) {
      }
    }
  }
}

Fatal error: Cannot redeclare baz() (previously declared in /tmp/xx.php(10) : eval()'d code:2) in /tmp/xx.php(10) : eval()'d code on line 5

Call Stack:
    0.0002     115672   1. {main}() /tmp/xx.php:0
    0.0006     122304   2. foo() /tmp/xx.php:22

So much badness, so little effort.

Upvotes: 1

OIS
OIS

Reputation: 10033

You cant just search through the files yourself? grep or wingrep is perfect for this.

If not you can try the pecl function rename_function and log all the eval calls which create functions.

Upvotes: 1

Related Questions