Saturday, July 22, 2023

Coldfusion Random String Generator

 Today I needed to generate some random strings.  Now, I've used a function for years, but our codebase is mostly tag-based (not cfscript-based) here at work, and I wanted to follow that flow.  What began as rewriting the function I had been using, and adding a new feature, I built upon the work by Joshua Miller (josh@joshuasmiller.com) and came up with the below function.

I'm adding it here to this little-used blog so that a) I will find it again when I go searching the interwebz, and b) so maybe it can help others.  No need to "credit me" or anything like that for this version, and feel free to modify however you like.

<cffunction name="generateRandomString" output="false" returntype="string" access="public" hint="Returns a random string of the specified length of either alpha, numeric or mixed-alpha-numeric characters.">
   <cfargument name="type" type="string" required="true" hint="Type of random string to create." />
   <cfargument name="length" type="numeric" required="true" hint="Length of random string to create." />
   <cfargument name="firstCharAlpha" type="boolean" required="false" default="false" hint="Require first character to be a letter" />

   <!---
      Notes:
         * No functionality to prevent duplicate characters.
      Stats:
      Generated 100,000/99,735 non-duplicate alphanum strings of 5 alphanumeric characters in 1476 ms. Average of 0.01476 ms each.
      Generated 100,000/100,000 non-duplicate alphanum strings of 7 alphanumeric characters in 2114 ms. Average of 0.02114 ms each.
      Generated 100,000/100,000 non-duplicate alphanum strings of 10 alphanumeric characters in 2566 ms. Average of 0.02566 ms each.
      Generated 1,000,000/999,963 non-duplicate alphanum strings of 7 alphanumeric characters in 18367 ms. Average of 0.018367 ms each.
      Generated 1,000,000/1,000,000 non-duplicate alphanum strings of 10 alphanumeric characters in 22135 ms. Average of 0.022135 ms each.
      Generated 2,000,000/1,999,836 non-duplicate alphanum strings of 7 alphanumeric characters in 37435 ms. Average of 0.0187175 ms each.
      Based on this, minimum 7 characters recommended for uniqueness and maybe generate less than 2 million at a time. Heh.
   --->

   <cfset var i = 1 />
   <cfset var nStart = 1 />
   <cfset var randStr = "" />
   <cfset var useList = "" />
   <cfset var numList = "0,1,2,3,4,5,6,7,8,9" />
   <cfset var alphaList = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z" />
   <cfset var secureList = "!,@,$,%,&,*,-,_,=,+,?,~" />

   <cfif arguments.firstCharAlpha AND arguments.type EQ "alphanum" OR arguments.type EQ "secure">
      <!--- Ensure we always get a letter for the first character, and start our loop to build character two and beyond --->
      <cfset nStart = 2 />
      <cfset randStr = listGetAt(alphaList, randRange(1, listLen(alphaList))) />
   </cfif>

   <cfswitch expression="#arguments.type#">
      <cfcase value="alpha">
         <cfset useList = alphaList />
      </cfcase>
      <cfcase value="alphanum">
         <cfset useList = alphaList & numList />
      </cfcase>
      <cfcase value="secure">
         <cfset useList = alphaList & numList & secureList />
      </cfcase>
   </cfswitch>

   <cfloop condition="#len(randStr)# LT #arguments.length#">
      <cfset randStr &= listGetAt(useList, randRange(1, listLen(useList))) />
   </cfloop>

   <cfreturn randStr />
</cffunction>