Accessibility
Home / Developer Center / ColdFusion Developer Center

ColdFusion Article

Icon or Spacer Icon or Spacer Icon or Spacer
Kevin Towes
Kevin Towes
Pangaea NewMedia
 
Previous Columns
· Use CFCs Properly by Ben Forta
· Building a Macromedia Flash interface for content management
by Kevin Towes
· Security best practices: Authenticating and authorizing against
NT domains with ColdFusion MX

by Rob Rusher
 
Using ColdFusion Tags in CFScript


Call it getting back to my roots, but writing this article refreshed my love for ColdFusion even more. These past few months, I have been so heavily involved with ActionScript that I almost forgot my roots.

Both Ben Forta’s last CF Extreme article, Use ColdFusion Components—Properly, and Ray Camden’s article, Writing User-Defined Functions in ColdFusion MX, got me thinking about how we old-school ColdFusion developers are in the midst of evolving in the way we develop applications. The thought process has changed dramatically. Objects, prototypes, methods, properties, instantiation and what is “this"? It all sounds a little “Flashy" to me. Well, it’s not a bad thing and it's worth the time and energy to learn these new techniques.

This article will step you through using ColdFusion tags within your cfscript block. To start with, I’ll discuss cfscript code to ensure everyone’s on the same page. This article assumes that you understand ColdFusion components. To learn more about ColdFusion components, read Ben Forta’s Introduction to ColdFusion Components.


Sample files

Download the source files for this tutorial:

Windows
Download the sample file cftags_cfscript.zip (2K)
 

 

Do you notice something unusual with the following cfscript?

<CFSCRIPT>
  SQLString = "Select * From LoginInfo where 
  UserID='BobZ' and Password = 'Ads10'";
  DATASOURCE = "CompanyInfo";
  checkUser=CFQUERY(SQLString: SQLString,  
  DATASOURCE: DATASOURCE);
  if (checkUser.recordCount neq 0) {
    CFOUTPUT("Welcome Back, " & checkUser.UserID);
  } else {
    CFOUTPUT("Your UserName is Wrong.. try again!");
    CFLOCATION(theURL:"login.cfm");
  }
</CFSCRIPT>

The code snippet stores the username in a field called UserID. But did you also notice that the script performs a database authentication process without leaving the cfscript blocks? Compare the previous code to the following code snippet, which would does the same thing:

<CFQUERY NAME="checkUser" Datasource="CompanyInfo">
  Select * From LoginInfo 
  where UserID='BobZ' and Password = 'Ads10';
</CFQUERY>

<CFIF checkUser.RecordCount neq 0>
	<CFOUTPUT>Welcome Back, #checkUser.UserID#</CFOUTPUT>
<CFELSE>
	Your UserName is Wrong... try again!
	<CFLOCATION URL="login.cfm">
</CFIF>

Why would you want to use script instead of ColdFusion tags? First, you may not want to completely rewrite the entire CFML tag library (although, that would be a great thing). But, you could use this technique to help you consolidate your ColdFusion code. Call it the ActionScript coder in me, but wouldn’t it be great if you could validate a user with code as simple as this:

if (authenticateUser("BobZ", "Ads1")) 
     { /* User Authenticated*/ }
		else {/* User Login Failed */}

When someone tells me I can’t do something I don’t believe it. I know that if you can think it, you can find a way to do it. When user-defined functions (UDFs) were introduced in ColdFusion Server 5, the ColdFusion community jumped for joy. Once the excitement settled, the questions started. Developers wanted to know whether they could use the native CFML tag library within cfscript. For one, they commonly used tags like cfquery or cffile in their ColdFusion applications, and they thought it could be possible to use these tags within cfscript.

In ColdFusion Server 5, you could only use the custom tag architecture to implement cfquery, cfhttp, cfmail, or any other CFML tags within script. In ColdFusion MX, you can use the cffunction tag to group ColdFusion tags into a UDF that you can use within cfscript. The following example uses the cfquery tag within a user-defined function named “cfquery."

<cffunction name="CFQUERY" access="public" returntype="query">
  <cfargument name="SQLString" type="string" required="yes">
  <cfargument name="Datasource" type="string" required="yes">
  <cfargument name="dbType" type="string" default="">		
  <cfquery name="RecordSet" datasource="#arguments.Datasource#" 
    dbtype="#arguments.dbType#">
	#preserveSingleQuotes(arguments.SQLString)#
 </cfquery>
 <cfreturn RecordSet>
</cffunction>

Notice that all the attributes of the cfquery user-defined function are not listed above. Ray Camden’s article, Writing user-defined functions in ColdFusion MX, is an excellent primer for understanding the cffunction tag.

You can use this knowledge to perform a cfquery within a cfscript block, as in the example below:

<CFSCRIPT>
	SQLString = "Select * From Departmt";
	DATASOURCE = "CompanyInfo";
	checkUser=CFQUERY(SQLString: SQLString,DATASOURCE:DATASOURCE);
</CFSCRIPT>

<CFDUMP var="#checkUser#">

The cfdump tag, introduced in Macromedia Spectra, is a great tool for outputting a variable or structure. But it’s still outside of the cfscript code block below. Here, I’ve added it to the script list.

<cffunction name="CFDUMP" returntype="boolean" output="yes">
  <cfargument name="structure" type="any" 
     default="nothing to output">
  <CFDUMP Var="#arguments.structure#">
  <cfreturn true>
</cffunction>

With it added to the script list, you can now use the cfdump script function inside the cfscript code block.

<CFSCRIPT>
	SQLString = "Select * From Departmt";
	DATASOURCE = "CompanyInfo";
	checkUser=CFQUERY(SQLString: SQLString, DATASOURCE:DATASOURCE);
	CFDUMP(checkUser);
</CFSCRIPT>

Nothing will change in your output. It will look like the Figure 1.

Figure 1:  The cfdump output for the cfscript block.
Figure 1: The cfdump output for the cfscript block.
 

Most developers avoid creating functions that generate output. However, since the goal in this column is to duplicate the functionality of the CF Tag library, I’ve used cfdump to output a result.

The problem with the previous method is that if the cffunction is on the same page, ColdFusion MX must parse the cffunction tag each time you want to use the function. You can solve this problem by including a simple statement in your Application.cfm file.

But wouldn’t it be great to create a custom “object" that you could use without loading the functions each time?

This object would contain the methods (functions) you define in your CFC, but it could also maintain its own properties (variables) too.

Consolidating the methods into a CFC
You can consolidate these functions as methods of a ColdFusion Component (CFC). This will make it easier to reuse the functions in other applications you build. It will also allow you to take advantage of some additional features of CFCs, which I will discuss shortly.

This exercise will use the Microsoft Access database, “companyInfo" that was installed with your ColdFusion MX server. You can check that the DSN is mapped by logging into the ColdFusion Administrator, and clicking “Data Sources."

 
1 Create a new CFC file in a folder called “extremeCF" in your ColdFusion MX server’s webroot. Note that ColdFusion server can only locate the CFC if: a) The CFC is within your webroot and you have a slash “/" mapping to the webroot (which exists by default). or b) You have a custom tag path pointing to the CFC. Note that if you’re new to ColdFusion components, you can learn more about them in Ben Forta’s Introduction to ColdFusion Components.
2 Add the <cfcomponent></cfcomponents> tags to the document. Add line breaks between the tags. The following CFML will be placed in between them.
3 Copy the two user-defined functions (CFQUERY and CFDUMP) from the code samples above and put them into the CFC.
4 Remove the “CF" from the function Names, so they are named QUERY and DUMP, respectively.
5 Replace the data source default value in the cfargument tag. This argument will use a property we will set when the CFC is instantiated.

<cfargument name="Datasource" type="string" default="#this.dsn#">
6 Add the OUTPUT method (below). Note that this is a rewrite of the basic CFOUTPUT tag process. You could extend this function with some of the additional attributes of the CFOUTPUT tag.
 

<cffunction name="OUTPUT" returntype="boolean" output="yes"> <cfargument name="trace" type="string" default="nothing to output"> <cfargument name="addLineBreak" type="boolean" default="false"> <CFOUTPUT>#arguments.trace#
<CFIF addLineBreak><BR></CFIF> </CFOUTPUT> <cfreturn true> </cffunction>
7 Save the CFC as CFOTags.cfc in the same folder as the CFML file that will invoke the CFC tag.
 

Invoking the CFC into a new ColdFusion object
In this example you will copy, or instantiate, the cffunction tags declared in the CFC into the local “variables" scope using the “CFO" key. Keys, or variables, placed within the variables scope are available to all scripts operating under the application and are case insensitive. For ease of use, you’ll add a property within the variables.CFO object to declare the data source name (DSN).

<CFSCRIPT>
	variables.CFO =createObject("component","CFOTags");
	variables.CFO.DSN = "companyInfo";
</CFSCRIPT>

With your object now available to your local “variables” scope, you can now do call any method within it. You can also call any properties you set too. The script below will look like the following:

<CFSCRIPT>
  /* Set the SQL String */
  variables.SQLString = 
  "Select * From LoginInfo where UserID='BobZ' and Password = 'Ads10'";
  /* Call the Query Method within the CF object */
  checkUser=CFO.QUERY(SQLString);
</CFSCRIPT>

Notice how you didn’t have to send in the data source name? The line you added to the QUERY function in an earlier reference, the property, “DSN" using “this" accomplished just that. If you’re familiar with ActionScript, this logic is very similar. The “this" simply references methods and properties within the same object. Because you defined the property “variables.CFO.DSN," the method was able to access it.

Now, use the DUMP function to output the contents of the variables structure, to see what it looks like. The dump tag is a great tool to monitor the methods and properties of your objects.

<CFSCRIPT>
/* Dump out the structure*/
	CFO.DUMP(variables);
</CFSCRIPT>
 
Figure 2: The CFO object structure outputted by the cfdump tag.

Figure 2: The CFO object structure as outputted by the cfdump tag.
(click image for full-size view)

 

This screen shot shows the CFO object as a key within the variables structure. You can see each function (or method) available within the CFO object. You can also see the property, “DSN" with its value, “companyInfo" in the right column.

Building a CFC with the cfscript function
Let’s go one step further and add a new method to the CFC. Because I’m a cfscript fan, I won’t use the cffunction tags. This time, I’ll build the CFC method with the cfscript function.

At the bottom of your CFC file, (just above </CFCOMPONENT>) add the following script:

<CFSCRIPT>
  function authenticateUser(username, password) {
  var SQLString = "SELECT UserID FROM LoginInfo 
	    WHERE UserID='#arguments.username#' 
	    AND Password = '#arguments.password#'";
	 /* perform the Query, remember, the DSN is already set! */
	 var checkUser=this.QUERY(SQLString);
	 /* Trace the SQL Statement to the Browser */
	 this.OUTPUT("Trace: " & SQLString, true);
	 /* Return a value of true or false to the user */
	 if (checkUser.recordCount neq 0) return true;
	  else return false;
  }
</CFSCRIPT>

This cfscript function will call some of the functions you declared within the CFC. (Note, that’s where the “this" comes in). The “this" is not required, but it’s always preferable to scope variables so that ColdFusion doesn’t search all the server to find it.

Now I’ll step through the function line by line. First, the function, authenticateUser, was defined with two arguments, “username" and “password". Next, a SQL string was developed to select the UserID from the LoginInfo table, where the supplied username and password arguments are passed.

The value of SQLString is then sent to the “QUERY" function, defined earlier within the CFC. The data returned will be stored in a local function variable called "checkUser." The data source is not required, because it is set as a property of the ColdFusion (CFO) object. Following the query, a simple cfoutput tag lets you see what was sent to the query.

Finally, a recordCount challenge for the query, named checkUser checks for a value of zero. If it isn’t zero, it means a match was found, and a Boolean value of “true" is sent back to the caller.

Tip: You should be aware that the SQL mentioned in the above code has the potential of an injection hack (someone putting some malicious code within the login and password fields). To compensate for that, you can (optionally) escape the single quotes using a replace command:

var SQLString = "Select UserID From LoginInfo where 
UserID='#replace(arguments.username,"'","''","ALL")#' and 
Password = '#replace(arguments.password,"'","''","ALL")#'";

Accessing the authenticateUser() function
Now the authentication function can now be accessed from any ColdFusion page by simply calling the authenticate method, passing the username and password.

<CFSCRIPT>
	IF (CFO.authenticateUser("BobZ", "Ads10")) { 
		/* User Authenticated*/ 
		CFO.Output("Success!");
		}
	ELSE {
		/* User Login Failed */
		CFO.Output("Failed!");
	}
</CFSCRIPT>

In most cases, you wouldn’t hardcode the username and password. I only hardcoded the values for demonstration purposes. Typically, you’d use parameters sent from a form post method, as follows:

CFO.authenticateUser(FORM.username, FORM.password)

Clearly you can do a lot with this concept. I hope I've helped you see what you can achieve with this approach. Certainly, there are other ways to achieve what I've set out to do in this column. This article was intended to start you thinking about objects, methods and properties. Object-oriented ColdFusion development is powerful. If you want to excel in ActionScript with Macromedia Flash MX or the Macromedia Flash Communication Server, I strongly recommend you read more about them in the application developer centers and in books.

You can find a lot of functions on the Common Function Library Project. This open-source repository of ColdFusion functions is managed by Ray Camden and Rob Brook-Bilson. Check it out, there are already a number of ColdFusion Tag Libraries converted to cfscript functions.

 

About the author
Kevin Towes is a Co-Founder and Chief Technical Officer of Pangaea NewMedia Inc. in Toronto, Canada. His experience ranges from traditional film, photography, and sound to 3D animation and database and software development. A leader in the ColdFusion community, Kevin is also an accomplished Macromedia Flash developer. His expertise in Macromedia Flash and ColdFusion has enabled him to understand how to integrate the creative strengths of Macromedia Flash into a server environment. Kevin founded the Toronto ColdFusion User Group, one of the largest such groups in the world and is a certified ColdFusion Developer who has led his team at Pangaea to achieve much success with the Macromedia suite of products. Kevin is a regular speaker at industry conferences, workshops and schools throughout North America including the annual Macromedia Developer Conference. He is the author of the upcoming book, Flash Communication Server MX, published by NewRiders.