In my work environment we have ColdFusion 7 and I like to write my templates in cfscript, but since CF7 does not support some new scripting functions in CF8, I wrote a component to mimic those functions and allow me to stay focused on the scripting.

Well, it is not my original idea, I saw it from other blogs, but I added some value to it with some additional functions.
You may download the component here


First of all, I instantiate the component as a local variable called CF, then I call it from the script as cf.functionName.
Here is the list of functions available in the component:

  • directory: cf.directory(action, directory, newdirectory, sort, recurse,filter)
  • file: cf.file(action, file, output, source, destination, charset)
  • dump: cf.dump(var, label, expand)
  • abort: cf.abort()
  • query: cf.query(query, datasource)
  • location: cf.location(url, addToken)
  • flush: cf.flush(interval) do not use it if you have a cflocation in your template otherwise the cflocation will not work.
  • trace: cf.trace(text, interval, crlf) used to display messages on screen during the process for debugging purposes. Same as cf.flush, if you use it, any cflocation in your template will not work.
  • mailIt: cf.mailIt(mailFrom, mailTo, subject, msg, failTo, mailType) sends email messages
  • postError: cf.postError(message, sendMail, withTrace, abort, cfLogFile, webmasterEmail, errorType, thread, date, time, aplication, template, line) logs the error, sends message, abort, etc.
  • fileWriteUTF8: cf.fileWriteUTF8(sFilePath, sInput) creates an empty text file with the BOM header for UTF-8, then you can append to it using cf.file

Here is the component:<cfcomponent>
<cfset this.logFile = "myLogFile" />
<cfset this.webmasterEmail = "webmaster@myDomain.com" />
<cfset this.applicationName = "myApplication" />
<cffunction name="resultInit" access="private" output="false" returntype="Any">
   <cfscript>
   result = structNew();
   result.status = true;
   result.content = "";
   return result;
   </cfscript>
</cffunction>
<cffunction name="directory" access="remote" output="true" returntype="any">
   <cfargument name="action" type="string" required="true" />
   <cfargument name="directory" type="string" required="true" />
   <cfargument name="newdirectory" type="string" required="false" default="" />
   <cfargument name="sort" type="string" required="false" default="name asc" />
   <cfargument name="recurse" type="string" required="false" default="false" />
   <cfargument name="filter" type="string" required="false" default="" />
   <cfset result = resultInit() />
   <cfswitch expression="#arguments.action#">
      <cfcase value="create">
         <cftry>
            <cflock name="cfdirectory" type="exclusive" timeout="10">
               <cfdirectory action="create" directory="#arguments.directory#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>
         </cftry>
      </cfcase>
      <cfcase value="delete">
         <cftry>
            <cflock name="cfdirectory" type="exclusive" timeout="10">
               <cfdirectory action="delete" directory="#arguments.directory#" />
            </cflock>
            <cfcatch type="any">
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>
         </cftry>
      </cfcase>
      <cfcase value="rename">
         <cftry>
            <cflock name="cfdirectory" type="exclusive" timeout="10">
               <cfdirectory action="rename" directory="#arguments.directory#" newdirectory="#arguments.newdirectory#" />
            </cflock>
            <cfcatch type="any">
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="list">
         <cftry>
            <cflock name="cfdirectory" type="readonly" timeout="10">
               <cfdirectory action="list" directory="#arguments.directory#" name="result.content" sort="#arguments.sort#" filter="#arguments.filter#" recurse="#arguments.recurse#" />
            </cflock>
            <cfcatch type="any">
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfdefaultcase>
         <cfset result.status = false />
         <cfset result.content = structNew() />
         <cfset result.content.message = "Invalid operation requested!" />
         <cfset result.content.detail = "" />
      </cfdefaultcase>
   </cfswitch>
   <cfreturn result />
</cffunction>
<cffunction name="file" access="remote" output="true" returntype="any">
   <cfargument name="action" type="string" required="true" default="read" />
   <cfargument name="file" type="string" required="false" default="" />
   <cfargument name="output" type="string" required="false" default="" />
   <cfargument name="source" type="string" required="false" default="" />
   <cfargument name="destination" type="string" required="false" default="" />
   <cfargument name="charset" type="string" required="false" default="UTF-8" />
   <cfset result = resultInit() />
   <cfswitch expression="#arguments.action#">
      <cfcase value="write">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="write" file="#arguments.file#" output="#arguments.output#" charset="#arguments.charset#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="copy">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="copy" source="#arguments.source#" destination="#arguments.destination#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="rename">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="rename" source="#arguments.source#" destination="#arguments.destination#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>
         </cftry>
      </cfcase>
      <cfcase value="move">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="move" source="#arguments.source#" destination="#arguments.destination#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="delete">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="delete" file="#arguments.file#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="read">
         <cftry>
            <cflock name="myComponent-cffile" type="readonly" timeout="10">
               <cffile action="read" file="#arguments.file#" variable="result.content" charset="#arguments.charset#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfcase value="append">
         <cftry>
            <cflock name="myComponent-cffile" type="exclusive" timeout="10">
               <cffile action="append" file="#arguments.file#" output="#arguments.output#" />
            </cflock>
            <cfcatch>
               <cfset result.status = false />
               <cfset result.content = cfcatch />
            </cfcatch>         
         </cftry>
      </cfcase>
      <cfdefaultcase>
         <cfset result.status = false />
         <cfset result.content = structNew() />
         <cfset result.content.message = "Invalid operation requested!" />
         <cfset result.content.detail = "" />
      </cfdefaultcase>
   </cfswitch>
   <cfreturn result />
</cffunction>
<cffunction name="dump" access="remote" output="true" returntype="any">
   <cfargument name="var" type="any" required="true" />
   <cfargument name="label" type="string" required="false" default="" />
   <cfargument name="expand" type="boolean" required="false" default="true" />
   <cfdump var="#arguments.var#" label="#arguments.label#" expand="#arguments.expand#" />
</cffunction>
<cffunction name="abort" access="remote" output="false" returntype="any">
   <cfabort />
</cffunction>
<cffunction name="query" access="remote" output="false" returntype="Any">
   <cfargument name="query" type="string" required="true" />
   <cfargument name="datasource" type="string" required="false" default="#application.mainDSN#" />
   <cfset result = resultInit() />
   <cftry>
      <cfquery name="result.content" datasource="#arguments.datasource#">
         #arguments.query#
      </cfquery>
      <cfcatch>
         <cfset result.status = false />
         <cfset result.content = cfcatch />
      </cfcatch>
   </cftry>
   <cfreturn result />
</cffunction>
<cffunction name="location" access="remote" output="true" returntype="Any">
   <cfargument name="url" type="string" required="true" />
   <cfargument name="addToken" type="boolean" required="false" default="false" />
   <cflocation url="#arguments.url#" addtoken="#arguments.addToken#" />
</cffunction>
<cffunction name="flush" access="remote" output="true" returntype="Any">
   <cfargument name="interval" type="numeric" required="false" default="10" />
   <cfflush interval="#arguments.interval#" />
</cffunction>
<cffunction name="trace" access="remote" output="true" returntype="Any">
   <cfargument name="text" type="string" required="true" />
   <cfargument name="interval" type="numeric" required="false" default="10" />
   <cfargument name="crlf" type="boolean" required="false" default="true" />
   <cfoutput><cfif arguments.crlf><br/></cfif>#arguments.text#</cfoutput>
   <cfflush interval="#arguments.interval#" />
</cffunction>
<cffunction name="mailIt" access="remote" output="false" returntype="Any">
   <cfargument name="mailFrom" type="string" required="true" />
   <cfargument name="mailTo" type="string" required="true" />
   <cfargument name="subject" type="string" required="true" />
   <cfargument name="msg" type="string" required="true" />
   <cfargument name="failTo" type="string" required="false" default="#this.webmasterEmail#" />
   <cfargument name="mailType" type="string" required="false" default="html" />
   <cfset result = resultInit() />
   <cftry>
      <cfmail from="#arguments.mailFrom#" to="#arguments.mailTo#" failto="#arguments.failTo#" subject="#arguments.subject#" type="#arguments.mailType#">
      #arguments.msg#
      </cfmail>
      <cfcatch>
         <cfset result.status = false />
         <cfset result.content = cfcatch />
      </cfcatch>
   </cftry>
   <cfreturn result />
</cffunction>
<cffunction name="postError" access="remote" output="true" returntype="any">
   <cfargument name="message"         required="true" type="string" />
   <cfargument name="sendMail"         required="false" type="boolean" default="false" />
   <cfargument name="withTrace"      required="false" type="boolean" default="false" />
   <cfargument name="abort"         required="false" type="boolean" default="false" />
   <cfargument name="cfLogFile"      required="false" type="string" default="#this.applicationName#" />
   <cfargument name="webmasterEmail"   required="false" type="string" default="#this.webmasterEmail#" />
   <cfargument name="errorType"      required="false" type="string" default="Any" />
   <cfargument name="thread"         required="false" type="string" default="true" />
   <cfargument name="date"            required="false" type="string" default="true" />
   <cfargument name="time"            required="false" type="string" default="true" />
   <cfargument name="application"      required="false" type="string" default="true" />
   <cfargument name="template"         required="false" type="string" default="" />
   <cfargument name="line"            required="false" type="string" default="" />
   <cfset result = resultInit() />
   <cfif len(trim(arguments.cfLogFile))>
      <cflog file="#arguments.cfLogFile#" application="#arguments.application#" type="#arguments.errorType#"
         text="#arguments.message#" />      
   <cfelse>
      <cflog log="Application" application="#arguments.application#" type="#arguments.errorType#"
         text="#arguments.message#" />      
   </cfif>
   <cfif arguments.sendMail>
      <cfsavecontent variable="msg">
      <cfoutput>
      <body>
      <head>
      <title>Error Message</title>
      </head>
      <div id="wrapper">
         <div id="title">ERROR Occurred in #this.applicationName#</div>
         <div id="text">Message time stamp: #dateFormat(now(),"yyyy-mm-dd")# #timeFormat(now(),"HH:mm:ss")#</div>
         <cfif len(trim(arguments.template))>
            <div id="template">Template: #arguments.template#</div>
         </cfif>
         <cfif len(trim(arguments.line))>
            <div id="line">Line: #arguments.line#</div>
         </cfif>
         <div id="text">#arguments.message#</div>
      </div>
      </body>
      </cfoutput>
      </cfsavecontent>
      <cfset result = mailIt("errorHandler@myDomain.com", "#arguments.webmasterEmail#", "Error occurred in #this.applicationName#", "#msg#") />
   </cfif>
   <cfif arguments.withTrace>
      <cfset trace(arguments.message) />
   </cfif>   
   <cfif arguments.abort>
      <cfabort />
   </cfif>
   <cfreturn result />
</cffunction>
<cffunction name="fileWriteUTF8" access="remote" output="false" returntype="Any">
   <cfargument name="sFilePath" type="string" required="true" />
   <cfargument name="sInput" type="string" required="true" />
   <cfscript>
   // declare jWrite object
   var jWriter = "";
   // create the file stream
   var jFile = createobject("java", "java.io.File").init(sFilePath);
   var jStream = createobject("java", "java.io.FileOutputStream").init(jFile);
   result = resultInit();
   try {
      // output the UTF-8 BOM byte by byte directly to the stream
      jStream.write(239); // 0xEF
      jStream.write(187); // 0xBB
      jStream.write(191); // 0xBF
      // create the UTF-8 file writer and write the file contents
      jWriter = createobject("java", "java.io.OutputStreamWriter");
      jWriter.init(jStream, "UTF-8");
      jWriter.write(sInput);
      // flush the output, clean up and close
      jWriter.flush();
      jWriter.close();
      jStream.close();
   } catch (Any excpt) {
      result.status = false;
      result.content = excpt;
   }
   return result;
   </cfscript>
</cffunction>
</cfcomponent>

So, from my template I will call the cffile function for example like this:
<cfscript>
cf = createObject("component","cffunctions");
result = cf.file(action="read" file=expandPath(myFile.txt);
if (not result.status) cf.postError (result.content.message & "<br />" & result.content.detail, true, true, true); // this will log the error, send a message, show on screen and abort
myDoc = result.content;
</cfscript>

Another example, listing a directory and deleting its contents:
<cfscript>
result = cf.directory(action="list", directory=expandPath(myDirectory), filter="*.jpg");
if (not result.status) cf.postError(result.content.message & "<br/>" & result.content.detail, true, true, true); it logs error, sends message, outputs error and aborts
qDir = result.content;
for (i=1; i lte qDir.recordCount; i=i+1){
   result = cf.file(action="delete", file=qDir.directory[i] & "\" & qdir.name[i]);
   if (not result.status) cf.postError(result.content.message & "<br/>" & result.content.detail, true, true, false); // it logs error, sends message, output error and continue without aborting
}

Generating a UTF-8 file with BOM header:
<cfscript>
result = cf.fileWriteUTF8(expandPath(myFile.xml), '<?xml version="1.0" encoding="UTF-8"?>');
if (not result.status) cf.postError(result.content.message & " - " result.content.detail, true, true, true);
//.... here you add your logic to generate the content for the file
result = cf.file(action="append", file=expandPath(myFile.xml), output=myContent, newLine=true);
if (not result.status) cf.postError(result.content.message & " - " result.content.detail, true, true, true);
</cfscript>

Feel free to add more functions to the component, but please don’t forget to send me a copy so I can update mine too.

One thought on “Scripting Functions for ColdFusion 7 Users

  1. This is good stuff.. Im a big fan of cfscript, this’ll open up some limitations. Thanks! (I found this site looking for dump() (figured why reinvent the wheel…))

Leave a Reply