我正在使用YUI富文本编辑器格式化我正在构建的CMS中的textarea。 CMS允许用户上传和包含图像(其博客应用程序)。
在将textarea的内容写入数据库之前,我希望ColdFusion能够找到所有图像标记,并去除除SRC之外的任何无关属性。
例如:
<IMG src="foo.jpg" title="Foo!" alt="Foo!" height="100" width="100" style="border=1;">
应该出现另一端:
<IMG src="joo.jpg">
挑战:
如果有办法告诉YUI不允许任何图像属性,可以避免这种ColdFusion练习,但我不确定这是否(很容易)成为可能。
非常感谢提前!
致以最诚挚的问候,
克里斯
答案 0 :(得分:4)
最稳定,最安全的方法是将HTML加载到DOM中,从中删除不需要的位(或者更安全地,除了所需的位之外的所有内容)并转换结果回到一个字符串。
然而 - 据我所知 - ColdFusion没有为HTML提供自己的DOM解析器(只有一个用于XML),而YUI富文本编辑器不生成XML(即XHTML)。这有点不幸,但不一定是死路一条。
为了帮助您入门,我为内置XML解析器的HTML元素和属性创建了一个示例严格的白名单解决方案:
<!--- to serve as an example of what you would get from jTidy --->
<cfset xhtml = XmlParse('
<html xmlns="http://www.w3.org/1999/xhtml">
foo <img src="foo.jpg" title="Foo!" alt="Foo!" height="100" width="100" style="border=1;" />
bar <a href="asdasdad" title="blah" target="baz" onmouseover="doSomethingEvil();">Link</a>
baz <script type="text/javascript">doSomethingEvil();</script>
</html>', true)>
<!--- an easily configurable list of allowed elements and attributes --->
<cfset whiteList = StructNew()>
<cfset whiteList["html"] = "xmlns">
<cfset whiteList["head"] = "">
<cfset whiteList["body"] = "">
<cfset whiteList["img"] = "src">
<cfset whiteList["a"] = "href,title,name">
<!--- delete all attributes that are not white-listed --->
<cfloop collection="#whiteList#" item="tag">
<cfset nodes = XmlSearch(xhtml, "//*[local-name() = '#tag#']")>
<cfloop from="1" to="#ArrayLen(nodes)#" index="i">
<cfset nodeAttrs = nodes[i].XmlAttributes>
<cfloop list="#StructKeyList(nodeAttrs)#" index="attr">
<cfif not ListFind(whiteList[tag], attr)>
<cfset StructDelete(nodeAttrs, attr)>
</cfif>
</cfloop>
</cfloop>
</cfloop>
<!--- delete all elements that are not white-listed --->
<cfset unwantedElements = XmlSearch(xhtml, "//*[not(contains(',#StructKeyList(whiteList)#,', concat(',',local-name(),',')))]")>
<cfloop from="1" to="#ArrayLen(unwantedElements)#" index="i">
<cfset node = unwantedElements[i]>
<cfset node.XmlAttributes["x-delete-flag"] = "true">
<cfset parent = XmlSearch(node, "..")>
<cfif ArrayLen(parent) eq 1 and StructKeyExists(parent[1], "XmlChildren")>
<cfset childNodes = parent[1].XmlChildren>
<cfloop from="#ArrayLen(childNodes)#" to="1" step="-1" index="k">
<cfif StructKeyExists(childNodes[k].XmlAttributes, "x-delete-flag")>
<cfset ArrayDeleteAt(childNodes, k)>
</cfif>
</cfloop>
</cfif>
</cfloop>
完成后,xhtml
的内容如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
foo <img src="foo.jpg"/>
bar <a href="asdasdad" title="blah">Link</a>
baz
</html>
一些解释:
<cfdump>
来了解ColdFusion如何表示XML文档并了解我的代码中发生了什么。parentNode()
也不公开removeChild()
DOM方法。此实现基于Ben Nadel's approach to deleting DOM nodes in CF。它有效,但我痛苦地意识到它很糟糕。对不起。 : - \ "//*[not(contains(',#StructKeyList(whiteList)#,', concat(',',local-name(),',')))]"
选择所有节点,其本地名称(即不查看XML名称空间)未包含在允许名称列表中。详细地:
//
是“文档中任何位置”的简写。*
表示“任何元素节点”。contains()
会在"a"
中返回"abbr"
作为匹配项。答案 1 :(得分:2)
我可能会在三个步骤中完成这项工作。找到所有图像标签,从中提取数据,然后替换原件。
首先,识别图像标签。我会使用正则表达式来执行此操作 - 类似于
<img [^>]+>
这基本上是说“启动图像标记,然后抓住除了右括号之外的所有内容,然后是结束括号。将它与reFind或reFindNoCase结合使用以获取每个图像标记的位置和长度。
接下来,由于您只想保留href,因此可以使用类似的方法找到它。使用mid()函数和上面的位置/长度抓取标记。现在,使用正则表达式获取href
href="[^"]+"
现在,您可以循环搜索结果,将每个图像标记替换为只包含相应href的图像标记。