Remote Synthesis
Search my blog:
Viewing By Entry / Main
Apr 24, 2006

Adding Open-Source LylaCaptcha to BlogCFC

Are you tired of comment spam? Well, I am not...I love it (cue Police Squad). Well, fortunately Peter Farrell recently released LylaCaptcha, an highly configurable and high-quality open-source captcha solution. Also fortunately, adding LylaCaptcha to Ray Camden's BlogCFC is also easy...here's how.Obviously the first thing you need to do is download LylaCaptcha and unzip it. I placed my copy in the org folder of BlogCFC as this seemed like an obvious location for it.

The next step is to edit the xml config file for LylaCaptcha. You will need to set the location for the temp image files by modifying the outputDirectory attribute. I set mine to /img/captcha/ which is a folder I created for this purpose. I also decided to change height config to 45 and font size to 25 to shrink the size of the generated file (this is purely for appearance sake...this step is not necessary but it shrinks the size of the captcha a bit so it doesn't utlize so much real estate). That's it. The rest of the configuration parameters can remain the same unless you choose to go further. One of the nice things about LylaCaptcha is the sheer amount of configurable settings it includes (and for a new open-source project, it is very well documented - though the documentation could potentially include a more usable example, but Peter has mentioned that an example application is in the works).

Ok, now we need to modify some of the BlogCFC files - you will need to keep this in mind for future BlogCFC upgrades. You can begin by adding this code to line 60 of application.cfm:

<!--- NOTE: added lyla capthca --->
<cfset application.captcha = CreateObject("component","org.captcha.captchaService").init(configFile="/org/captcha/captcha.xml") />
<cfset application.captcha.setup() />

This code is exactly what it seems, it initializes the captcha component with your configuration XML. The second line is required because LylaCaptcha was built with user's adding dependency injection via ColdSpring in mind.

The next step will be to create two include files (which I have included in the download attachment to this post). The first is called captcha.cfm. It includes the form fields necessary to display the captcha and collect the user's response. It includes the hash needed to verify the correct response in a hidden form field. The code is pretty basic:

<cfset variables.captcha = application.captcha.createHashReference() />
<cfoutput>
<input type="hidden" name="captchaHash" value="#variables.captcha.hash#" />
<tr>
<td colspan="2" align="right"> Captcha text: <input type="text" name="captchaText" size="6" />
</td>
</tr>
<td colspan="2" align="right">
<img src="showCaptcha.cfm?hashReference=#variables.captcha.hash#" />
</td>
</tr>
</cfoutput>

The createHashReference() function creates the hash code that we will use later to generate the captcha and it is stored in the hidden form field. Finally, the image src is another include of sorts (showCaptcha.cfm) that will serve up the generated captcha image via cfcontent like so:

<cfset variables.captcha = application.captcha.createCaptchaFromHashReference("file",url.hashReference) />
<cfcontent type="image/jpg" file="#variables.captcha.fileLocation#" deletefile="true" reset="false" />

You will notice that the captcha file is generated from hash reference above. Both of these files are placed in the root directory of your blog (i.e. the client folder in the blogCFC zip download). Now just include captcha.cfm in the form line 193 of addcomment.cfm.

The next step is including the code to validate the captcha entry. You can add the captcha validation at line 73 of addcomment.cfm as follows:

<!--- captcha validation --->
<cfif not len(form.captchaText)>
<cfset errorStr = errorStr & "Please enter the Captcha text.<br>">
<cfelseif NOT application.captcha.validateCaptcha(form.captchaHash,form.captchaText)>
<cfset errorStr = errorStr & "The captcha text you have entered is incorrect.<br>">
</cfif>

The first part of the if statement obviously checks to ensure that the captcha was entered, but the second code validates the entry using the validateCaptcha() function of LylaCaptcha. It takes two arguments, the first being the hash code and the second is the captcha text (i.e. the form entry by the user) and simply returns a boolean either validating or invalidating the match. Simple enough. Note, I did not use the resource bundle in BlogCFC to generate the error messages obviously to make the example code easier to follow.

Well, that's it...comment spammers be damned. If you would like to test out my code, just comment on this entry with whatever ego boosting compliments you might have for me (unless you are a spammer that is) ;)

Download the attachment.

Comments
Brian Rinaldi
Just an update. I recommend changing the launchcomment javascript function on tags/layout.cfm to a height of 550 to prevent the need to scroll to find the post button when adding the initial comment (further comments will need to scroll anyway).


Jacob Munson
Good job! I'll try this out on my blog. I had played with LylaCaptcha a bit, but got an error message so didn't continue. Now I'll have to try again.


Todd
I keep getting &quot;Captcha not available&quot; in random font variations and I've read the FAQ (located at http://lyla.maestropublishing.com/ ) and uncertain what I'm missing. The hash is being sent in correctly, but there's a talk about &quot;a &quot;&quot; string of text,&quot; but I'm uncertain where to debug/track that down.


Todd
Ok, found the issue. The function getHashReference() is returning text = &quot;&quot;. Not sure why variables.instance.hashReferenceCache isn't being found yet.

I'll stop spamming here now. ;)


Brian Rinaldi
No problem. If you figure it out feel free to share the fix. One note I should make to this post is that I did have to implement the setColro fix listed under Known Bugs or Problems on the lylaCatpcha site.


Todd
Brian,

Getting closer to the issue. Least, I know where the disconnect is now. I have a feeling that Steven is running into the same issue (or chose his to be static or pulled from a list), because if you look at his comments page and hit refresh a few times, you'll start to see a pattern. It's not random like yours.

The disconnect is that the variables.captcha.hash that you're passing into showCaptcha.cfm isn't matching up with the CFC's getHashReference's variables.instance.hashReferenceCache[1].

If I turn the &lt;img src=&quot;&quot;&gt; code temporarily into a module or comment out the cfcontent part and work with showCaptcha.cfm directly, they match up and it randomly generates like yours does. The moment I use the the img tag again, it fails again and falls back on the default answer of &quot;&quot; from getHashReference().

So, now I'm beginning to wondering if this isn't a code issue, but a server issue. I'm using Apache 2. How about you?

~Todd


Brian Rinaldi
Todd, I went to Steven's site and did about 15 refreshes without error. I am running on IIS, so perhaps that is the issue. I would recommend submitting a bug via the email on the site. I will try to pass your issue on to the author and see if he is aware of them.


Todd
Sorry. I don't mean to imply that you'll get an error on Steven's website. I mean to imply that if you refresh it 15 times, you'll start to see a pattern of words that he's using. He's not using the random feature of the Captcha text as you are. He has a defined list.


Brian Rinaldi
Right...rereading your comment, I now see what you meant. I did see a repeat words because he chose to run off a static list (as his post mentions), nonetheless, I did not see a &quot;pattern&quot;...the repetition seemed random.


Todd
I got it working. Stupid error on my part. I was so focused on reproducing what you have here that I forgot the context of how you were using it (in conjunction with BlogCFC) as I was just randomly using it without a framework involved (BlogCFC). Code works pretty good. Not too crazy about the actual image creation being dependent on the application scope, but.. oh well.


Raymond Camden
Hey Brian, I'm beggining the integration work. I'm getting:

The selected method setColor was not found.

Did you ever get this?


Brian Rinaldi
Yup. It is listed under the known bugs on the lyla site. Here's the fix from the site:

Line 248 that currently reads:

&lt;cfset graphics.setColor(getConfigBean().getFontColor()) /&gt;

Should read:

&lt;cfset graphics.setColor(getColorByType(getConfigBean().getFontColor())) /&gt;


Raymond Camden
Got it. He forgot to mention that this bug is on two lines.

It is unclear from your post - how do you fix the captcha text not available thing? I'm getting that now.


Raymond Camden
Never mind. All is well now. Thanks Brian! (Oh, you ARE ok with this code going into v5, right?)


Brian Rinaldi
Absolutely! Glad I could contribute.


John Pollard
I have tried your code with a couple of small changes on a want ad reply page on my site. You will find a test page here - http://www.expat-online.com/living/classifieds/ad_reply.cfm?id=7282. I can't seem to get the validate command to work. I am using cfform with required=yes so I do not need the first line of your validation and am using this:

&lt;cfif NOT application.captcha.validateCaptcha(form.captchaHash,form.captchaText)&gt;
&lt;cfset captcha_error = 'yes'&gt;

and then I include the error text in the cfform if captcha_error is yes.

Can you help me on this?

Thanks

John


Brian Rinaldi
John, your form validation doesn't seem to have anything to check if the captcha was not entered (as described above) - as I get the captcha error before I even submit the form. Beyond that, you would need to provide me more information for me to assist. For instance, are you getting an error? What exactly is happening? As long as you create the image from the proper hash reference you should be good to go.


Dennis Longnecker
I'm having problems getting your code snippets to work on a very simple page. First, I can get the sample to work: http://www.gyro4.org/captcha/captchatest.cfm

When I create a simple form using the examples from the blog, the picture doesn't show.
http://www.gyro4.org/captcha/test2.cfm

my application.cfm has:
&lt;cfset application.captcha = CreateObject(&quot;component&quot;,&quot;captchaService&quot;).init(configFile=&quot;/captcha/captcha.xml&quot;) /&gt;
&lt;cfset application.captcha.setup() /&gt;


test2.cfm has:
&lt;cfset variables.captcha = application.captcha.createHashReference() /&gt;
&lt;cfoutput&gt;
&lt;input type=&quot;hidden&quot; name=&quot;captchaHash&quot; value=&quot;#variables.captcha.hash#&quot; /&gt;
&lt;tr&gt;
   &lt;td colspan=&quot;2&quot; align=&quot;right&quot;&gt;
Captcha text: &lt;input type=&quot;text&quot; name=&quot;captchaText&quot; size=&quot;6&quot; /&gt;
   &lt;/td&gt;
&lt;/tr&gt;
   &lt;td colspan=&quot;2&quot; align=&quot;right&quot;&gt;
&lt;img src=&quot;showCaptcha.cfm?hashReference=#variables.captcha.hash#&quot; /&gt;
   &lt;/td&gt;
&lt;/tr&gt;
&lt;/cfoutput&gt;

and showcaptcha.cfm has:
&lt;cfset variables.captcha = application.captcha.createCaptchaFromHashReference(&quot;file&quot;,url.hashReference) /&gt;
&lt;cfcontent type=&quot;image/jpeg&quot; file=&quot;#variables.captcha.fileLocation#&quot; deletefile=&quot;true&quot; reset=&quot;false&quot; /&gt;

When I access the test.2cfm, it does create a new jpg in the directory I told the xml file to put it into. Any thoughts as to what I might have messed up?


Brian Rinaldi
Dennis, are your appliation variables being set inside a conditional statement? It should be like this:

&lt;cfif not structKeyExists(application,&quot;captcha&quot;)&gt;
&lt;cfset application.captcha = CreateObject(&quot;component&quot;,&quot;captchaService&quot;).init(configFile=&quot;/captcha/captcha.xml&quot;) /&gt;
&lt;cfset application.captcha.setup() /&gt;
&lt;/cfif&gt;
Other than that, I am not sure...you could send me the files.


Doug Bedient
I have been trying to get the captchatest.cfm example to work. Something is obviously wrong as it force downloads a CFM file to my desktop.

Does anyone know what may cause this to happen? Thanks for any help.


Brian Rinaldi
Doug, try this post from a later date - http://www.remotesynthesis.com/blog/index.cfm/2006/6/21/Validating-CAPTCHA-with-AJAX
It gives a more generic example of how to add captcha to your site (though it uses some simple ajax for validation). There is also downloadable code for that as well.


diana
I'm having a problem with my implementation and was wondering if you have a suggestion; if one person loads my page with the captcha on it and then a second person comes along and accesses the same page, before the first person has finished typing the captcha text, the first person will then get &quot;invalid captcha text&quot; error. I have it implemented almost exactly as it is presented in this blog. Is this a known issue? Any suggestions?

Thanks!
Diana


Brian Rinaldi
Diana, No, this is not a known issue. It sounds to me like maybe you are missing the cfapplication perhaps? Are you actually integrating into blogCFC because I didn't cover certain things in great detail because they were already in blogCFC. If you like, check out my other more general instructions at http://www.remotesynthesis.com/blog/index.cfm/2006/6/21/Validating-CAPTCHA-with-AJAX


Michael Appenzellar
Hello,

I can get the test to work, but when i try to implement, I get no graphic. If this helps, when I try to go to the url of the captcha image on working models it takes me to a save this file prompt but what I get for mine is the following error:

The web site you are accessing has experienced an unexpected error.
Please contact the website administrator.

The following information is meant for the website developer for debugging purposes.

Error Occurred While Processing Request
Element CAPTCHA is undefined in a Java object of type class [Ljava.lang.String; referenced as


J
Hi,

I've managed to get lylaCaptcha working on my development server, but when I've uploaded it to my live server I get the following error from CF Diagnostics:

Element INSTANCE.HASHREFERENCECACHETIMESTAMP is undefined in VARIABLES.
The error occurred on line 936.

The erroring file is showCaptcha.cfm. Has anyone else received this error before? I think it has something to do with the way the two servers could be caching variables but I'm not too sure.

Cheers

J


Julian Warren
Having just moved from CF5 to MX 7 development I have plunged into the deep end with this. I am quite used to java so I can read the code but the debugging of why I was only seeing &quot;captch not available&quot; had me utterly perplexed. Especially as I could not find an equivlent of the &quot;System.out&quot; in Java to print debug rubbish to the console. I was delving into all the instance of object stuff when I cam across this note on this blog:

&quot;&lt;cfif not structKeyExists(application,&quot;captcha&quot;)&gt;&quot;

So if I understand this correctly, when I don't have this line I just keep creating more unique objects each time the page is refreshed. And thus &quot;instance&quot; never refers to the right one.

I added that test and all was well. So far. I will get better at this - I promise.

Is there simple &quot;System.out.println&quot; in CF


Brian Rinaldi
The debugging tag you are looking for is &lt;cfdump var=&quot;#whatever#&quot;&gt;

You are also correct on the application variable.

Also, unless you are trying to edit an older copy of blogCFC (the recent versions already include this code), I would probably refer you to my other post - http://www.remotesynthesis.com/blog/index.cfm/2006/6/21/Validating-CAPTCHA-with-AJAX
While that focuses on using LylaCaptcha with Ajax, it is a more generalized example.


Julian Warren
I too am getting:

Element INSTANCE.HASHREFERENCECACHETIMESTAMP is undefined in VARIABLES

from showCaptcha.cfm

when running on a live server which I believe is 6.1. Any ideas?

Julian


John Ramon
For those with the INSTANCE.HASHREFERENCECACHETIMESTAMP undefind problem, check you application name, and make sure there are no special characters my blog was having the same problem http://www.johnramon.com and I found an underscore in my application name was the problem.


Brian
Well, I have read your both the tutorials, but when I implement them to my site the image never gets showed?:S do you know what am i missing here? i also downloaded your own zipped code and implemented it too but i still get no graphics:S i am really fedup now coz I am unable to fix this problem and trying since last three days... can u help me with this? my email id iz meet.love@hotmail.com

Thanx for your tutorials! I loved the ajax one!! coz i use mx kollection and it is being impossible for me to implement and captcha service in it!!

Anyway thanx!!


Jose Galdamez
Another developer got LylaCaptcha working last year, but after we moved to a new web server it suddenly stopped working (none of the code had changed either). I re-downloaded and tried to re-configure the code from scratch, but I basically ran into the same issue as Todd according to his 5/4/06 posting.

I went over the documentation for 2 days straight and could never figure out what was wrong. After going through the examples in this blog I found this in my showCaptcha.cfm file wasn't working:

&lt;cfset variables.captcha = application.captcha.createCaptchaFromHashReference(&quot;stream&quot;,url.hashReference) /&gt;
&lt;cfcontent type=&quot;image/jpg&quot; variable=&quot;#variables.captcha.stream#&quot; reset=&quot;false&quot; /&gt;

Switching to this code did the trick for me.

&lt;cfcontent type=&quot;image/jpg&quot; file=&quot;#variables.captcha.fileLocation#&quot; deletefile=&quot;true&quot; reset=&quot;false&quot; /&gt;

That along with another code modification got the captcha to verify.

Thanks!
I couldn't find this fix anywhere in the LylaCaptcha documentation.

Jose


Lewis John
We found that when your application name is longer than 35 characters it throws that error ('Element INSTANCE.HASHREFERENCECACHETIMESTAMP is undefined in VARIABLES')!

Shortening the app name solved the problem.


Write your comment



(it will not be displayed)