tags:

views:

183

answers:

5

Possible Duplicate:
PHP: How To Disable Dangerous Functions

Hi, this is my situation: I must let my clients enter PHP code, but only safe functions like string function, date function etc. So I need the danger PHP functions list to remove them by using string replace before save to PHP file. Any suggestion?

+7  A: 

Forget it. Reliable function whitelisting is not possible in php. Example:

$x = 'e' . str_replace('y', 'x', 'yec');
...lots of code...
$x('format c:');

realistic options are

NullUserException
This answer is wrong and confusing. Reliable function blacklisting is impossible in php.
stereofrog
@stereofrog That's why I am not recommending it. Feel free to edit my answer to make it less confusing. I am terrible at explanations.
NullUserException
post edited....
stereofrog
Shouldn't that be "Reliable function **whitelisting** is impossible in PHP"? Because blacklisting is possible using disable_functions.
wimvds
@wimvds, just edit it, it's CW
stereofrog
Didn't notice that, I'll edit it then :p.
wimvds
+1  A: 

Giving users the possibility to enter PHP code is really dangerous. Consider all other options before implementing this. Some kind of PHP-code builder. Inspired on a Query builder.

If you decide to allow PHP code by the clients, it is better to use a whitelist. You should use regular expressions to extract these functions from the posted code.

Stegeman
PHP is not a regular language.
Gumbo
@Gumbo: Please explain what that has to do with this situation?
Stegeman
@Stegeman You can't use regular expressions on a language that's not regular.
NullUserException
Maybe I'm wrong, but he says enter, which, in my understanding, means that he will post the code. In that case the code is just a string and it is possible to use regular expressions on a string isn't it?If he wants to upload the code I know I'm wrong. Just trying to understand and learn a little :)
Stegeman
@Stegeman: Sure you can use regular expressions on strings. But the data in the string (i.e. PHP code) is not a regular language. Just think about removing the function call of `foobar` in a PHP code like this: `<?php echo "calling foobar()"; foobar();` Here you cannot simply use something like `/\bfoobar\s*\(\s*\)/` to find that function call.
Gumbo
@Gumbo, thanks for the lesson. +1 for that :)
Stegeman
+1  A: 

What you are expected to do is extremely hard work if you want to get it right. I would start by parsing the entered php code, checking each called function, disallowing backticks altogether, etc.

In other words: If you want to allow a sub-set of PHP you must implement your own lexer (even if PHP provides you a parser out of the box).

soulmerge
+2  A: 
Álvaro G. Vicario
+1 for mentioning disable_functions (which is the reliable way), -1 for tokenizing (which is useless at best).
stereofrog
+1, i dont understand why people tend to over complicate issues like these, over-compicating it wont make it safer, stick to the original methods such as `disable-functions` and `disable-classes`
RobertPitt
@stereofrog, I've figured out what you meant (you don't really say) and edited my post accordingly.
Álvaro G. Vicario
actually, this is not what i meant. No matter how you use the tokenizer, it's not possible to filter out function calls (think variable functions, 'call_user_func' etc)
stereofrog
PHP.net's token documentation is pretty lacking. They leave out certain tokens and also incorrectly define a few tokens--either that or their usage by `token_get_all()` and by PHP's warning/error messages are different, and they are going by the latter.
Lèse majesté
@stereofrog: of course, you're right about that. It's not even worth trying.
Álvaro G. Vicario
+2  A: 

The most secure and easy to maintain option will be to program a dedicated "mini-language" in php. You can make it a subset of php, or make it look like Excel formulas, or even invent your own one. This way you'll always have the full control of what's happening.

//

just for fun, here's a small Lisp for you

function lisp($x) {

    if(is_string($x)) {
        $re = '~\(([^()]*)\)~';
        while(preg_match($re, $x))
            $x = preg_replace_callback($re, 'lisp', $x);
        return trim($x);
    }

    $x = preg_split('~\s+~', $x[1]);
    $e = array_shift($x);
    if(!$x)
        return is_numeric($e) ?  floatval($e) : $e;

    switch($e) {
        case '+':  return lisp($x[0]) + lisp($x[1]);
        case '-':  return lisp($x[0]) - lisp($x[1]);
        case '*':  return lisp($x[0]) * lisp($x[1]);
        case '/':  return lisp($x[0]) / lisp($x[1]);

        case 'concat':  return lisp($x[0]) . lisp($x[1]);
    }

    return function_exists($e) ?
        call_user_func_array($e, array_map('lisp', $x)) : '';
}

$input = '
    (strtolower 
        (concat
            (strrev olleh) 
            (+ 22 20)))';

echo lisp($input); // hello42

;))

stereofrog
That's potentially a *lot* of work.
NullUserException
@NullUserException yeah, and a lot of fun as well ))
stereofrog
You could make a dynamic-scoped lisp-1. You don't have to tell them it's lisp. Or if you prefer, you could go get LIME for PHP and implement infix algebra, perhaps inside [square brackets] and make something that looks like TCL. Why does it have to look like PHP?
Ian
or You can write a parser of a subset of PHP in PHP and run only selected functions! :D
naugtur