Search code examples
phparrayspreg-replacedeprecatedpreg-replace-callback

preg_replace The /e modifier is deprecated using arrays as pattern and replacement


I used to have this block of code to simulate some sort of BBCode:

$pattern = array(
    '/\\n/',
    '/\\r/',
    '/\[list\](.*?)\[\/list\]/ise',
    '/\[b\](.*?)\[\/b\]/is',
    '/\[strong\](.*?)\[\/strong\]/is',
    '/\[i\](.*?)\[\/i\]/is',
    '/\[u\](.*?)\[\/u\]/is',
    '/\[s\](.*?)\[\/s\]/is',
    '/\[del\](.*?)\[\/del\]/is',
    '/\[url=(.*?)\](.*?)\[\/url\]/ise',
    '/\[email=(.*?)\](.*?)\[\/email\]/is',
    '/\[img](.*?)\[\/img\]/ise',
    '/\[color=(.*?)\](.*?)\[\/color\]/is',
    '/\[font=(.*?)\](.*?)\[\/font\]/ise',
    '/\[bg=(.*?)\](.*?)\[\/bg\]/ise',
    '/\[size=(.*?)\](.*?)\[\/size\]/ise'
);

$replace = array(
    '<br/>',
    '',
    '$this->sList(\'\\1\')',
    '<b>\1</b>',
    '<strong>\1</strong>',
    '<i>\1</i>',
    '<span style="text-decoration: underline;">\1</span>',
    '<span style="text-decoration: line-through;">\1</span>',
    '<span style="text-decoration: line-through;">\1</span>',
    '$this->urlfix(\'\\1\',\'\\2\')',
    '<a href="mailto:\1" title="\1">\2</a>',
    '$this->imagefix(\'\\1\')',
    '<span style="color: \1;">\2</span>',
    '$this->fontfix(\'\\1\',\'\\2\')',
    '$this->bgfix(\'\\1\',\'\\2\')',
    '$this->sizefix(\'\\1\',\'\\2\')'
);

return preg_replace($pattern, $replace, nl2br(stripslashes($string)));

But I'm moving to PHP 5.5 and I'm getting errors here, it used to work perfectly, this is the erros I'm getting:

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in

I tried several stuff but nothing worked so far.

This is the code I tried so far:

return preg_replace_callback(
    $pattern,
    function($matches) use ($replace) {
        return ((isset($replace[$matches[0]])) ? $replace[$matches[0]] : '');
    },
    nl2br(stripslashes($string))
);

I have been reading around but most examples are related to basic replacements, here I have two arrays.

Please notice that there are some methods that are being called from the $replace area.

How can I solve this? Is this the right approach?


Solution

  • After a lot of work and testings and reading I came out with a solution for this, I hope it can help someone else.

    Here is my solution to replace bbcode:

    $bbcodes    = [
        '/\\n/' => '$this->setLineJump()',
        '/\\r/' => '$this->setReturn()',
        '/\[list\](.*?)\[\/list\]/is' => '$this->setList(\'\\1\')',
        '/\[b\](.*?)\[\/b\]/is' => '$this->setBold(\'\\1\')',
        '/\[strong\](.*?)\[\/strong\]/is' => '$this->setBold(\'\\1\')',
        '/\[i\](.*?)\[\/i\]/is' => '$this->setItalic(\'\\1\')',
        '/\[u\](.*?)\[\/u\]/is' => '$this->setUnderline(\'\\1\')',
        '/\[s\](.*?)\[\/s\]/is' => '$this->setStrike(\'\\1\')',
        '/\[del\](.*?)\[\/del\]/is' => '$this->setStrike(\'\\1\')',
        '/\[url=(.*?)\](.*?)\[\/url\]/is' => '$this->setUrl(\'\\1\',\'\\2\')',
        '/\[email=(.*?)\](.*?)\[\/email\]/is' => '$this->setEmail(\'\\1\',\'\\2\')',
        '/\[img](.*?)\[\/img\]/is' => '$this->setImage(\'\\1\')',
        '/\[color=(.*?)\](.*?)\[\/color\]/is' => '$this->setFontColor(\'\\1\',\'\\2\')',
        '/\[font=(.*?)\](.*?)\[\/font\]/is' => '$this->setFontFamiliy(\'\\1\',\'\\2\')',
        '/\[bg=(.*?)\](.*?)\[\/bg\]/is' => '$this->setBackgroundColor(\'\\1\',\'\\2\')',
        '/\[size=(.*?)\](.*?)\[\/size\]/is' => '$this->setFontSize(\'\\1\',\'\\2\')'
    ];
    
    $string = stripslashes($string);
    
    foreach ($bbcodes as $bbcode => $html) {
        $string = preg_replace_callback(
            $bbcode,
            function($matches) use($html) {
                return $this->getBbCode($matches, $html);
            },
            $string
        );
    }
    
    private function getBbCode($matches, $replace)
    {
        if (isset($matches[1])) {
    
            $replacements   = [
                '\1' => isset($matches[1]) ? $matches[1] : '',
                '\2' => isset($matches[2]) ? $matches[2] : ''
            ];
    
            return eval('return ' . strtr($replace, $replacements) . ';');   
        } else {
    
            return eval('return ' . $replace . ';');   
        }
    }
    

    As you can see I'm using objects but you can replace them by your own functions. What really matters here is that you can replace element by element, just making some changes in your arrays.