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";
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!
$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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With