coldfusion variables within cftry do not persist - coldfusion

I have a <cftry outside of a <cfmail tag. Within the <cftry a variable x is set. The variable x does not survive past the </cftry> .
<cfoutput>
<cftry>
<cfmail
from = "user#example.org"
to = "other#example.org"
password = "something"
username = "user#example.org"
server = "localhost"
replyto = "user#example.org"
subject = "try-catch"
type = "html" >
<cfset x = 'abc'>
this is to test email
</cfmail>
success
<cfcatch>
<cfoutput> email failed </cfoutput>
</cfcatch
</cftry>
<!--- there is no variable x --->
x is #x#
</cfoutput>
I would like to find some way to pick up the value of x after the end of the <cftry. I've tried setting it with diferrent scopes inside the <cftry
<cfset register.x = 'abc'> or even
<cfset session.x = 'abc'>
But neither of those preserves x outside of the <cftry>. Can someone suggest a way to preserve x beyond the </cftry>?

It looks like you have a misconception about exception handling. Code within try is only fully executed if there is no exception. As soon as an exception occurs within try, the execution is stopped and jumps to the catch.
Example 1
<cftry>
<cfset x = "everything is ok">
<cfcatch>
<cfset x = "an exception occured">
</cfcatch>
</cftry>
<cfoutput>#x#</cfoutput>
This will always output everything is ok, because the code within try can be executed without causing an exception.
Example 2
<cftry>
<cfthrow message="I fail you!">
<cfset x = "everything is ok">
<cfcatch>
<cfset x = "an exception occured">
</cfcatch>
</cftry>
<cfoutput>#x#</cfoutput>
This will always output an exception occured, because the code within try is only executed to the point where an exception is thrown (we are doing it on purpose here with <cfthrow>).
Example 3
<cftry>
<cfset x = "everything is ok">
<cfthrow message="I fail you!">
<cfcatch>
<cfset x = "an exception occured">
</cfcatch>
</cftry>
<cfoutput>#x#</cfoutput>
This will still output an exception occured. Although the <cfset x = "everything is ok"> statement was properly executed and set the variable x, we are still jumping to the catch due to throwing an exception.
Example 4 (this is your issue!)
<cftry>
<cfthrow message="I fail you!">
<cfset x = "everything is ok">
<cfcatch>
<!--- we are doing nothing --->
</cfcatch>
</cftry>
<cfoutput>#x#</cfoutput>
This will throw a runtime error telling you that x is undefined. Why? Because the statement declaring x is never reached due to encountering an exception. And the catch doesn't introduce the variable either.
Long story short
Your <cfmail> is causing an exception and <cfset x = 'abc'> is never reached.
The Fix
Proper error handling means to meaningfullly handle caught exceptions. Don't <cfoutput> email failed </cfoutput> your way out of it and act like you don't care. Log the exception (there is <cflog> for that) and monitor it. For debugging purposes, you can use <cfrethrow> within <cfcatch> to keep the original exception instead of silently absorbing the real reason for the error.

Related

trying to check for a session if itexist and has value

i am writing a code to check for session and session value and if they do not exists or exists but have empty value or 0, i want them redirected
here is my start
<cfset lstofSessionsToCheck = 'EmplyID,Username'>
<cfset st = {}>
<cfloop collection="#session#" item="i">
<cfset SetVariable("st.session.#i#",duplicate(session[i]))>
</cfloop>
<cfparam name="redirection" default="false">
<cfif session.Username eq ''>
<cfset redirection = true>
<cfelseif session.EmplyID eq ''>
<cfset redirection = true>
</cfif>
it is missing some checks here
check if session is defined before it checks its value
if its defined, its value should not be empty or 0 or -1
please guide,m i am almost near its end but stuck at that
session is a special scope in ColdFusion and either always or never exists. It depends on the state of the sessionManagement attribute in your Application.cfc (or Application.cfm/<cfapplication>). In case sessionManagement is false, accessing session will immediately throw an exception. I assume you are not seeing this error, so session management is enabled in your environment. That leaves you with checking if the session fields are initialized. Your new best friend is called structKeyExists().
<!--- username needs to exist and must not be empty --->
<cfset hasUsername = (
structKeyExists(session, "Username") and
(len(session.Username) gt 0)
)>
<!--- ID needs to exist, must be a number and > 0 --->
<cfset hasID = (
structKeyExists(session, "EmplyID") and
isNumeric(session.EmplyID) and
(session.EmplyID gt 0)
)>
<!--- if either username or ID is not properly set, do a redirect --->
<cfif (not hasUsername) or (not hasID)>
<cfset redirection = true>
</cfif>
You can simplify the last line to a single expression:
<cfset redirection = ((not hasUsername) or (not hasID))>
As for your usage of setVariable(): You should generally avoid this function (along with evaluate()) as they can be easily exploited and pose a security risk.
Rewrite:
<cfset st = {}>
<cfloop collection="#session#" item="i">
<cfset SetVariable("st.session.#i#",duplicate(session[i]))>
</cfloop>
to
<cfset st = {}>
<cfset st.session = {}>
<cfloop collection="#session#" item="i">
<cfset st.session[i] = duplicate(session[i])>
</cfloop>
(And by the way, i is actually a key here, not a numeric index. Only use i with a for loop.)
I'm not sure the best way to do this is by looping through the entire thing every time you check. Unless those values are coming from a database or something after authentication?
Typically, if you want to restrict access to a page, you would check the session scope using structKeyExists(), for just a couple specific things.
The code would look something like this:
<!---This code sees if the user is logged in at all. If they are missing important information, I clear the session scope and redirect them to the login page. --->
<cfif !structKeyExists(SESSION, 'Username')>
<cfset structClear(SESSION)>
<cflocation url="YourPageHere" addtoken="maybe">
</cfif>
<!---This code checks for a specific permission to be defined. If not, it stops or redirects the user.--->
<cfif structKeyExists(SESSION, 'CanEditUsers') AND SESSION.CanEditUsers eq 1>
<!---your code here--->
<cfelse>
<cflocation url="YourPageHere" addtoken="maybe">
</cfif>
This is only a rough example - but hopefully puts you on the right path. Let me know if anything is unclear or needs to be edited to better fit your situation.

Coldfusion exception not caught by containing try/catch

You can run this cftry gist with either the first or second indicated block of code uncommented to see the problem.
<cffunction name="alpha" returntype="boolean">
<cfargument name="boo" type="boolean" />
<cfreturn arguments.boo />
</cffunction>
<cffunction name="beta">
<cfset var temp = {} />
<cftry>
<cfset temp.userID = 1 />
<!--- This way throws an *unhandled* exception --->
<!--- --->
<cfif alpha(structAppend({userID = temp.userID}, foo))>
<cfdump var="It worked" />
</cfif>
<!--- This way works as expected --->
<!---
<cfset temp.args = {userID = temp.userID} />
<cfif alpha(structAppend(temp.args, foo))>
<cfdump var="It worked" />
</cfif>
--->
<cfcatch>
<cfdump var="#cfcatch.message#" />
</cfcatch>
</cftry>
</cffunction>
I know the struct literal notation {} will sometimes show generically named structs in my debugger, but why should assigning what's created by such syntax make the struct creation happen at a different time than if it's not assigned?
If I debug, I can set a breakpoint on the line where I set temp.userID = 1 and it skips right over it. Moreover, the exception is being thrown on a line contained in a try/catch, but it's failing to catch it.
I know in JavaScript there's the notion of 'hoisting'. I can only assume in some (but not all!) cases CF is doing something similar to struct literals.
Is this a bug, or a known behavior of CF?

Catching an error message

I'm using Coldfusion Fusebox 3 and I would like to know how I can keep my app from throwing an error message if someone thoughtlessly removes the Circuit and fuseaction from the URL.
For example, if the original URL is:
http://www.noname/Intranet/index.cfm?fuseaction=Bulletins.main
...and someone removes the circuit information so it reads like the following: http://www.noname/Intranet/index.cfm?fuseaction=
...the app throws an error message. Can I code against something like this happening?
Here is my fbx_Settings.cfm file as it exists right now. Thank you.
Try something along these lines, haven't had chance to test but should go something like this in your index.cfm file.
<cfprocessingdirective suppressWhiteSpace="yes">
<cftry>
<!--- Include the config file --->
<cfinclude template="../config.cfm">
<cfset variables.fromFusebox = True>
<cfinclude template="fbx_fusebox30_CF50.cfm">
<cfif Len(fusebox.fuseaction) EQ 0>
<!--- Error Handle --->
</cfif>
<cfcatch type="Any">
<!---<cfset SendErrorEmail("Error", cfcatch)><cfabort />--->
</cfcatch>
</cftry>
</cfprocessingdirective>
or better still, in your switch file have a default case such as:
<cfdefaultcase>
<cfinclude template="act_HandleError.cfm">
<cflocation url="hompage.cfm" addtoken="false">
</cfdefaultcase>
Hope this helps!

why can I not catch an error message in a Coldfusion cftry/cfcatch statement?

I have a form where I can upload logos a plenty. I'm validating files (empty form fields, wrong extension, ...) inside a cftry/cfcatch statement.
When I find an error in the cftry, I do this:
<cfthrow type="FileNotFound" message="#tx_settings_app_error_create_first#" />
and inside my 'cfcatch'
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#cfcatch.message#");window.location.href="hs_apps.cfm"; } </script></cfoutput>
</cfcatch>
This works fine, catches all errors and alerts the user what is wrong.
Now I wanted to use the same handler on a database call where I'm checking for duplicate username. Still the same:
<cfquery datasource="#Session.datasource#" name="duplicates">
SELECT a.app_alias
FROM apps AS a
WHERE a.iln = <cfqueryparam value = "#Session.loginID#" cfsqltype="cf_sql_varchar" maxlength="13">
AND a.app_alias = <cfqueryparam value = "#form.app_basic_alias#" cfsqltype="cf_sql_varchar" maxlength="50">
</cfquery>
<cfif duplicates.recordcount GT 0>
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
</cfif>
The cfcatch is also the same.
However. This now procudes a server error page and I'm thrown out of the application.
Question:
Any idea, why I'm struggling to get cftry/cfcatch to work here? I'm clueless.
Thanks!
EDIT:
Here is the full code
<cfif isDefined("send_basic")>
<cfset variables.timestamp = now()>
<cfset variables.orderview = "1">
<cfif form.send_basic_type EQ "new">
<cftry>
<cfif module_check.recordcount GT 0>
<cfloop query="module_check">
<cfif module_check.module_name EQ "preorder">
<cfset variables.module_name = module_check.module_name>
<cfset variables.b2b_preord_ok = "true">
</cfif>
</cfloop>
<cfif form.app_basic_orderview EQ "preo">
<cfset variables.orderview = "0">
</cfif>
</cfif>
<!--- PROBLEM HERE: DUPLICATES --->
<cfquery datasource="#Session.datasource#" name="duplicates">
SELECT a.app_alias
FROM apps AS a
WHERE a.iln = <cfqueryparam value = "#Session.loginID#" cfsqltype="cf_sql_varchar" maxlength="13">
AND a.app_alias = <cfqueryparam value = "#form.app_basic_alias#" cfsqltype="cf_sql_varchar" maxlength="50">
</cfquery>
<cfif duplicates.recordcount GT 0>
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
</cfif>
<!--- IF PASS, CREATE/UPDATE --->
<cfquery datasource="#Session.datasource#">
INSERT INTO apps ( ... )
VALUES( ... )
</cfquery>
<cfset variables.app_action = "Applikation erstellt">
<!--- success --->
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_cfm_create#");}</script></cfoutput>
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_err_create#");}</script></cfoutput>
</cfcatch>
</cftry>
<cfelse>
<cftry>
<!--- UPDATE --->
<cfquery datasource="#Session.datasource#">
UPDATE apps
SET ... = ...
</cfquery>
<cfset variables.app_action = "Applikation aktualisiert">
<!--- success --->
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_cfm_update#");}</script></cfoutput>
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_err_update#");}</script></cfoutput>
</cfcatch>
</cftry>
</cfif>
</cfif>
The error message I'm getting it the message I specify =
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
Which if caught should alert the text behind tx_settings_apps_error_dup. If I dump the cfcatch, cfcatch.message is my specified text, so the error gets caught allright, only I get a server error page vs. an alert. I'm using exactly the same handler for fileuploads and form submits. I don't get why it's not working here?
Thanks for helping out!
WORKAROUD:
Note nice, but suffice(s):
<cfif dups.recordcount NEQ 0>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_apps_error_dup#"); location.href = "hs_apps_detail.cfm?create=newApp&id=none";}</script
</cfoutput>
<cfabort>
</cfif>
So when a duplicate is found I alert the user, reload the exact same page and cfabort to prevent the old page from processing further. Patch that is.
(moved this down from being just a comment)
OK, so the catch is definitely catching the exception if you're able to dump it, so it's not that the try/catch ain't working, it's something else. Bear in mind that processing will continue until the end of the request after your catch block, and only then will the output buffer be flushed, and your alert() sent to the browser. It sounds to me like after your output the alert, and processing continues, some OTHER error is occurring which is causing the server's error page to display. I recommend getting rid of the error page temporarily and eyeballing the actual error CF is raising.
NB: if you want processing to stop immediately in the catch block after you output the alert(), you're going to need to tell CF that, ie: with a <cfabort>. Otherwise, as per above, it'll just keep going.
I think exceptions that are caught by the server error page are still logged in the exception log, but I could be wrong. You could always put an onError() handler in your Application.cfc, log whatever error occurred, then rethrow the error so the error page still deals with it. That way you get the info on the error, and the punter still sees the nice error page.

CFCATCH throwing error in CFC

For some reason, a piece of code that works fine on a *.cfm page, and did work fine in a *.cfc, now is throwing an error when error is detected.
The error is:
Element SQL is undefined in CFCATCH.
The code block where this is getting throw looks like this:
<cfcatch type="database">
<cfset errorMessage = "
<p>#cfcatch.message#</p>
<p>Please send the following to a developer:</p>
<p>#cfcatch.SQL#</p> <--- ERROR HERE
<p>#cfcatch.queryError#</p>
<p>#cfcatch.Where#</p>">
some other stuff
</cfcatch>
Any thoughts?
UPDATE
Using #BenKoshy suggestion, I modified my <cfcatch> statement.
Remember K.I.S.S.? Keep It Simple Stupid
Using his method and then modifying it, I was getting more data back than I was going use, so I went with a simple version, and it works as advertised.
<cfif isDefined("cfcatch.message")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.message#</p>">
</cfif>
<cfif isDefined("cfcatch.SQL")>
<cfset errorMessage = errorMessage & "<p>Please send the following to a developer:</p><p>#cfcatch.SQL#</p>">
</cfif>
<cfif isDefined("cfcatch.QueryError")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.queryError#</p>">
</cfif>
<cfif isDefined("cfcatch.Where")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.Where#</p>">
</cfif>
Nice and easy and it works. KISS
Just means the error data did not contain an SQL statement. Shouldn't assume that variable will exist for all errors:
<cfif isDefined("cfcatch.sql")>
<p>#cfcatch.SQL#</p>
</cfif>
Is the easy fix. Probably best to loop through the struct like this:
<cfparam name="errorMessage" default="">
<cfloop collection="#cfcatch#" item="this">
<cfset errorMessage = errorMessage & "<p>#cfcatch[this]#</p>">
</cfloop>