Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

preg_replace() quotes within quotes

I have a PHP serialize()'d string coming from an external source:

s:4:"0.00";s:4:"type";s:5:"price";s:3:"$20";s:12:"Foo "Bar" Baz";s:1:"y";

I need to replace "Bar" with "Bar" in order to successfully unserialize().

How can I use preg_replace() to accomplish this?

I tried (?<!s:\d{1,4}:)("[0-9a-zA-Z ]+"), but PHP throws look-behind errors: lookbehind assertion is not fixed length at offset 14

Update: This is a dummy string that I made up. I incorrectly counted the characters... it's safe to assume the count is correct... the string should actually be:

s:4:"0.00";s:4:"type";s:5:"price";s:3:"$20";s:13:"Foo "Bar" Baz";s:1:"y";

like image 806
Jordan Arseno Avatar asked Jul 19 '26 18:07

Jordan Arseno


2 Answers

If your string can be deserialized do so and then use htmlspecialchars to replace the quotes (and also < and >) with HTML entities. If you want to replace only quotes use str_replace.


The problem in your code is not the fact that there are quotes! Actually, escaping the quotes will not solve your problem.

Let's look at the representation of the serialized string you have: s:12:"Foo "Bar" Baz";
This means you have a string containing 12 characters - quotes do not need to be escape in there at all.

Now what's the problem with the serialized data you have?

s:12:"Foo "Bar" Baz";
      1234567890123

As you can see, you have 13 characters while the parser expects only 12 characters. That's the reason why you cannot unserialize it! This however means that you need to change the 12 to 13 to fix it.

What does this actually mean? It is impossible to fix your data using a regular expression! What you actually need to do is fix the source which sends you invalid data!

like image 196
ThiefMaster Avatar answered Jul 22 '26 07:07

ThiefMaster


$string = preg_replace_callback('/(s:\d+:\")(.*?)(\";)/i', function($matches){
  return $matches[1] . htmlspecialchars($matches[2], ENT_QUOTES) . $matches[3];
}, $string);

(this will fail if you have semicolon following quotes in your string, like Foo "Bar"; Foo)


@ThiefMaster is right. An attempt to fully correct the string:

$keys = 0;
$string = preg_replace_callback('/s:(\d+):\"(.*?)\";/i',
  function($matches) use(&$keys){
    return sprintf('i:%d;s:%d:"%s";', ++$keys, strlen($matches[2]), $matches[2]);
  }, $string);

$string = sprintf('a:%d:{%s}', $keys, $string);
$result = unserialize($string);

I've wrapped this in an array, because if you unserialize what you have there, you only get the value of the first element...

like image 34
nice ass Avatar answered Jul 22 '26 07:07

nice ass