Question

I'm trying to deploy my website on the Internet in order to test it in the real environment. It's some kind of text editor where users can use regular expressions and user-defined callback functions.

I have some problem with preg_replace_callback() function. My hosting has PHP version older than 5.3 and I cannot use anonymous function in my code (I have PHP 5.4 at localhost). So I have to rewrite this part of the code (which works correctly at localhost)

$newString = preg_replace_callback(
                    '#' . $this->pattern . '#' . $this->modifiers,
                    function($match)
                    {
                        return eval('return ' . $this->replacement . ';');
                    },
                    $string);

At this point I'm not talking about dangers of using eval() - this problem will be paid proper attention a bit later ("prohibited" word list check etc.). The problem is that my try below

$replacement = $this->replacement;
$newString = preg_replace_callback(
    '#' . $this->pattern . '#' . $this->modifiers,
    create_function('$match', '
                     global $replacement;
                     return eval(\'return \' . $replacement . \';\');
                    '),
                    $string);

does not work and no errors occur. What's wrong with my code?

Any help would be much appreciated.


New info. I've tried this

 Class A
{
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $modifiers = 'um';
        $replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
        $newString = preg_replace_callback(
                            '#' . $pattern . '#' . $modifiers,
                            create_function('$match', '
                             global $replacement;
                             echo $replacement;
                             return eval(\'return \' . $replacement . \';\');
                            '),
                            $string);
        echo $newString;
    }
}

$a = new A;
$a->check();//get nothing

and found out that $replacement inside create_function() is empty. But when I use the same create_function() outside the class $replacement is not empty:

$string = 'series 3-4';
$pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
$modifiers = 'um';
$replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
$newString = preg_replace_callback(
                '#' . $pattern . '#' . $modifiers,
                create_function('$match', '
                 global $replacement;
                 echo $replacement . "<br/>";
                 return eval(\'return \' . $replacement . \';\');
                '),
                $string);
echo $newString;
//$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"
//series 3 and 4
Was it helpful?

Solution

This works, inserting the $replacement string value properly formatted as PHP source into the source of the function:

function check()
{
    $string = 'series 3-4';
    $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
    $modifiers = 'um';
    $replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
    $newString = preg_replace_callback(
                        '#' . $pattern . '#' . $modifiers,
                        create_function('$match', '
                            return eval("return " . '.var_export($replacement,true).' . ";");
                        '),
                        $string);
    echo $newString;
}
check(); // prints "series 3 and 4"
?>

But why bother putting in code and evaling it, when you can just put it in the source of the function directly:

<?
function check()
{
    $string = 'series 3-4';
    $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
    $modifiers = 'um';
    $replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
    $newString = preg_replace_callback(
                        '#' . $pattern . '#' . $modifiers,
                        create_function('$match', '
                            return '.$replacement.';
                        '),
                        $string);
    echo $newString;
}
check(); // prints "series 3 and 4"
?>

OTHER TIPS

You may use a method in place of the lambda function:

Class A
{
    private $replacement;
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $this->replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
        $modifiers = 'um';
        $newString = preg_replace_callback(
                            '#' . $pattern . '#' . $modifiers,
                            array($this, 'replacementCallback'),
                            $string);
        echo $newString;
    }

    private function replacementCallback($match)
    {
        return eval('return ' . $this->replacement . ';');
    }
}

$a = new A;
$a->check();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top