• PHP Help
  • Need help understanding /e deprication

Hello there!

A recent server upgrade caused my forum to break and I'm reading up on the issue but I don't understand the suggestion to convert /e to a preg-match callback.

The error:

preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead

The code in question:

preg_match_all("/(<img\/?[^>]*?\/>)/e", $display_text, $images);

Could someone explain to me what I should be doing to bring this code into the 21st century?

Thanks for your time!

    It does not look to me like your code is using a callback function, so I think either that e modifier is not needed, or it was actually a typo and supposed to be some other modifier (such as /i for case-insensitive, perhaps?).

      Wait...the error message is talking about preg_replace(), but the code you showed us is using preg_match_all(). I'm not sure if it ever made sense to use /e for match or not? 😕

        I'm so sorry Nog. That's my fault. The error is springing up in a myriad of places and my copy and paste correlated to another error.

        The error above:

        preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead

        correlates to this:

        $bbcode_tpl = preg_replace('/{L_([A-Z_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $bbcode_tpl);

        I found what was touted as a solution that I've plugged in to get rid of the error:

        $bbcode_tpl = preg_replace_callback('/{L_([A-Z0-9_]+)}/', function ($m) { return (!empty($user->lang['\$m[1]'])) ? $user->lang['\$m[1]'] : ucwords(strtolower(str_replace('_', ' ', '\$m[1]'))); }, $tpl);

        I don't understand how it works though, so I'm unable to duplicate this fix for the other errors. For instance, this is the most prevalent now:

        preg_match_all(): The /e modifier is no longer supported, use preg_replace_callback instead

        preg_match_all("/(<img\/?[^>]*?\/>)/e", $display_text, $images);

        I've tried to guess my way through the conversion and I'm reading my butt off but I just don't understand how to modify this to work.

          The "/e" modifier means you intend to use a "callback function" -- which only makes sense for a replace function. It was probably being silently ignored in your prior version, but now is triggering that deprecation error. Just removing that final "e" will probably get that particular preg_match_all() running fine.

            Thank you very much, I removed the e and removed the error. I've squashed a few more as well but I'm perplexed by this. I'm getting the same error but the function doesn't seem to be utilizing the e at all:

            error:

            on line <b>112</b>: <b>preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead

            code(line 112 marked):

            		$str = array('search' => array(), 'replace' => array());
            		$preg = array('search' => array(), 'replace' => array());
            
            	$bitfield = new bitfield($this->bbcode_bitfield);
            	$bbcodes_set = $bitfield->get_all_set();
            
            	$undid_bbcode_specialchars = false;
            	foreach ($bbcodes_set as $bbcode_id)
            	{
            		if (!empty($this->bbcode_cache[$bbcode_id]))
            		{
            			foreach ($this->bbcode_cache[$bbcode_id] as $type => $array)
            			{
            				foreach ($array as $search => $replace)
            				{
            					${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search);
            					${$type}['replace'][] = $replace;
            				}
            
            				if (sizeof($str['search']))
            				{
            					$message = str_replace($str['search'], $str['replace'], $message);
            					$str = array('search' => array(), 'replace' => array());
            				}
            
            				if (sizeof($preg['search']))
            				{
            					// we need to turn the entities back into their original form to allow the
            					// search patterns to work properly
            					if (!$undid_bbcode_specialchars)
            					{
            						$message = str_replace(array('&#58;', '&#46;'), array(':', '.'), $message);
            						$undid_bbcode_specialchars = true;
            					}
            
            					$message = preg_replace($preg['search'], $preg['replace'], $message); // THIS IS LINE 112
            					$preg = array('search' => array(), 'replace' => array());
            				}
            			}
            		}
            	}
            
            	// Remove the uid from tags that have not been transformed into HTML
            	$message = str_replace(':' . $this->bbcode_uid, '', $message);
            }
            

            It doesn't look like the previous examples so I'm not sure how to modify. Maybe it's found in other parts of the code that is then getting pulled in?

              It might be useful to see what's actually getting passed in to that call, maybe something like:

                      // DEBUG ONLY, THEN DELETE:
                      die("<pre>DEBUG:\n".var_export($preg, 1)."</pre>"); // just for debugging, then delete!!!
                      $message = preg_replace($preg['search'], $preg['replace'], $message); // THIS IS LINE 112
              

              Then we can see if the /e is actually needed, in which case you'd need to create the callback function then reference it by using preg_replace_callback() instead.

                Here's what I got as a result of the debug code:

                DEBUG:
                array (
                'search' =>
                array (
                0 => '#\[img:3ph6e7a7\](.*?)\[/img:3ph6e7a7\]#s',
                ),
                'replace' =>
                array (
                0 => 'Image',
                ),
                )

                  Hmm...no "e" is being used in that instance, only an "s" (they're using "#" as the regex limiter in that example). But it's in a loop, so maybe that one is fine but a later iteration is the problem. Looks like maybe you can get all the search/replace possibilities in $this->bbcode_cache if you really want to dig into it. (I.e. you could var_export() that and see what all is in it.) 🤷

                    A slightly tacky way to do it would be to put functions into the necessary entries in the source of $preg['replace']'s content, and use an is_callable check to decide whether to use preg_replace or preg_replace_callback.

                    Slightly less tacky is the way the code is already distinguishing between string replacements and regex replacements by grouping them into different "types". Another "type" for callback replacements perhaps?

                      I'm a bit perplexed as to where it's making this array utilize the e parameter. I did a search through the entire filesystem for /e and I didn't find any instances of it that it looks like it's building that array.

                      I really need to get better at this troubleshooting. Is there a better search parameter I should/could be using that would backtrace this array construction so I can see where it might be attaching the e flag?

                        It's coming from $this->bbcode_cache. Find out where that's getting initialised.

                          Write a Reply...