昨天我追踪了一个奇怪的错误,导致网站只显示一个白页 - 没有内容,没有错误信息可见。
我发现preg_replace中使用的正则表达式是问题所在。
我使用了正则表达式,以便在回显html之前替换累积内容中的标题html标记。 html在发生错误的页面上变得相当大(60 kb - 不是太大)并且看起来像preg_replace /使用的正则表达式只能处理一定长度的字符串 - 或者我的正则表达式真的搞砸了(也可能)。
看看这个重现问题的示例程序(在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 />';
输出:
orignal:60018
已取代:0
所以 - 函数获取一个长度为60000的字符串,并返回一个长度为0的字符串。不是我想用我的正则表达式做的。
更改
for($i = 0; $i < 10; $i++) {
到
for($i = 0; $i < 1; $i++) {
为了减少总字符串长度,输出为:
orignal:6018
替换:6018
删除替换后,页面内容显示没有任何问题。
答案 0 :(得分:3)
好像你正在遇到backtracking limit。
如果您打印preg_last_error()
,则会确认:它会返回PREG_BACKTRACK_LIMIT_ERROR
。
您可以增加ini文件中的限制,也可以使用ini_set()
或将正则表达式从([\s\S]+)
更改为.*?
,这样可以阻止它回溯太多。
答案 1 :(得分:1)
之前已经多次说过,例如Regex to match the first ending HTMl tag(并且可能会再次提到)正则表达式不适合HTML,因为标签过于不规则。
在可用的DOM功能中使用它们。
答案 2 :(得分:1)
回溯:[\s\S]+
将匹配所有可用字符,然后返回查找</title>
的字符串。 [^<]+
匹配所有不是<
的字符,因此可以更快地抓取</title>
。
function replaceTitleTagInHtmlSource($content, $replaceWith) {
return preg_replace('#(<title>)([^<]+)(</title>)#i', '$1'.$replaceWith.'$3', $content);
}
答案 3 :(得分:0)
你的正则表达式似乎有点滑稽。
([\ s \ S] +)匹配所有空格和非空格。你应该尝试(。*?)。
改变你的功能对我有用:
function replaceTitleTagInHtmlSource($content, $replaceWith) {
return preg_replace('`\<title\>(.*?)\<\/title\>`i', '<title>'.$replaceWith.'</title>', $content);
}
问题似乎是你试图用$ 1和$ 3来匹配和