关于php:preg_match_all突然停止在文本中查找事件

preg_match_all suddenly ceased to find occurrences in text

我有一些代码可以通过使用preg_match_all在电子邮件正文中查找发生的事件。像这样:

1
2
3
4
$sHrefPattern ="<(a|area)\s*.*(unsubscribe_url\s*=\s*?)(["\']??)([^">]*?)";
if (preg_match_all("/$sHrefPattern/siU", $sHtmlBody, $aMatches, PREG_SET_ORDER)) {
    // do smth ...
}

和类似内容(可以包含俄语文本出现):

1
2
3
4
5
6
7
8
... <td align="left" colspan="3" height="22" valign="center">
   
        Unsubscribe
     |
   
        Advertisement in emails
   
</td> ...

很长一段时间以来,这个代码工作得很好。但有一天,这个代码停止正常工作。我认为它与一些程序包安装相关,但我不知道安装了哪个程序包。此代码所在的服务器在我们的团队中具有共享访问权限。有什么想法吗?

1
2
uname -a
Linux ourhost 2.6.32-042stab076.8 #1 SMP Tue May 14 20:38:14 MSK 2013 i686 i686 i386    GNU/Linux


我认为你睡着的时候,坏人已经编辑了你的模式,幸运的是,我建议你测试一下这个模式来取代旧模式:

1
2
3
4
$sHrefPattern ="rea)?\b(?>[^u]++|u++(?!nsubscribe_url\b))+"
               ."unsubscribe_url\s*+=\s*+["']?+\K[^"'\s]++";
preg_match_all("
/$sHrefPattern/iu", $sHtmlBody, $aMatches, PREG_SET_ORDER);
print_r($aMatches);

它是为快速失败而优化的,也要注意新的标志,现在结果是整个模式(不需要捕获组),(即0组)。


检查所涉及的字符集。我不知道最近在这方面对PHP所做的任何更改,但是您的regexp是否也包含俄语?您使用的是8位西里尔字符集还是UTF-8?它是由PHP显式设置还是检测?也许您的代码只是忽略了编码的问题,并且在某个地方更改了一些默认值。我建议把它当作新代码来调试。找到一个失败的regexp,找到一个它失败的小输入,并尝试确定它的编码。

regexps可以使用u修饰符智能地处理unicode,所以我首先尝试一下,以防它自动修复所有内容。