preg_replace()引号内的引号

时间:2013-02-24 11:33:12

标签: php regex preg-replace

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

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抛出了后视错误: lookbehind断言在偏移量14处不是固定长度

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

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

3 个答案:

答案 0 :(得分:3)

如果您的字符串可以反序列化,请执行此操作,然后使用htmlspecialchars将引号(以及<>)替换为HTML实体。如果您要使用str_replace替换引号。


代码中的问题是有引号的事实!实际上,转义引号并不能解决你的问题。

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

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

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

如您所见,您有13个字符,而解析器只需要12个字符。这就是为什么你不能反序化它的原因!但是,这意味着您需要将12更改为13才能解决问题。

这究竟意味着什么? 无法使用正则表达式修复数据!您实际需要做的是修复向您发送无效数据的来源!

答案 1 :(得分: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);

我把它包装在一个数组中,因为如果你反序列化你所拥有的,你只能得到第一个元素的值......

答案 2 :(得分:-1)

preg_replace('|( "[0-9A-Z]+" )|ei', " stripslashes(htmlentities('$1')) ", $str)