ColdFusion:从图像标记中剥离图像标记属性

时间:2010-12-02 16:37:26

标签: image coldfusion replace

我正在使用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">

挑战:

  1. 图像属性可以是示例中列出的任何,全部或全部。
  2. 图像属性可以按任何顺序
  3. 图片标记可以位于textarea
  4. 的文本正文中的任何位置

    如果有办法告诉YUI不允许任何图像属性,可以避免这种ColdFusion练习,但我不确定这是否(很容易)成为可能。

    非常感谢提前!

    致以最诚挚的问候,

    克里斯

2 个答案:

答案 0 :(得分:4)

最稳定,最安全的方法是将HTML加载到DOM中,从中删除不需要的位(或者更安全地,除了所需的位之外的所有内容)并转换结果回到一个字符串。

然而 - 据我所知 - ColdFusion没有为HTML提供自己的DOM解析器(只有一个用于XML),而YUI富文本编辑器不生成XML(即XHTML)。这有点不幸,但不一定是死路一条。

  1. plenty HTML parsers available for Java并且使用ColdFusion中的Java对象很容易。您可以在项目中包含其中一个。
  2. 您可以将HTML输入转换为XHTML(通过jTidy),然后使用内置的XML解析器来实现清理。完成后,您甚至可以使用jTidy将其转换回HTML。
  3. 为了帮助您入门,我为内置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>
    

    一些解释:

    • 关于如何让Tidy在网络上的ColdFusion中工作,有几个描述和UDF,只需查找它们。
    • 在ColdFusion中,XML DOM处理很麻烦。它既不漂亮也不优雅,但它仍然比试图使用(上帝禁止)正则表达式来达到同样的效果更好。我强烈反对您使用它们解决此问题。
    • 使用<cfdump>来了解ColdFusion如何表示XML文档并了解我的代码中发生了什么。
    • 第二位(删除所有非白名单元素)有点毛茸茸。显然,不可能更优雅地从ColdFusion中删除节点,因为ColdFusion XML节点确实既不公开parentNode()也不公开removeChild() DOM方法。此实现基于Ben Nadel's approach to deleting DOM nodes in CF。它有效,但我痛苦地意识到它很糟糕。对不起。 : - \
    • XPath:表达式"//*[not(contains(',#StructKeyList(whiteList)#,', concat(',',local-name(),',')))]"选择所有节点,其本地名称(即不查看XML名称空间)未包含在允许名称列表中。详细地:
      • //是“文档中任何位置”的简写。
      • *表示“任何元素节点”。
      • 方括号表示条件。额外的逗号是为了确保只考虑完整匹配 - 例如,contains()会在"a"中返回"abbr"作为匹配项。

答案 1 :(得分:2)

我可能会在三个步骤中完成这项工作。找到所有图像标签,从中提取数据,然后替换原件。

首先,识别图像标签。我会使用正则表达式来执行此操作 - 类似于

<img [^>]+>

这基本上是说“启动图像标记,然后抓住除了右括号之外的所有内容,然后是结束括号。将它与reFind或reFindNoCase结合使用以获取每个图像标记的位置和长度。

接下来,由于您只想保留href,因此可以使用类似的方法找到它。使用mid()函数和上面的位置/长度抓取标记。现在,使用正则表达式获取href

href="[^"]+"

现在,您可以循环搜索结果,将每个图像标记替换为只包含相应href的图像标记。