12

How do I create an anonymous function dynamically when I have function body in a string.

For e.g.

$user = "John Doe";
$body = "echo 'Hello' . $user;";

$myFunct = function($user) {$body}; // How do I have function body here from string.

$myFunct($user);

Any help would be much appreciated.

P.S. I'm looking for a replacement for create_function() functionality which was there in prior versions of PHP. Just like in create_function() where we could pass the function body as a string, I would like to define anonymous function's body off the string variable.

Aditya Hajare
  • 1,372
  • 1
  • 15
  • 24
  • 9
    with evil eval. _BUT_ if you think you need to do this, there's something wrong. – Jeff Sep 30 '18 at 15:04
  • I'm writing a custom code obfuscator for which this is needed. In prior versions of PHP, this was pretty straight forward with create_function(). I'm looking for a replacement in PHP 7.2 for create_function() functionality where we used to pass function body as a string. – Aditya Hajare Sep 30 '18 at 15:05
  • 2
    https://stackoverflow.com/a/951868/4830296 – Jeff Sep 30 '18 at 15:07
  • https://stackoverflow.com/a/43694834/2469308 – Madhur Bhaiya Sep 30 '18 at 15:10
  • 1
    It is unsafe for this and it has been removed. Read, please https://stackoverflow.com/a/642331/8352809 – Aro Oct 07 '18 at 12:20
  • You should consider encapsulating this in an object. Eval is not the answer. – Rafael Oct 07 '18 at 15:43
  • You can still use `create_function` in 7.2 - sure, it's deprecated so not recommended - but it's still there, for now. – Darragh Enright Oct 12 '18 at 11:56

6 Answers6

19

If you have explored all other options and are absolutely sure the only way to accomplish your goals is to define custom functions at runtime using code that's in a string, you have two alternatives to using create_function.

The quick solution is to just use eval:

function create_custom_function($arguments, $body) {
    return eval("return function($arguments) { $body };");
}

$myFunct = create_custom_function('$user', 'echo "Hello " . $user;');

$myFunct('John Doe');
// Hello John Doe

However, eval() can be disabled. If you need this sort of functionality even on servers where eval is not available, you can use the poor man's eval: write the function to a temporary file and then include it:

function create_custom_function($arguments, $body) {
    $tmp_file = tempnam(sys_get_temp_dir(), "ccf");
    file_put_contents($tmp_file, "<?php return function($arguments) { $body };");
    $function = include($tmp_file);
    unlink($tmp_file);

    return $function;
}

$myFunct = create_custom_function('$user', 'echo "Hello " . $user;');

$myFunct('John Doe');
// Hello John Doe

In all honesty though, I strongly recommend against these approaches and suggest you find some other way to accomplish your goal. If you're building a custom code obfuscator, you're probably better off creating a php extension where the code is de-obfuscated prior to execution, similar to how ionCube Loader and Zend Guard Loader work.

rickdenhaan
  • 10,857
  • 28
  • 37
  • 1
    "code is de-obfuscated prior to execution, similar to how ionCube Loader and Zend Guard Loader work" - this is not even close to how those extensions work :) ionCube and Zend protection works by compiling PHP to bytecode, protecting the bytecode, and executing the compiled code with an engine in the respective Loaders. For ionCube, code can also be encrypted with keys that are never stored, requiring the protected PHP application itself to produce decryption keys on demand in order to be able to decrypt and run further layers of the application. There's no PHP source in the encoded files :) – Nick Nov 04 '18 at 15:31
  • @Nick Wow, thanks for commenting! Your [post](https://stackoverflow.com/a/40139195/1941241) from a few years ago is an interesting look into ionCube. I stand corrected :) – rickdenhaan Nov 05 '18 at 19:39
2

You can use the callable type hint. Here is an example

function callThatAnonFunction(callable $callback) {
    return $callback();
}

It can take an anonymous function with any arg params:

$user = "person";
$location = "world";
callThatAnonFunction(function() use ($user, $location) {
    echo "Hello " . $user . " in " . $location;
});
Alaa Awad
  • 3,612
  • 6
  • 25
  • 35
2

You can try this:

$user = "John Doe";
$body = "echo 'Hello' . $user;";

$myFunct = function($user) {
    return $body;
}; 

echo $myFunct($user);
gauri
  • 121
  • 1
  • 3
  • 14
2

Well this is ugly and you shouldn't really do this, but you said in a comment that you're doing this for a code obfuscator so here are my 2 cents:

$args = '$user, $number';
$body = 'echo "#$number: Hello $user.\n";';

function _create_function_without_eval($args, $body) {
    $func_name = sprintf('temp_func_%s', md5($body));
    $code = sprintf("<?php if (!function_exists('%s')) {function %s(%s){%s}}", $func_name, $func_name, $args, $body);
    $func_file = tempnam('/tmp', $func_name);
    $handle = fopen($func_file, "w+");
    fwrite($handle, $code);
    fclose($handle);
    include $func_file;
    unlink($func_file);
    return function(...$user_args) use ($func_name) {
      return call_user_func_array($func_name, $user_args); 
    };
}

function _create_function_with_eval($args, $body) {
    $func_name = sprintf('temp_func_%s', md5($body));
    $code = sprintf("if (!function_exists('%s')) {function %s(%s){%s}}", $func_name, $func_name, $args, $body);
    eval($code);
    return function(...$user_args) use ($func_name) {
      return call_user_func_array($func_name, $user_args); 
    };
}

$fn_deprecated = create_function($args, $body);
$fn_with_eval = _create_function_with_eval($args, $body);
$fn_without_eval = _create_function_without_eval($args, $body);

echo $fn_deprecated('Old Bob', '1');
echo $fn_without_eval('Bob without eval', 2);
echo $fn_with_eval('Bob with eval', 3);

See it live here: https://3v4l.org/urQ4k

mrbm
  • 2,164
  • 12
  • 11
1

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.

so Eval is the worst replacement, create_function is depreicated because of using eval.

use anonymous functions for adiinviter pro.

$b  = function () use ($d,$f1,$c,$ps){
            return gzinflate( base64_decode(str_rot13($ps) ) );
        };
olissongs
  • 63
  • 1
  • 6
-3

PHP developers love you hahaha look here

$user = "John Doe";
$body = 'echo "Hello " . $a;';
$f = create_function('$a', $body);

$f($user);

//out : Hello John Doe

Documentation PHP official : create_function(string $args,string $code)