如何比使用strip_tags函数更安全地去除标签?

8

当字符串中包含“小于”和“大于”符号时,我在使用strip_tags PHP函数时遇到了一些问题。例如:

如果我执行以下操作:

strip_tags("<span>some text <5ml and then >10ml some text </span>");

我会得到:
some text 10ml some text

但是,显然我想得到:
some text <5ml and then >10ml some text

我知道我可以使用 &lt; 和 &gt;,但是由于数据已经存储,所以我没有将这些字符转换为HTML实体的机会。

我正在寻找一种聪明的方法来解析HTML,以便仅消除实际的HTML标记。

由于TinyMCE用于生成该数据,我知道在任何情况下可以使用哪些实际的html标记,因此 strip_tags($string, $black_list) 的实现比 strip_tags($string, $allowable_tags) 更有用。

有任何想法吗?


2
为什么你想获取什么是显而易见的?<anything> 是一个起始标签,因此应该被移除。所以 strip_tags 正在按照您的要求执行。 - ircmaxell
我同意ircmaxell的观点。无论你喜不喜欢,你的句子有三个标签。你可能需要采用不同的方法。源数据格式是否一致?在去除标签之前,你能否将尖括号转换为它们的HTML编码等价物? - clifgriffin
@ircmaxell和@clifgriffin:我写“显然”是因为从语义上讲,这些符号不是标签的一部分,它们表示“小于五毫升”和“大于十毫升”。 - texai
@ircmaxell:我并不是说strip_tags有bug。我只是在问获取我需要的正确方法。 - texai
@clifgriffin:我没有机会将这些字符转换为HTML实体,因为数据已经像您在示例中看到的那样存储。 - texai
1
@texai:我的观点是,对于计算机来说,你所要求的并不明显。这可能对我们中的任何一个人来说都很明显,但是没有一种编程语言可以使你摆脱澄清自己想法的负担。这就是我在那条评论中的意思。 - ircmaxell
4个回答

6
作为一个古怪的解决办法,您可以使用以下方式过滤非HTML尖括号:
$html = preg_replace("# <(?![/a-z]) | (?<=\s)>(?![a-z]) #exi", "htmlentities('$0')", $html);

之后应用strip_tags()。请注意,这仅适用于您特定的示例和类似情况。它是一个带有一些启发式的正则表达式,而不是人工智能来区分具有其他含义的未转义角括号的HTML标记。


既然您已经在使用 PCRE_EXTENDED,那么您可以添加内联注释,以便我们更好地理解正则表达式。 - Gordon

4

是的,我知道,但由于数据已经存储在我的示例中,我没有机会将这些字符转换为HTML实体。我正在寻找一种聪明的方法来解析HTML以剥离实际的HTML标记。 - texai
@texai:好的,那么你就去猜测和痛苦之地吧,也就是启发式算法的世界;)@mario的回答在这方面看起来很有用。 - Piskvor left the building

2

这不符合用""替换"<span>"和"</span>"的要求。 - bdsl
htmlspecialchars() 和 htmlentities() 只会对字符串中的内容进行编码,不会删除任何标签。 - Andy

0

在接受使用启发式函数尝试删除标签同时保留<和>符号的答案后,这里是一个使用preg_replace_callback的版本,因为preg_replace中的/e修饰符现已弃用:

function HTMLToString($string){
    return htmlspecialchars_decode(strip_tags(preg_replace_callback("# <(?![/a-z]) | (?<=\s)>(?![a-z]) #xi",    
        function ($matches){
            return (htmlentities($matches[0]));
        }
        , $string)));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接