3

我有一个serialize()来自外部来源的 PHP 字符串:

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

我需要替换"Bar""Bar"才能成功unserialize()

我该如何使用preg_replace()来完成此操作?

我试过(?<!s:\d{1,4}:)("[0-9a-zA-Z ]+")了,但 PHP 抛出后视错误:后视断言在偏移 14 处不是固定长度

更新:这是我编的一个虚拟字符串。我错误地计算了字符......可以安全地假设计数是正确的......字符串实际上应该是:

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

4

3 回答 3

3

如果您的字符串可以反序列化,请这样做,然后用HTML 实体htmlspecialchars替换引号(以及<和)。>如果您只想替换引号,请使用str_replace.


您的代码中的问题在于有引号!实际上,转义引号并不能解决您的问题。

让我们看看您拥有的序列化字符串的表示形式:s:12:"Foo "Bar" Baz";
这意味着您有一个包含字符12字符串 - 引号根本不需要在其中转义。

现在您拥有的序列化数据有什么问题?

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!

于 2013-02-24T12:15:32.087 回答
1
$string = preg_replace_callback('/(s:\d+:\")(.*?)(\";)/i', function($matches){
  return $matches[1] . htmlspecialchars($matches[2], ENT_QUOTES) . $matches[3];
}, $string);

(如果字符串中的引号后面有分号,这将失败,例如Foo "Bar"; Foo


@ThiefMaster 是对的。尝试完全更正字符串:

$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);

我把它包装在一个数组中,因为如果你反序列化你在那里的东西,你只会得到第一个元素的值......

于 2013-02-24T12:01:11.237 回答
-1
preg_replace('|( "[0-9A-Z]+" )|ei', " stripslashes(htmlentities('$1')) ", $str)
于 2013-02-24T11:48:34.507 回答