Blog
January 2010
For awhile I had a Javascript bot blocker that did a good job keeping spammers from flinging crap at our blogs, but apparently they got smarter. Go Figure. Even though I hate them, I figured the best option would be to add a Captcha system. I looked into systems like Snook and Askimet and really didn't think they were right for our customers at this point. At least not for a first line of defense.
Before you get much further, this is not a plugin, and I'm not even going to provide full examples. One of the chief benefits of a custom system is the obscurity. However, I do think the general approach is sound and worth sharing. IMO, creating a captcha plugin is kind of like selling every lock with the same key.
I looked at hosted solutions like Re-Captcha, but didn't want to be reliant on a third party. I also looked at the Simple Captcha Rails plugin. The problem I had with it is that it generated the images on the fly, which seemed like it could turn into a resource nightmare with all the requests we get.
I wanted to create a system that used static pre-generated images so it would be super fast.
The Gist of It
I generated a set of images using ImageMagick. Here's an example of the code I used to do that...
words = %w{ sack river space }
for word in words
`convert xc:#FFF -resize 110x35! -frame '1x1' -family Helvetica -pointsize 13 -gravity "Center" -draw "text 0,0 '#{word}'" #{word}.jpg`
end
Notice the text is the name of the file. I put those images in a directory in my app. Then I created a table with a key, filename, and created date.
Here's some psuedo code.
image = getRandomCaptchaFile() captcha = findCaptcha(filename = image, createdDate > expireInterval)
if captcha == nil
captcha = new Captcha
captcha.filename = image
captcha.key = getRandomKey()
captcha.created_date = now()
captcha.save
end deleteAllCaptchas(created_date < 1.day.ago) return captcha
This is the crux of the system. Basically I get a random image file, check to see if a captcha record has been created within a set interval, if not create a new one with a new key (such as a GUID), and delete all the old captchas. For doodlekit I also have some code to take into account the multi-site environment.
Once you have this you can create a controller or action to accept the random key. This will look up the image from the captcha table and return the image data. The random key breaks the link between the URL and the actual image.

