Posted in jQuery, JavaScript, ColdFusion | Posted on 03-14-2011 | 5,254 views
A few years ago I wrote a quick blog entry on working with CAPTCHA and ColdFusion. (Quick and dirty CAPTCHA Guide - for ColdFusion 8) A reader on that entry asked if it was possible to add a "reload if you can't read feature" to the CAPTCHA. We've all seen CAPTCHAs before that are impossible to read. For many of these forms you have no choice but to submit the form and hope the next one is better. But more and more forms are allowing you to reload just the CAPTCHA. Here is a quick example of how I modified the earlier blog entry to support this.
To start off - I modified my code from the old entry to avoid using a hash of the CAPTCHA for validation. Instead I stored the value in the session scope and verified it there. Here is the modified template. I'm not going to explain it since it's 95% the same as the old blog entry, but as you can see I now don't bother with a hash.
2 <cfset var chars = "23456789ABCDEFGHJKMNPQRS">
3 <cfset var length = randRange(4,7)>
4 <cfset var result = "">
5 <cfset var i = "">
6 <cfset var char = "">
7
8 <cfscript>
9 for(i=1; i <= length; i++) {
10 char = mid(chars, randRange(1, len(chars)),1);
11 result&=char;
12 }
13 </cfscript>
14
15 <cfreturn result>
16</cffunction>
17
18<cfset showForm = true>
19<cfparam name="form.name" default="">
20<cfparam name="form.comments" default="">
21<cfparam name="form.captcha" default="">
22
23<cfif isDefined("form.send")>
24 <cfset errors = "">
25
26 <cfif not len(trim(form.name))>
27 <cfset errors = errors & "You must include your name.<br />">
28 </cfif>
29
30 <cfif not len(trim(form.comments))>
31 <cfset errors = errors & "You must include your comments.<br />">
32 </cfif>
33
34 <cfif form.captcha neq session.captcha>
35 <cfset errors = errors & "You did not enter the right text. Are you a spammer?<br />">
36 </cfif>
37
38 <cfif errors is "">
39 <!--- do something here --->
40 <cfset showForm = false>
41 </cfif>
42
43</cfif>
44
45<cfif showForm>
46
47 <cfset session.captcha = makeRandomString()>
48
49 <cfoutput>
50 <p>
51 Please fill the form below.
52 </p>
53
54 <cfif isDefined("errors")>
55 <p>
56 <b>Correct these errors:<br />#errors#</b>
57 </p>
58 </cfif>
59
60 <form action="#cgi.script_name#" method="post" >
61 <table>
62 <tr>
63 <td>Name:</td>
64 <td><input name="name" type="text" value="#form.name#"></td>
65 </tr>
66 <tr>
67 <td>Comments:</td>
68 <td><textarea name="comments">#form.comments#</textarea></td>
69 </tr>
70 <tr>
71 <td>Enter Text Below:</td>
72 <td><input type="text" name="captcha"></td>
73 </tr>
74 <tr>
75 <td colspan="2">
76 <cfimage action="captcha" width="300" height="75" text="#session.captcha#">
77 </td>
78 </tr>
79 <tr>
80 <td> </td>
81 <td><input type="submit" name="send" value="Send Comments"></td>
82 </tr>
83 </table>
84 </form>
85 </cfoutput>
86
87<cfelse>
88
89 <cfoutput>
90 <p>
91 Thank you for submitting your information, #form.name#. We really do care
92 about your comments. Seriously. We care a lot.
93 </p>
94 </cfoutput>
95
96</cfif>
If you want to run this, you can do so here. But that isn't the interesting one. Let's look at a nicer version.
In order to support reloading just the CAPTCHA, I moved the CAPTCHA display into a DIV I'll be loading via Ajax. So where before I had the cfimage tag, now I have just this:
I used some jQuery to load it:
showcaptcha.cfm now includes the logic to generate a random CAPTCHA string and to store/render it.
2 <cfset var chars = "23456789ABCDEFGHJKMNPQRS">
3 <cfset var length = randRange(4,7)>
4 <cfset var result = "">
5 <cfset var i = "">
6 <cfset var char = "">
7
8 <cfscript>
9 for(i=1; i <= length; i++) {
10 char = mid(chars, randRange(1, len(chars)),1);
11 result&=char;
12 }
13 </cfscript>
14
15 <cfreturn result>
16</cffunction>
17
18<cfset session.captcha = makeRandomString()>
19<cfimage action="captcha" text="#session.captcha#" width="300" height="75">
Ok, so how do we handle reload? After my div, I added a quick link:
And then wrote a lot of JavaScript to handle clicks there. (OK, maybe not a lot of code - but jQuery saves me such much time I've got to pretend I actually work!)
2 $("#captchaDiv").load("showcaptcha.cfm");
3 e.preventDefault();
4});
And that's it. The form page has changed quite a bit so I'll display it completely below. Before that you can demo it here:
2<cfparam name="form.name" default="">
3<cfparam name="form.comments" default="">
4<cfparam name="form.captcha" default="">
5
6<cfif isDefined("form.send")>
7 <cfset errors = "">
8
9 <cfif not len(trim(form.name))>
10 <cfset errors = errors & "You must include your name.<br />">
11 </cfif>
12
13 <cfif not len(trim(form.comments))>
14 <cfset errors = errors & "You must include your comments.<br />">
15 </cfif>
16
17 <cfif form.captcha neq session.captcha>
18 <cfset errors = errors & "You did not enter the right text. Are you a spammer?<br />">
19 </cfif>
20
21 <cfif errors is "">
22 <!--- do something here --->
23 <cfset showForm = false>
24 </cfif>
25
26</cfif>
27
28<cfif showForm>
29
30 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
31 <script>
32 $(document).ready(function() {
33 $("#captchaDiv").load("showcaptcha.cfm");
34
35 $("#reloadLink").click(function(e) {
36 $("#captchaDiv").load("showcaptcha.cfm");
37 e.preventDefault();
38 });
39 })
40 </script>
41
42 <cfoutput>
43 <p>
44 Please fill the form below.
45 </p>
46
47 <cfif isDefined("errors")>
48 <p>
49 <b>Correct these errors:<br />#errors#</b>
50 </p>
51 </cfif>
52
53 <form action="#cgi.script_name#" method="post" >
54 <table>
55 <tr>
56 <td>Name:</td>
57 <td><input name="name" type="text" value="#form.name#"></td>
58 </tr>
59 <tr>
60 <td>Comments:</td>
61 <td><textarea name="comments">#form.comments#</textarea></td>
62 </tr>
63 <tr>
64 <td>Enter Text Below:</td>
65 <td><input type="text" name="captcha"></td>
66 </tr>
67 <tr>
68 <td colspan="2">
69 <div id="captchaDiv"></div>
70 Can't read? <a href="" id="reloadLink">Reload</a>
71 </td>
72 </tr>
73 <tr>
74 <td> </td>
75 <td><input type="submit" name="send" value="Send Comments"></td>
76 </tr>
77 </table>
78 </form>
79 </cfoutput>
80
81<cfelse>
82
83 <cfoutput>
84 <p>
85 Thank you for submitting your information, #form.name#. We really do care
86 about your comments. Seriously. We care a lot.
87 </p>
88 </cfoutput>
89
90</cfif>


I'm just using --- onclick="window.location.reload();return false;" --- on an anchor next to the image ...
http://tutorial571.easycfm.com/
Hard to tell without Firebug support...
x = Math.floor(Math.random()*100000);
"showcaptcha.cfm?x=" + x;
$.ajaxSetup ({
// Disable caching of ANY AJAX responses.
cache: false
});
This tells jquery to add the current date string to the end of the url each time a request is made. Simple and you never have to think about request caching again.
One Server: coldfusion.image.ImageWriter$ImageWritingException: An exception occurred while trying to write the image.
The other one rendered it fine.
My simple test:
<cfimage action="captcha" width="300" height="75" text="abcd3">
Does anyone have suggestions on why this happens or have they seen it before.
http://www.bennadel.com/blog/1289-ColdFusion-8-0-1...
Are you up to date with your hot fixes?
Where does
$("#captchaDiv").load("showcaptcha.cfm");
go in the form so the captcha image loads?
The requested scope session has not been enabled.
Before session variables can be used, the session state management system must be enabled using the cfapplication tag.
Should this be enabled in the CF Admin ?
<cfapplication name = "captcha"
sessiontimeout = #CreateTimeSpan(0, 0, 0, 60)#
sessionmanagement = "Yes">
and the captcha now shows. Thanks for the help!
Regarding the random URL variable, how do I incorporate the code
x = Math.floor(Math.random()*100000);
"showcaptcha.cfm?x=" + x;
into the showCaptcha.cfm code?
What do you mean? It isn't "appearing" - it is simply being added to the end of the main url. It's a way to trick IE into thinking you are asking for something it hasnt asked for before. (Technically it isn't a trick - it IS a new url.)
"This method is working in every browser except IE."
How is it not working for you? Remember that this fixes an issue where IE users would see the same captcha. So are your IE users seeing the same captcha? If so - can you share the URL of where this is so I can test it myself?
$("#reloadLink").click(function(e) {
$("#captchaDiv").load("showcaptcha.cfm");
e.preventDefault();
});
$("#reloadLink").click(function(e) {
x = Math.floor(Math.random()*100000);
$("#captchaDiv").load("showcaptcha.cfm?x="+x);
e.preventDefault();
});
Is this incorrect?
[Add Comment] [Subscribe to Comments]