5

I'm working on this old code, and ran across this - which fails:

preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $sObject);

It tells me that preg_replace e modifier is deprecated, and to use preg_replace_callback instead.

From what I understand, I am supposed to replace the 's:'.strlen('$2').':\"$2\";' part with a callback function that does the replacement on the match.

What I DON'T quite get, is exactly what the regexp is doing that I'll be replacing. It's part of a bit to take php serialized data stuffed in a database field (dumb, I know ...) with broken length fields and fix them for reinsertion.

So can anybody explain what that bit is doing, or what I should replace it with?

1 Answers1

8

Use

preg_replace_callback('!s:(\d+):"(.*?)";!', function($m) {
      return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
}, $sObject);

The !e modifier must be removed. $2 backreferences must be replaced with $m[2] where $m is a match object containing match value and submatches and that is passed to the anonymous function inside preg_replace_callback.

Here is a demo where the digits after s: get replaced with the $m[2] length:

$sObject = 's:100:"word";';
$res = preg_replace_callback('!s:(\d+):"(.*?)";!', function($m) {
      return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
}, $sObject);
echo $res; // => s:4:"word";
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Nice - a note to [use the return value of `preg_replace_callback()`](https://eval.in/515251) as the output – scrowler Feb 08 '16 at 21:31
  • I guess OP knows about string immutability. I will add a demo. – Wiktor Stribiżew Feb 08 '16 at 21:32
  • Yes, I'm using the return value as the output. So far, it looks like it's doing it's job, and this is the correct answer. There are other parts of the code that aren't working properly, namely that the serialized strings I'm jacking with appear to be multidimensional arrays. Whoever decided it was a good idea to stuff serialized php data into a database should be hung, stabbed, shot THEN killed! – user1632874 Feb 08 '16 at 22:04
  • How would i convert $content = preg_replace('/\{([A-Z_]+)\}/e', "$1", $content); to preg_replace_callback function? – João Costa May 05 '20 at 22:21
  • @JonnyDevv No need of callbacks, remove `e`. – Wiktor Stribiżew May 05 '20 at 22:38