Session Variables, welcome messages - coldfusion

Why does this not work? My welcome message, it just doesn't show up:
<p>Welcome <cfoutput>#Recordset1.UserID#</cfoutput>.</p>
The session variable on the login page I created is:
<cflock timeout=999 scope="Session" type="Exclusive">
<cfset Session.IDUsers =''>
</cflock>
is this incorrect? On the index page where I'm trying to display my welcome message I have:
<cfquery name="Recordset1" datasource="cfGossip">
SELECT *
FROM users
WHERE users.IDUsers = <cfqueryparam value="#Session.IDUsers#">
</cfquery>
I'm not sure if this works, or is necessary?

If you set the userid stored in the session to be the empty string, when you query on it, you will only get users for whom the id is the empty string, which shouldn't be any of them. Therefore, the query is returning an empty set, and your page is (correctly) not displaying a user id.
How are you initially identifying the user? Are you querying against a database when they log in? Are you storing a cookie? Reading Tarot cards? For this to work, at some point, you have to store the correct userid, probably in the session. To do that, you need to first identify who the user is.
Also, if you are using CF6+, you probably do not need the cflock. It is now used to prevent race conditions, as CF is now thread-safe.

Looks like you're just starting with CF, welcome to the community.
My understanding of your code makes the structure look like the following, if I'm understanding you correctly:
<cfset session.idUsers = '' />
<cfquery datasource = "cfgossip" name = "recordset1">
SELECT * FROM USERS WHERE USERS.ID_USERS = <cfqueryparam cfsqltype = "cf_sql_integer" value = "#session.idUsers# />
</cfquery>
<cfoutput>Welcome #recordset1.userID#</cfoutput>
The reason this doesn't work is because your session.idUsers value is blank. Assuming you have a user in your database with an ID_USERS value of 1, you could change the CFSET to look like and it should return results.
Additionally, while it's great to see you using CFQUERYPARAM, I'd recommend including a CFSQLTYPE attribute in the tag whenever possible to provide an added line of defense against injection attacks. You can check out http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html to see the list of available types.

Is there anywhere in your code where you set your session.IDUsers? You initialize it as a blank ''. Coldfusion does not populate it for you. The session scope is a place that will remember things for that user that you put there for a specified period of time inactivity, usually 20 minutes. So hopefully, somewhere before you run your query you have additional logic that fills that in, otherwise you are asking the database for a user named, ''.
This is just a point of style, but the following may work better for you:
<cfset Session.IDUsers =''>
<!--- Do something here to populate Session.IDUsers --->
<!--- Creates a blank query - not necessary, but can reduce errors later --->
<cfset Recordset1 = queryNew("UserID")>
<!--- Populate the query from the database --->
<cfquery name="Recordset1" datasource="cfGossip">
SELECT *
FROM users
WHERE users.IDUsers = <cfqueryparam value="#Session.IDUsers#">
</cfquery>
<!--- If the query has data, use it, otherwise show generic message --->
<cfoutput>
<cfif Recordset1.recordcount>
<p>Welcome #Recordset1.UserID#.</p>
<cfelse>
<p>Welcome new user!</p>
</cfif>
</cfoutput>
<!--- OR since we used queryNew("userID"), we can simplify without throwing an error. ---->
<cfoutput>
<p>Welcome <cfif len(Recordset1.userID)>#Recordset1.userID#.<cfelse>new user!</cfif></p>
</cfoutput>
Putting the cfoutput outside the paragraph block will make it easier if you have additional variables to insert into the text. (but will work either way)
Regardless of all that, unless you forgot to share a bit more of the code, I think the issue is that the session.IDUsers is blank and needs to be populated before the query. I hope this helps!

Related

Coldfusion Complex Construct

I am trying to construct a coldfusion conditional statement that looks for incremental form ID checkboxes to have been selected. All checkboxes are defined as Component[component number]. I have established a loop that is looking for a URL variable that is different for every form that calls on the condition as seen below. The issue I am having is that I recieve an error when executing that tells me "Complex constructs are not supported with function parameterexists."
Clearly it has to do with the dynamic nature of the parameterexists statement, but I do not fully know what this means. Can anyone explain this and also offer a solution? I am fairly new to coldfusion and coding, so take it easy on me.
<cfloop from="1" to="#URL.loopcounter#" index="loopvar">
<cfif parameterexists(Form.Component#loopvar#)>
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES ('#Form.MontaplastBarcode#', 'YES', '#URL.BadgeNumber#')
</cfloop>
<cfoutput>
<p class="success">YOUR REWORK HAS BEEN SUBMITTED SUCCESSFULLY.</p>
</cfoutput>
<cfelse>
<p class="error">NO REWORK WAS SUBMITTED. NO COMPONENTS SELECTED.</p>
</cfif>
Depending on the form that calls on this action, the URL loopcounter variable could range from 1 to 50.
To answer the question, there are several ColdFusion functions that won't allow you to create a dynamic name before the function evaluates it. parameterExists() was one of those. Both isDefined() and structKeyExists() will allow dynamic variables. So will the member function of structKeyExists() > structName.keyExists("theKey").
Again, if you are new to ColdFusion, I'd simply pretend you never saw parameterExists(). I believe it has been listed as "deprecated" since CF 4.5 or somewhere around there. That's almost 20 years ago. That function has actually become somewhat of a joke about how Adobe never really throws away their trash.
As I pointed out above, I'd get rid of it completely and go with structKeyExists(). I also don't know what your whole page is doing, but with the code you provided, I'd change it to something like this:
<cfloop from="1" to="#url.loopcounter#" index="loopvar">
<cfoutput>
<cfif structKeyExists(form,"Component#loopvar#")>
<!--- SANITIZE INPUTS --->
<cfset inMontplastBarcode = sanitizingFunction(FORM.MontaplastBarcode)>
<cfset inBadgeNumber = sanitizingFunction(URL.BadgeNumber)>
<!--- Now use sanitized inputs in query with queryparams --->
<cfquery name="InsertStuff" datasource="myds">
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES (
<cfqueryparam value="#inMontaplastBarcode#" cfsqltype="cf_sql_varchar" maxlength="50">
, 'YES'
, <cfqueryparam value="#inBadgeNumber#" cfsqltype="cf_sql_varchar" maxlength="20">
)
</cfquery>
</cfif>
</cfoutput>
</cfloop>
In your database, Reworked should be a boolean datatype. It appears that it may be a 'Yes' or 'No' string. A true boolean will be a) smaller and b) easier to validate. In the cfqueryparams, if you are using a cf_sql_varchar datatype, make sure you set an appropriate max length. You'll need to look at the available CF datatypes and see how they match up to your database datatypes. (Also see https://cfdocs.org/cfqueryparam)
For your sanitizingFunction() that you'll use to sanitize your input variables, you'll want to write a function that will follow through the steps to clean up your variables to strip out unsafe characters or other things you don't want. That is an entirely different, extremely large topic all on its own.
In your form, name your checkboxes simpler. Like reworked01 through reworked50.
On the action page use cfparam to default them to zero (since html forms don't post unchecked boxes):
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfparam name="form.reworked#numberFormat(i, 00)#" default="0">
</cfloop>
Then instead of fumbling with whether or not a variable exists, you can instead look for the value:
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfif evaluate("form.reworked"&i) eq 1>
<!--- some logic here --->
<cfelse>
<!--- some other logic here --->
</cfif>
</cfloop>

Stripping CGI.HTTP_REFERER and CGI.SCRIPT_NAME in Coldfusion

I have the block of code below which runs a query and checks for an existing record and runs a second insert query if no record is found.
<cffunction name="EndRequestFunc" access="public" returnType="string">
<!---Queries Table To Get Requested Record--->
<cfquery name="qryGetPageRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
SELECT pageName
FROM tblCFMPageRequest
WHERE pageName = '#CGI.HTTP_REFERER#' AND scriptName =
'#CGI.SCRIPT_NAME#'
</cfquery>
<!---Conditional Check for record count equal to 0--->
<cfif qryGetPageRecord.recordCount eq 0>
<!---If record count equal to 0, recordset query executed--->
<cfquery name="setNewRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES ('#CGI.HTTP_REFERER#', '#CGI.SCRIPT_NAME#')
</cfquery>
</cfif>
</cffunction>
What I need to do is strip the values of the two CGI variables of all formatting so that a value like this "example.com/portal/mypage.cfm" will be stripped of http and everything else down everything to just mypage.cfm before its inserted by the query. Any guidance would be appreciated.
Update: Thank to the advice given, I was able to eliminate the http://example.com/ portion of the URL using the ListLast function.
I was short sighted in not remembering my urls have characters that need to be eliminated after the "cfm" point. Here is one of my actual results from ListLast: client_modify.cfm?uid=248&al=1&a_trigger=1.
I've tried using some other List functions in Coldfusion to no avail as of yet. Any advice on how to eliminate the bold portion of:
client_modify.cfm ?uid=248&al=1&a_trigger=1 so I'm just left with a clean client_modify.cfm
Use ListLast() function with / as a delimiter. Also, always try to use cfqueryparam to put values in queries. Like this.
<cfquery name="setNewRecord" datasource="First_Main_Dev" bname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES (<cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.HTTP_REFERER,'/')#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.SCRIPT_NAME,'/')#">)
</cfquery>
CGI variables shouldn't have any "formatting", so your question is a bit confusing.
If you're just looking to get the filename at the end of the string, you can use the list functions.
fileIwant = ListLast(CGI.SCRIPT_NAME,"/");
If CGI.SCRIPT_NAME is /wwwroot/example/index.cfm, fileIwant will result in index.cfm.
Have a care with the referrer, as it may not be defined and parsing it out will throw an error.

ColdFusion cfset issue

I am new to ColdFusion. Anyone know why this code is not working. When I leave the form null it is not showing 100 in the database.
<cfif isdefined("FORM.Percentage")>
<cfset Form.Percentage = #Form.Percentage#>
<cfelse>
<cfset Form.Percentage = 100>
</cfif>
<cfquery name="percent" datasource ="abc">
Insert into Employees
(Percentage)
Values
(#Form.Percentage#)
</cfquery>
If you have a textbox it is submitted to the form even if it's left blank, so you want to check if the field was left blank. If it was then you can set the default.
You'll also want to do some server side validation that the value is a number and use cfqueryparam for inserting your value into the database.
<cfif NOT len(trim(FORM.Percentage))>
<cfset Form.Percentage = 100>
<cfif>
<cfquery result="percent" datasource="abc">
Insert into Employees (Percentage)
Values (
<cfqueryparam cf_sql_type="cf_sql_integer" value="#Form.Percentage#">
)
</cfquery>
When using cfquery with an INSERT the name attribute doesn't provide anything. Using result would allow you to view some data about the query if needed, but generally it shouldn't be used.
You could also have dumped form to the screen by using <cfdump var="#form#"> to see what it was returning. If you want to check that the key exists for a radio button or checkbox you can use structKeyExists(form,'myCheckbox') rather than using isDefined().

Resetting cached query with cachedwithin

Inside a cffunction I have a query that I want to long cache by setting the cachedwitin to a big value. However, I also want to clear that cache under a few circumstances.
I've done this in a number of places, but in one of them the cache is never updated and I always get the original value if I ask it to give me the cached value.
The cfquery documentation states:
To use cached data, the current query must use the same SQL statement, data source, query name, user name, and password.
This is the case with the query, since it's a single sql statement with no non-sql except the cfqueryparam; datasource and query name don't change and username and password are not specified.
The relevant code is:
<!--- Long cache the query since the values rarely change, but allow the cache to be cleared. --->
<cfif Arguments.ClearCache EQ false>
<cfset local.CachedWithin = CreateTimeSpan(7,0,0,0)>
<cfelse>
<cfset local.CachedWithin = CreateTimeSpan(0,0,0,-1)>
</cfif>
<cfquery name="local.qryName" datasource="#Variables.DSN#" cachedwithin="#local.CachedWithin#">
SELECT
[User].[Name]
FROM
[User]
WHERE
[User].[UserID] = <cfqueryparam value="#Arguments.UserID#" cfsqltype="cf_sql_integer">
</cfquery>
Why does this work in other places, but not here?
There is an additional "sameness" requirement for cached queries that isn't mentioned in the documentation. That note should end with:
... password, and underlying data types of any cfqueryparam values.
Change your code so that the Arguments.UserID is forced to a data type. In your case this can be accomplished by putting the following code before the cfquery:
<!--- Make sure data types used in query are consistent --->
<cfset local.UserID = Int(Arguments.UserID)>
and change the cfqueryparam value to value="#local.UserID#".
I've phrased the above as an omission in the documentation, but I suspect it's a bug in CF9 instead.

cffeed function: show just most recent post?

We have a function to pull RSS feeds and display the post on a ColdFusion page using this code:
<cfset rssUrl = "rss1">
<cffeed action="read" source="#rssUrl#" query="fitness" properties="info">
<cfset rssUrl2 = "rss2">
<cffeed action="read" source="#rssUrl2#" query="nutrition" properties="info">
<cfif #fitness.PUBLISHEDDATE# gt #nutrition.PUBLISHEDDATE#>
<cfset entries="fitness">
<cfelse>
<cfset entries="nutrition">
</cfif>
Output done via:
<cfoutput query="#entries#">
Problem is, the RSS feed has several posts and we only want to show one. Any thoughts on how to get it to pull and display only the most recent post? (We want the feed to have multiple posts, so right now our non ideal solution is to set maximum posts per feed to 1)
cfoutput/query=".." will go over an entire query. If you only want to do the first row, use:
<cfoutput>
Title from row 1: #somequery.title[1]#
</cfoutput>
Basically - array notation on the column. Make sense?
There's nothing wrong with Ray's answer, but here are some other options.
<cfoutput query="#entries#" maxrows="1">
Offers the least disruption to your existing code and, should you decide to change the number of rows displayed (like, via a user setting) it's an easy change.
OR
If you copy the query object rather than the query name (which isn't actually a copy but a copy by reference)
<cfset entries = fitness>
instead of
<cfset entries = "fitness">
you can do this
<cfoutput>
#entries.columnName1#
#entries.columnName2#
<!--- etc. --->
</cfoutput>
which will, by default, display only the first row of the query.