Code Samples

Here's our example form; stripped down to the absolute bare essentials.

Bold fields are required.

Verification

Verification Information

Type the characters you see in this picture. This ensures that a person, not an automated program, is submitting this form.

Working with Alagad's CAPTCHA component is a breeze, provided you get past a few sticky points. I'm not a fan of the code in the examples, so I came up with my own technique. Here's the working bits of that technique.

If you don't know what CAPTCHA is, you can read all about it at Wikipedia's CAPTCHA page.

Source Code

<!--- captcha --->

<cfscript>
  app = StructNew();
  app.starting_disk_path = '{Path to root directory of site}';  

  app.images = StructNew();
  app.images.root = '{Subdirectory for images}';

  app.chars = StructNew();
  app.chars.password = '{Comma-delimited list of characters deemed safe to use in passwords}';
  
  app.valid_data = 1;
  app.errormessage = 'We encountered errors in the information you submitted.  Please check the fields marked below and try again.';
  app.errorPrefix = '<p class="error">';
  app.errorSuffix = '</p>';
  
  error = StructNew();
</cfscript>

<cfinclude template="captcha/act_captcha.cfm">
<cfif LCase(cgi.request_method) EQ "post">
  <cfinclude template="captcha/val_captcha.cfm">
  <cfinclude template="captcha/pro_captcha.cfm">
</cfif>
<cfinclude template="captcha/dsp_captcha.cfm">
<!--- udf_captcha --->

<!--- Normally these UDFs would be included in application.cfm, not in an include file like this --->

<cfscript>
  function CreatePassword(length, characters)
  {
    var returnValue = '';
    var delimiters = ',';
    var i = 1;
    var low = 1;
    var high = 1;
    if(ArrayLen(arguments) GTE 3)
      delimiters = arguments[3];
    high = ListLen(characters, delimiters);
    for(i = 1; i LTE length; i = i + 1)
      returnValue = returnValue & ListGetAt(characters, RandRange(low, high));
    return returnValue;
  }

  function FormValueFormat(string)
  {
    var returnValue = string;
        string = Replace(string, '&', '&amp;', 'ALL');
        string = Replace(string, '"', '&quot;', 'ALL');
        string = Replace(string, '<', '&lt;', 'ALL');
        string = Replace(string, '>', '&gt;', 'ALL');
    return string;
  }
</cfscript>
<!--- act_captcha --->

<cfif NOT DirectoryExists(app.starting_disk_path & app.images.root & "/captcha/")>
  <cfdirectory action="create" directory="#app.starting_disk_path##app.images.root#/captcha/">
</cfif>

<cfscript>
  captcha = CreateObject('component', 'captcha');
  captcha.configure(app.starting_disk_path & app.images.root & '/captcha/');
  captcha.output = captcha.createCaptcha(CreateUUID() & '.jpg', CreatePassword(9, app.chars.password));
</cfscript>

<cfparam name="form.captcha" default="">
<cfparam name="form.captcha_hash" default="#captcha.output.hash#">
<cfparam name="form.captcha_file" default="#captcha.output.filename#">
<!--- Reset the captcha_hash value to the new hash if validation fails --->

<cfscript>
  error.captcha = '';
</cfscript>
<!--- dsp_captcha --->

<cfoutput>
  <h1>#app.applications[app.section].title#</h1>
  
  <cfif NOT Val(app.valid_data)>
  #app.errorPrefix##app.errorMessage##app.errorSuffix#
  </cfif>

  <p>Here's our example form; stripped down to the absolute bare essentials.</p>
  
  <form action="#app.script_name##app.tokens["?"]#" method="post" class="noprint">
    <p><strong>Bold</strong> fields are required.</p>
    <fieldset><legend>Verification</legend>
      <input type="hidden" name="captcha_hash" value="#form.captcha_hash#" />
      <input type="hidden" name="captcha_file" value="#form.captcha_file#" />
      <div class="notes">
        <h4>Verification Information</h4>
        <p class="last">Type the characters you see in this picture.  This ensures that a person, not an automated program, is submitting this form.</p>
      </div>
      <div class="required">
        <label for="captcha">Picture:</label>
        <img src="/images/captcha/#form.captcha_file#" border="0" alt="" />
      </div>
      <div class="required<cfif Len(error.captcha)> error</cfif>">
        #error.captcha#
        <label for="captcha">Characters:</label>
        <input type="text" name="captcha" id="captcha" class="inputText" size="10" maxlength="25" value="#FormValueFormat(form.captcha)#" />
      </div>
    </fieldset>
    <fieldset>
      <div class="submit">
        <input type="submit" class="inputSubmit" value="Send &raquo;" />
      </div>
    </fieldset>
  </form>

  <cfinclude template="#app.mapping##app.static.root#/content/code/coldfusion/captcha.txt">

</cfoutput>
<!--- val_captcha --->

<cfscript>
  if(NOT Len(form.captcha))
    error.captcha = 'Required.';
  else if(NOT captcha.validate(form.captcha_hash, form.captcha))
    error.captcha = 'The characters you type must match the characters in the picture. Please try again.';

  if(Len(error.captcha))
  {
    form.captcha_hash = captcha.output.hash;
    form.captcha_file = captcha.output.filename;
  }

  for(key IN error)
  {
    if(Len(error[key]))
    {
      error[key] = app.errorPrefix & error[key] & app.errorSuffix;
      app.valid_data = 0;
    }
  }
</cfscript>
<!--- pro_captcha --->

<cfif Val(app.valid_data)>
  <!--- Everything is validated, do whatever the app is supposed to do with valid data --->
</cfif>