【问题标题】:Regular expression crashes Apache due to PCRE limitations由于 PCRE 限制,正则表达式使 Apache 崩溃
【发布时间】:2011-04-06 12:02:05
【问题描述】:

我目前正在创建 bbcode 解析引擎,但遇到了我自己无法解决的情况。

问题是,我遇到了一个和这个完全一样的问题: Apache / PHP on Windows crashes with regular expression

这意味着如果我做出类似下面示例的操作,Apache 会因为递归计数达到 690(PCRE 的内存限制为 1MB)而崩溃:

$txt = '[b]'.str_repeat('a', 338).'[/b]';  // if I change repeat count to lower value it's ok
$regex = '#\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))](?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)\[/(?P=tag)]#mi';

echo preg_replace_callback($regex, function($matches) { return $matches['content']; }, $txt);

所以我需要以某种方式在我的正则表达式中尽量减少 *+ 的需求,但这就是我没有想法的地方,所以我想也许你可以提出一些建议。

欢迎使用其他解析 bbcode(可以处理嵌套标签)的方法。 但是我不想使用已经构建的类或其他东西。我喜欢自己做事!

我还研究了 PECL 和 Pear HTML_BBCodeParser。但我不希望我的应用程序依赖于扩展。更有可能我会做一些脚本来检查那个扩展,如果它不存在,请使用我在这里尝试做的 BBCode 解析器。

对不起,如果我的描述令人沮丧,我不擅长英语^^

编辑。所以正则表达式解释:

\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))]

这是我的开始标签。我使用了命名组。使用“标签”标识标签,使用“属性”标识标签属性。也可以将标签视为一个属性。那么这里发生了什么?我尝试匹配一个标签,当一个标签匹配时,我尝试匹配= 符号之后的任何内容或\s(空格)之后的任何内容,直到它到达标签关闭]

(?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)

现在我在这里尝试匹配内容。这是棘手的部分。我正在寻找任何不是 [ 的字符,如果找到任何字符,则检查它是否不是我的结束标记或递归,并告诉正则表达式引擎这样做,直到....

\[/(?P=tag)]

...找到结束标记。

【问题讨论】:

  • “我也研究了 PECL 和 Pear HTML_BBCodeParser。但我不希望我的应用程序依赖于扩展”——我认为这个选项比重新发明轮子更可取。
  • I like to do things on my own! - 为什么?您是否也编写自己的正则表达式引擎?还是你自己的 php 解释器/运行时?
  • 顺便说一句:您可能希望将正则表达式代码分散到多行并用 cmets 解释这些部分。我这可以提高你获得帮助的机会。
  • 感谢您的提示,VolkerK。我说的“我喜欢自己做事!”并不是这个意思。哦,好吧..让我们忘记它。我已经解释了代码,希望现在可以了。
  • 你能举一个你遇到限制的字符串的例子吗?

标签: php regex bbcode recursive-regex


【解决方案1】:

我打算推荐一个 BBCodeParser...

我还研究了 PECL 和 Pear HTML_BBCodeParser。但我不希望我的应用程序依赖于扩展

我觉得这很奇怪。为什么要重新发明轮子?好的软件工程的原则之一是 DRY(不要重复自己)。你正在尝试解决一个已经解决的问题。

我喜欢自己做事!

这本身并不坏,但有时你最好使用经过验证的真实解决方案;一个比您自己的测试更好且更强大的(正如您所发现的那样)。这样,您将花时间在您真正想要解决的问题上,而不是解决已经解决的问题。不要陷入重新发明轮子的陷阱。 :)

我对您的建议(和解决方案)是使用 BBCode 解析器。

编辑

另一件事是您正在解析类似 HTML 的内容。这种性质的东西不容易被正则表达式解析。

【讨论】:

  • 嗯,我说的是 php.net 建议的服务器端(我的意思是它必须由托管公司或服务器管理员安装)扩展。最好有一个独立的应用程序,您只需将其上传到主机即可使用。
  • 这应该是一条评论,因为它没有回答 OP 问题。
  • 我猜你错过了这部分:“我对你的建议(和解决方案)是使用 BBCode 解析器。”,以及编辑后的部分。
  • @Paul 您可以随时要求托管公司或服务器管理员包含该特定扩展名。有许多对开发人员友好的托管解决方案。如果不是这样,您将不得不重写每个扩展!
【解决方案2】:

您的正则表达式,尤其是零宽度断言(环视)导致正则表达式引擎灾难性地回溯。故事的寓意:不应该使用 Regex can't 来解析不规则的语言。如果你有嵌套结构,那就不是常规语言。

事实上,我认为 BBCode 是邪恶的。 BBCode 是一种标记语言,由不想以正确方式过滤 HTML 的懒惰程序员发明。结果,我们现在有了一个难以实施的松散“标准”。以正确的方式过滤您的 HTML:

http://htmlpurifier.org/

【讨论】:

  • 嗯...也许您对使用正则表达式处理此类问题是正确的。好吧,用 HTML 代替 BBCode 会很棒,但是人们已经习惯了 BBCode,现在它就像某种标准,所以你不能把它扔掉。
猜你喜欢
  • 2012-08-04
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 2014-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多