昨天我发现了一个奇怪的错误,它导致一个网站只显示一个白色的页面--没有内容,也没有可见的错误信息。
我发现preg_replace中使用的正则表达式是问题所在。
我使用regex来替换在回显html之前积累的内容中的title html标记。在bug发生的页面上,html变得相当大(60 kb --不太大),而且看起来preg_replace / regex只能处理一定长度的字符串--或者我的regex真的搞砸了(也可能)。
请看这个示例程序,它再现了问题(在PHP 5.2.9上进行了测试):
function replaceTitleTagInHtmlSource($content, $replaceWith) {
return preg_replace('#(<title>)([\s\S]+)(<\/title>)#i', '$1'.$replaceWith.'$3', $content);
}
$dummyStr = str_repeat('A', 6000);
$totalStr = '<title>foo</title>';
for($i = 0; $i < 10; $i++) {
$totalStr .= $dummyStr;
}
print 'orignal: ' . strlen($totalStr);
print '<hr />';
$replaced = replaceTitleTagInHtmlSource($totalStr, 'bar');
print 'replaced: ' . strlen($replaced);
print '<hr />';
输出:
起源: 60018
替换: 0
因此-函数获得长度为60000的字符串,并返回长度为0的字符串。这不是我想要做的事。
改变
for($i = 0; $i < 10; $i++) {
至
for($i = 0; $i < 1; $i++) {
为了减少字符串的总长度,输出如下:
原始地址: 6018
取代: 6018
当我删除替换时,显示页面的内容时没有出现任何问题。
发布于 2009-09-25 23:01:19
你好像遇到了回溯极限。
如果您打印preg_last_error()
:它返回PREG_BACKTRACK_LIMIT_ERROR
,就会确认这一点。
您可以增加ini文件中的限制,也可以使用ini_set()
,或者将正则表达式从([\s\S]+)
更改为.*?
,这将大大阻止它的回溯。
发布于 2009-09-25 23:07:57
以前曾多次这样说过,例如匹配第一个结束的HTMl标记的Regex (可能还会再次提到),正则表达式不适合于HTML,因为标签太不规则了。
在可用的地方使用DOM函数。
发布于 2009-09-25 23:37:19
回溯:[\s\S]+
将匹配所有可用字符,然后向后遍历字符串,查找</title>
。[^<]+
匹配所有不是<
的字符,因此可以更快地抓取</title>
。
function replaceTitleTagInHtmlSource($content, $replaceWith) {
return preg_replace('#(<title>)([^<]+)(</title>)#i', '$1'.$replaceWith.'$3', $content);
}
https://stackoverflow.com/questions/1480594
复制相似问题