我正在ColdFusion中编写一个应用程序,尽管它基本上是稳定的,但它经常出错。因为它已经取代了旧的应用程序,有时候会出现错误的用户而不是我。
我创建了一个很好的页面,人们在收到向我发送信息的错误时会得到这个页面,例如错误,引用,错误,页面,行号等。
我唯一无法工作的是获取表单数据(如果有的话)。我事先不知道它错误的页面,所以我不能只输出'#form.field#'。
例如:if:
form.abc = 1
form.def = 2
如何在事先不知道的情况下从'form'获取变量名称和值?
this document on looping over a structure是否在正确的道路上?
此外,我正在寻找一种将数据存储在数据库中的好方法,因为这是存储有关错误的其他信息的地方,我真的不想将其放入电子邮件中。我
答案 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>
您可以在那里转储您喜欢的任何范围。您可能需要也可能不需要我提供的那些。
你说你最初的问题是应用程序正在替换旧的应用程序?您是否在部署的同一台服务器上进行开发?如果是这样,您只需更改开发副本的应用程序名称 - 确保名称是唯一的以避免此问题(如果这就是您的问题)。