Allow Multiple CF Studio Instances
Ever have a wierd situation where you need two copies of ColdFusion Studio running at the same time, on the same computer? With a quick registry hack, you can do it! This only works for Studio 5 - for prior versions, do a googlesearch for "allowmultipleinstances".
[HKEY_CURRENT_USER\Software\Macromedia\Studio5]
"AllowMultipleInstances"="1"
Alternating Colored Rows
Ever wondered how to alternate colored rows in a table? Maybe the first one should be blue, the second one white, the third one back to blue, the fourth back to white, etc. This is the code that will do it for you.
<cfoutput query="myQuery">
<cfif myQuery.currentRow MOD 2 is 1>
<cfset bgcolor="##c0c0c0">
<cfelse><cfset bgcolor="##00ffff"></cfif>
<tr bgcolor="#bgcolor#">
<td>#name#</td><td>#maker#</td><td>#rating#</td>
</tr>
</cfoutput>
Securing Access Through index.cfm
In early versions of Fusebox, Application.cfm was shunned. In Fusebox 3, it is not recommended to use Application.cfm for much functionality because it is run once per request, regardless of subsequent <cfmodule> calls, which might produce unexpected results. So what should you put in Application.cfm and why? You should put code to secure access only to index.cfm (or your default webserver document like default.cfm). That way, you can be guaranteed that all requests by users go through index.cfm. You can still <cfmodule> individual fuses, though.
Place this code in Application.cfm:
<cfif listLast(cgi.script_name,'/') neq "index.cfm">
<cflocation url="/index.cfm">
</cfif>
<cfcontent> Works With Fusebox 3
Using <cfcontent> with Fusebox 3 is a piece of cake. Fusebox 3 uses a form of output buffering by way of the CF5 native tag <cfsavecontent> or the custom tag <cf_fbx_saveContent>. But these two tags are admitted by Macromedia to be incompatible with <cfcontent>. Well that's just not true! Thanks to Julian Halliwell for this one.
<cfset filename=chr(34) & attributes.file & chr(34)>
<cfheader name="Content-Disposition"
value="attachment;filename=#filename#">
<cfcontent
type="application/unknown"
deletefile="No"
file="#absolute_path#\#attributes.file#">
<cfmail> From Humans
The ColdFusion documentation doesn't tell us about this hidden gem. Make your <cfmail>ings much more user friendly.
<cfmail
from="Nat Papovich<nat@fusium.com>"
to="Erik Voldengen<erik@fusium.com>"
subject="Human-looking to and from">
Using Identity Keys in SQL Server
Most applications rely on primary keys in database tables. Many of those same applications use the auto-increment capabilities of some DBMSes like MSSQL Server. When inserting a record in a table that uses auto-increment primary keys, you do not have to insert the value of the primary key yourself - the DB does it for you. But what if you want to know the value of the row's primary key that you just inserted? Commonly, developers will run two queries in a row, wrapped in <cftransaction>. The first one inserts the record and the second one selects the newest record. But using this syntax, SQL server can insert the record as well as return the value of the new primary key all in one query.
<cfquery name="insert" datasource="DSN">
set nocount on
insert into customer (firstName, lastName)
values
('#attributes.firstName#', '#attributes.LastName#')
select @@identity as newID
set nocount off
</cfquery>
I am the new primary key value:
<cfoutput>#insert.newID#</cfoutput>
Insert Autonumbers Without Autonumber Data Type
Most people use their DB's auto-incremental integer data type to create new primary keys. In MS Access, it's an "autonumber" data type. In MS SQL Server, it's an integer data type with the "Identity" attribute set to "1". If you've ever had to migrate data from one database to another, you've probably noticed how those primary keys can get in the way sometimes. The trouble is that autonumbers can't be reused, even if the row is permanently deleted. To combat this problem, you can do a lookup of the current highest number, along the lines of Steve Nelson's <cf_maxID> tag, or wrap a "select max(ID)" query with your insert query with <cftransaction>. But we think those ways are a little hokey. Instead, use this syntax to let the DB create a new incremental primary key while inserting the new data - all in one query.
<cfquery name="insert" datasource="DSN">
INSERT INTO myTable
(autoID,
field1)
SELECT
IsNull(MAX(autoID),0)+1 AS autoID,
#attributes.field1# AS field1
FROM myTable
</cfquery>
Assigning values to form fields with dynamic variable names
From time to time you'll need to have a bunch of dynamically named form fields. And on occasion, you may need to use some Javascript magic to assign values to these fields. How? Use this code.
<html>
<head>
<title>Fusium</title>
<script language="JavaScript" type="text/JavaScript">
<!--
function setIt(formName,fieldname,theValue) {
temp = "document." + formName + "." + fieldname
+ ".value = '" + theValue + "'";
eval(temp); }
//-->
</script>
</head>
<body>
<form name="testForm">
<input type="text" name="foo">
<br><br>
<input type="button" value="Set Value"
onClick="setIt('testForm','foo','Fusium');">
<input type="Reset" value="Clear Value">
<input type="button" value="Fusium"
onClick="document.location.href='http://www.fusium.com'">
</form>
</body>
</html>
Mime Types And File Extensions
Ever wondered what mime types translate to what file extensions? We did, until we assembled this list. If you have more, let us know! (Thanks to Steve Robinson for the additions.)
<cfscript>
mime=structNew();
mime.ai="application.postscript";
mime.asc="text/plain";
mime.au="audio/basic";
mime.avi="video/avi";
mime.bmp="image/bmp";
mime.cfm="text/plain";
mime.cpt="application/mac-compactpro";
mime.csv="text/plain";
mime.dbm="text/plain";
mime.doc="application/msword";
mime.exe="application/octet-stream";
mime.gif="image/gif";
mime.html="text/html";
mime.htm="text/html";
mime.jpeg="image/jpeg";
mime.jpg="image/jpeg";
mime.mid="audio/midi";
mime.mov="video/quicktime";
mime.mp2="audio/mpeg";
mime.mp3="audio/mpeg";
mime.mpeg="video/mpeg";
mime.mpg="video/mpeg";
mime.pdf="application/pdf";
mime.png="image/pdf";
mime.ppt="vnd.ms-powerpoint";
mime.ps="application/postscript";
mime.ram="audio/x-pn-realaudio";
mime.rpm="audio/x-pn-realaudio-plugin";
mime.rtf="application/rtf";
mime.sit="application.stuffit";
mime.snd="audio/basic";
mime.swf="application/x-shockwave-flash";
mime.tar="application/x-tar";
mime.tiff="image/tiff";
mime.tif="image/tiff";
mime.txt="text/plain";
mime.wav="audio/wav";
mime.wrl="model/vrml";
mime.xbm="image/x-xbitmap";
mime.xpm="image/x-xpixmap";
mime.zip="application/zip";
mime._default="application/octet-stream";
</cfscript>
P3P, IE6, and Third Party Cookies
Microsoft IE 6 introduced more rigid security based on
P3P. The main effect this has on the developer is third party cookies are no longer accepted. The solution is to either have all your users set their privacy settings to LOW, or publish a P3P policy.
Below is a simple line of code you can use to either work around this problem, or use temporarily while you actually create a P3P policy for your site/server. Note a P3P policy is basically a serialized representation of your site's privacy policy. Publishing a policy that doesn't match up with your site's privacy policy could potentially result in a lawsuit, though I really doubt that'd ever happen.
<!--- P3P Policy --->
<cfheader name="P3P" value="CP='TST'" />
Accessing a Recordset in Array Notation
Ever wanted to get the data from a specific row of a recordset, or wanted to access a different row's data while looping over a recordset? Well you can, by accessing the recordset in array notation. The basic syntax is queryname["columnname"][rownumber].
<cfscript>
myQ=queryNew("col1,col2");
queryAddRow(myQ,3);
querySetCell(myQ,"col1","this is column 1, row 1",1);
querySetCell(myQ,"col2","this is column 2, row 1",1);
querySetCell(myQ,"col1","this is column 1, row 2",2);
querySetCell(myQ,"col2","this is column 2, row 2",2);
querySetCell(myQ,"col1","this is column 1, row 3",3);
querySetCell(myQ,"col2","this is column 2, row 3",3);
</cfscript>
<cfoutput>
Directly accessing column 1, row 3:
"#myQ["col1"][3]#"<br>
Directly accessing column 2, row 1:
"#myQ["col2"][1]#"<br>
Output the last row, the last column:
"#myQ[listLast(myQ.columnList)][myQ.recordCount]#"
</cfoutput>
Session End On Browser Close
Use this code to end a user's session when the close their browser. More information can be found in
this Macromedia technote. If you're using session variables instead of client variables, make sure you DON'T enable J2EE session variables in the CF Administrator or else CFID and CFToken will not exist.
<cfapplication name="fusium" sessionmanagement="No"
setclientcookies="No" clientmanagement="Yes">
<cfif not IsDefined("cookie.cfid")>
<cfcookie name="CFID" value="#client.cfid#">
<cfcookie name="CFToken" value="#client.cftoken#">
</cfif>
Anti Session Hijacking
If users cut and paste urls that include CFID and CFTOKEN, they can take over each others session. That's not good news for you, obviously. Troublesome users and wannabe hackers might also try randomly changing CFID and CFTOKEN values in their url until something happens. This is usually not a problem, but it could be.
<!--- session hijacking --->
<cfif isDefined("cookie.uniqueID")>
<cfif (NOT isDefined("client.uniqueID")) OR
(client.uniqueID NEQ cookie.uniqueID)>
<cfcookie name="uniqueID" value="" expires="NOW">
<cfcookie name="CFID" value="" expires="NOW">
<cfcookie name="CFToken" value="" expires="NOW">
<cf_location url="#request.nonSecureSelf#?hj=1">
<cfabort>
</cfif>
<cfelseif isDefined("client.uniqueID")>
<cfcookie name="uniqueID" value="" expires="NOW">
<cfcookie name="CFID" value="" expires="NOW">
<cfcookie name="CFToken" value="" expires="NOW">
<cf_location url="#request.nonSecureSelf#?hj=1">
<cfabort>
<cfelse>
<cfset variables.uniqueID=CreateUUID()>
<cfcookie name="uniqueID" expires="10"
value="#variables.uniqueID#">
<cfset client.uniqueID=variables.uniqueID>
</cfif>
Storing Files in a DB
You can store files in the database. You don't need to use BLOBs, that's crazy talk. Normal text fields can be used, so you can even store files in an MS Access database. To good to be true? Nah, here's the code. This should work for CF 4.0 and above.
<!--- Get the file: --->
<cffile action="upload"
filefield="BannerImage"
destination="#ExpandPath("./")#"
NAMECONFLICT="OVERWRITE">
<!--- Get the mime type in a string: --->
<cfset mtype="#file.ContentType#/#file.ContentSubType#">
<!--- get file, read as binary --->
<cffile ACTION="READBINARY"
FILE="#File.ServerDirectory#\#File.ServerFile#"
VARIABLE="ImageData">
<!--- insert it into db --->
<cfquery name="add" datasource="#request.dsn#">
insert into Things (
MimeType,
b64string
) values (
'#Variables.mtype#',
'#ToBase64(ImageData)#',
)
</cfquery>
<!--- display it with cfcontent --->
<img src="./getImage.cfm?thingID=123456&mtype=#get.MimeType#"
border="0" alt="Banner Image">
<!--- getImage.cfm would have something like: --->
<CFQUERY NAME="RetrieveImage" DATASOURCE="eschoolzone">
select b64String,MimeType from Things where ThingID='#URL.ThingID#'
</CFQUERY>
<cfset ImageData = ToBinary(RetrieveImage.b64String)>
<CFLOCK
TIMEOUT="10"
NAME="GetThing"
THROWONTIMEOUT="No"
TYPE= "Exclusive">
<CFFILE ACTION="Write"
FILE="#ExpandPath("./")#temp.tmp"
OUTPUT="#ImageData#"
NAMECONFLICT="OVERWRITE">
<CFHEADER NAME="Expires" VALUE="0">
<CFHEADER NAME="Pragma" VALUE="no-cache">
<CFCONTENT TYPE="#RetrieveImage.MimeType#"
FILE="#ExpandPath("./")#temp.tmp"
DELETEFILE="Yes">
</CFLOCK>
Validating Variables For Queries
Running dynamic queries by using variables passed in a form or URL string is common enough, but what happens when a malicious user modifies those values? If userID is passed on the URL string, it could be anything, including something like "?userID=14%3BDROP%20TABLE%20users" Which would be outputted as "SELECT * FROM users WHERE userID=14;DROP TABLE users" In SQL Server this SQL statement would drop the users table, which would erase all the data stored inside. How do you get around that? By using the val() function or using <cfqueryparam>.
<cfquery name="userDetail" datasource="#request.DSN#">
SELECT * FROM users
WHERE productID=#val(attributes.productID)#
</cfquery>
or
<cfquery name="userDetail" datasource="#request.DSN#">
SELECT * FROM users
WHERE productID=
<cfqueryparam value="#attributes.userID#"
cfsqltype="CF_SQL_INTEGER">
</cfquery>