在ColdFusion中,如何提取和存储提交表单的内容?

时间:2009-02-03 07:21:59

标签: database coldfusion error-logging

我正在ColdFusion中编写一个应用程序,尽管它基本上是稳定的,但它经常出错。因为它已经取代了旧的应用程序,有时候会出现错误的用户而不是我。

我创建了一个很好的页面,人们在收到向我发送信息的错误时会得到这个页面,例如错误,引用,错误,页面,行号等。

我唯一无法工作的是获取表单数据(如果有的话)。我事先不知道它错误的页面,所以我不能只输出'#form.field#'。

例如:if:

form.abc = 1
form.def = 2

如何在事先不知道的情况下从'form'获取变量名称和值?

this document on looping over a structure是否在正确的道路上?

此外,我正在寻找一种将数据存储在数据库中的好方法,因为这是存储有关错误的其他信息的地方,我真的不想将其放入电子邮件中。我

5 个答案:

答案 0 :(得分:7)

表单范围有一个FieldNames变量,它会告诉您提交的字段。

您还可以StructKeyList(Form)获取范围中当前变量的列表。这个还将包括FieldNames和已添加到表单范围的任何其他变量。

其中任何一个都可以在<cfloop index="CurField" list="#StructKeyList(Form)#">中使用 - 但有更简单的方法......


如果您使用的是CF8,则可以使用serializeJson()deserializeJson()函数将范围转换为一个很好的字符串,然后可以将其存储在合适的数据库字段中。

如果您使用的是CF6..7,那么您可以从cfjson下载一个名为riaforge的CFC,它模仿这些功能。


最后,如果您使用的是早期版本的CF,或者对使用JSON进行存储有一种奇怪的厌恶,您可以使用更简单的循环滚动自己的循环到上面提到的循环 - 集合循环可让您直接循环结构或范围 - 注意一些讨厌的人选择“项目”而不是“索引”作为这些的属性。

因为我们知道Form变量都是简单的对象(即字符串),所以我选择了基本的key=value[newline]key=value[newline]...格式,这也很容易反转。

编码:

<cfset Output = '' />
<cfloop item="CurField" collection="#Form#">
    <cfset Output = Output & CurField & '=' & Form[CurField] & Chr(10) />
</cfloop>

<cfoutput>#Output#</cfoutput>

解码:

<cfset FormData = StructNew()/>
<cfloop index="CurLine" list="#Output#" delimiters="#Chr(10)#">
    <cfset FormData[ListFirst(CurLine,'=')] = ListRest(CurLine,'=') />
</cfloop>

<cfdump var="#FormData#"/>


最后一个重要注意事项:与所有用户提供的变量(Form,Url,Cookie范围)一样,您必须确保正确处理它们以防止出现安全漏洞 - 特别是 确保您使用的是cfqueryparam 所有 您的数据库查询 - 不想偏离太远,但随意提出另一个问题如果您需要任何有关cfqueryparam的帮助。


希望这会有所帮助。 :)

答案 1 :(得分:4)

如果你想手动遍历所有表单字段,最简单的方法就是这样的cfloop:

<cfloop collection="#form#" item="variables.name">
  #variables.name#=(#form[variables.name]#)<br/>
</cfloop>

但是那说,出于错误电子邮件的目的,你可能会发现更容易“转储”表单范围(这只是一个特殊的结构),如下所示:

<cfmail
  from="errors@#cgi.server_name#"
  to="you@yourdomain.com"
  subject="Error Occurred in such and such a place"
  type="html">
    <cfdump var="#form#"/>
</cfmail>

发送错误电子邮件时,我想为CGI范围添加第二个cfdump(同样,只是一个特殊的结构),因为这可以提供有关请求的其他一些有用的信息。

如果您有CF 8,您可能还希望以文本格式转储,如下所示,因为它会使邮件大小变小(在我看来,使邮件更具可读性)

<cfdump var="#form#" format="text">

注意:为CF 8添加了CFDump标记的format属性,因此您无法在以前版本的ColdFusion中使用它。

您提到您正在寻找将这些错误存储在数据库中的方法,这是一个好主意。我建议您查看BugLogHQ,而不是为此推出自己的自定义解决方案。它已经存在了一段时间,并且适用于其他人,包括我,最重要的是免费和开源。它的年龄和广泛使用意味着它不太可能在自己的代码中出现错误,并且可能具有比你写的更多,更好的功能。

使用BugLogHQ,您不必担心错误的显示,您只需将数据发送到错误记录器,它将负责其余的工作。

答案 2 :(得分:3)

Form只是一个哈希/结构,所以你可以遍历它的键:

<cfoutput>
 <cfloop collection=#form# item="field">
  #htmleditformat(field)=#htmleditformat(form[field])#<br/>
 </cfloop>
</cfoutput>

将数据放入数据库?你如何做到这一点取决于你之后想要做什么。最灵活的解决方案可能是将整个form(和url)转换为WDDX对象,并将其存储在blob字段中:

<cfwddx action="cfml2wddx" input=#url# output="encodedURL"/>
<cfwddx action="cfml2wddx" input=#form# output="encodedForm"/>
<cfquery datasource="yourDSN">
 INSERT INTO errorlog (datestamp, event, script_name, path_info, url, form)
 VALUES
  (<cfqueryparam value=#now()# cfsqltype="CF_SQL_TIMESTANP"/>,
   <cfqueryparam value="your error string or cfcatch data" cfsqltype="CF_SQL_VARCHAR"/>,
   <cfqueryparam value=#cgi.script_name# cfsqltype="CF_SQL_VARCHAR"/>,
   <cfqueryparam value=#cgi.path_info# cfsqltype="CF_SQL_VARCHAR"/>,
   <cfqueryparam value=#encodedURL# cfsqltype="CF_SQL_BLOB"/>,
   <cfqueryparam value=#encodedForm# cfsqltype="CF_SQL_BLOB"/>)
</cfquery>

通过这种方式,您可以随意访问所有原始数据以供分析。当然还有很多其他方法可以解决这个问题。

答案 3 :(得分:3)

如果您在应用程序中使用Application.cfc,只需将onError方法替换为下面的方法即可。注意:application.settings.mode可以是以下值之一(dev,test,prod)。 application.settings.webmasteremail应设置为您希望将错误信息邮寄到的电子邮件地址。这两个变量都应该在onApplicationStart方法中设置。

这个功能有什么作用?如果应用程序设置为“dev”模式(通过设置application.settings.mode =“dev”),它将在屏幕上显示错误信息。如果应用程序设置为任何其他模式(如测试或产品),它将通过电子邮件发送并将信息存储在数据库中。

<cffunction name="onError" returnType="void" output="true">
    <cfargument name="exception" required="true">
    <cfargument name="eventname" type="string" required="true">
    <!--- corrects bug where <cfabort> throw an error --->
    <cfif arguments.exception.rootCause eq "coldfusion.runtime.AbortException">
        <cfreturn>
    </cfif>
    <cfsavecontent variable="errordata">
        <p>#eventname#</p>
        <cfdump var="#exception#" label="Exception Information" format="text">
        <cfdump var="#url#" label="URL Information" format="text">
        <cfdump var="#form#" label="FORM Information" format="text">
        <cfdump var="#application#" label="Application Scope" format="text">
        <cfif isdefined("session")>
            <cfdump var="#session#" label="Session Scope" format="text">
        </cfif>
        <cfif isdefined("client")>
            <cfdump var="#client#" label="Client Scope" format="text">
        </cfif>
        <cfdump var="#cgi#" label="URL Information" format="text">
    </cfsavecontent>

    <!--- will email the error inforation and display the error page --->
    <cfif application.settings.mode eq "dev">
        <p>#eventname#</p>
        #errordata#
    <cfelse>
        <cfmail to="#application.settings.webmasteremail#" from="error@#cgi.http_host#" subject="Error has occured on #cgi.http_host#" type="HTML" charset="windows-1252">
        <p>#eventname#</p>
        #errordata#
        </cfmail>

        <cfquery datasource="yourDSN">
        insert into errorlog
        (
            creationdate
            ,event
            ,info
        )
        values
        (
            <cfqueryparam value="#now()#" cfsqltype="CF_SQL_TIMESTAMP"/>
            ,<cfqueryparam value="#eventname#" cfsqltype="CF_SQL_VARCHAR"/>
            ,<cfqueryparam value="#errordata#" cfsqltype="CF_SQL_LONGVARCHAR"/>
        )
        </cfquery>

        <h2>A functional error has occurred.</h2>
        <p>A notification of this error has been automatically e-mailed to the development team; no action on your part is required.</p>
        <p>Please click the "back" button on your browser to return to the web site.  We apologize for this inconvenience.</p>
    </cfif>
</cffunction>

答案 4 :(得分:0)

如果您通过电子邮件发送自己的表单变量,只需转储它们,如下所示:

<cfmail type="html" ...>
    <cfdump var="#form#" label="form">
    <cfdump var="#cgi#" label="cgi">
    <cfdump var="#session#" label="session">
</cfmail>

您可以在那里转储您喜欢的任何范围。您可能需要也可能不需要我提供的那些。

你说你最初的问题是应用程序正在替换旧的应用程序?您是否在部署的同一台服务器上进行开发?如果是这样,您只需更改开发副本的应用程序名称 - 确保名称是唯一的以避免此问题(如果这就是您的问题)。