Simple Captcha 1.0
Update: SimpleCaptcha 1.2.2 is up!!
Major Changes…
FileSystem Usage Removed
Works Perfectly with Multiple Clustered Servers
Read Here for more details on implementation, usage and examples.
Major Changes…
Read Here for more details on implementation, usage and examples.
If you are using an older revision of SimpleCaptcha then it is strongly recommended that update it to the Simple Captcha version 1.0, coz there were certain bugs in the previous release viz. update_attribute, which has been fixed in this release.
check out more details here
captcha, plugin, rails, ror, rubyonrails
Hello Everyone !!
I have released a captcha plugin Simple Captcha. It is really simple to implement, and provides a cool feature of multiple styles of images. Visit here for more explanation.
To implement captcha in RubyonRails, validates_captcha plugin can be a good option but a small customization i need with this plugin was to use it on some specific action and not to be validated the captcha field every time an instance of the model is saved or updated.
Here is a small work-around for its customization…
How to use customized captcha in RoR ?
Install the plugin validates_captcha in your rails application by running this command from the root of your application
ruby script/plugin install http://svn.2750flesk.com/validates_captcha
Make sure that you can now see the directory vedor/plugins/validates_captcha.
Now run these commands from your application root to make the image and data directories
ruby script/generate captcha store_directory ruby script/generate captcha image_directory
Here is the complete API for the usage of this plugin. I am describing the same idea as given in this API but in a bit more specific means.
Lets consider a model User in which we will implement the captcha.
Add the following code in the file app/models/user.rb
class User < ActiveRecord::Base
validates_captcha :if => :request_captcha_validation?
attr_accessor :request_captcha_validation
def request_captcha_validation?
(self.request_captcha_validation==true)? true : false
end
end
Add the code in the view inside your existing form.
<% c = prepare_captcha :type => :image -%> <%= captcha_hidden_field c, 'user' %> <%= captcha_image_tag c %> <%= captcha_label 'user', 'Type in the text from the image above' %> <%= captcha_text_field 'user' %>
Your controller will look like
def save
# the line in bold represents that you need captcha validation.
# if captcha validation is not required then remove this line from your controller.
@user = User.new(params[:user])
@user.request_captcha_validation = true
@user.save
end
However image is too noisy and it contains repeated strings.
To improve the quality of images generated by the plugin validates_captcha visit Here.
captcha, image, rails, ror, validations
Hello Everyone !!
I have released a captcha plugin Simple Captcha. It is really simple to implement, and provides a cool feature of multiple styles of images. Visit here for more explanation.
Validates captcha is a good plugin to implement captcha in your rails application.
However i found that there is repetition of the string of the image and the quality of image is not that good. To get a good quality image and random string
something like this

replace the code of the file /vendor/plugins/validates_captcha/lib/captcha_challenge.rb with the following code…
require 'digest/sha1'
module AngryMidgetPluginsInc #:nodoc:
# CaptchaChallenge
class CaptchaChallenge
include CaptchaConfig
extend CaptchaConfig
DEFAULT_TTL = 1200#Lifetime in seconds. Default is 20 minutes.
attr_reader :id, :created_at
attr_accessor :ttl
def initialize(options = {}) #:nodoc:
generate_id
options = {
:ttl => config['default_ttl'] || DEFAULT_TTL
}.update(options)
self.ttl = options[:ttl]
@created_at = Time.now
self.class.prune
end
# Implement in subclasses.
def correct? #:nodoc:
raise NotImplementedError
end
private
def generate_id #:nodoc:
self.id = Digest::SHA1.hexdigest(Time.now.to_s+rand.to_s)
end
def id=(i) #:nodoc:
@id = i
end
def write_to_store #:nodoc:
store.transaction{
store[:captchas] = Array.new unless store.root?(:captchas)
store[:captchas] << self
}
end
class << self
# Removes old instances from PStore
def prune
store.transaction{
if store.root?(:captchas)
store[:captchas].each_with_index{|c,i|
if Time.now > c.created_at+c.ttl
store[:captchas].delete_at(i)
end
}
end
}
end#prune
end#class << self
end
# A CAPTCHA challenge where an image with text is
# generated. A human can read the text with relative
# ease, while most robots can not. There are accessibility
# problems with this challenge, though, as people
# with reduced or no vision are unlikely to pass the test.
class CaptchaImageChallenge < CaptchaChallenge
WORDS = ‘gorilla costume, superman, banana bender, chuck norris, xray vision, ahoy me hearties,
chunky bacon, latex, rupert murdoch, clap your hands, year 2000,
sugar coated, coca cola, rastafarian, airbus a380′.split(/,s+/)
DEFAULT_DIR = ‘captcha’#public/images/captcha
WRITE_DIR = File.join(RAILS_ROOT, ‘public’, ‘images’)
DEFAULT_FILETYPE = ‘jpg’
attr_reader :image
attr_accessor :string, :dir, :filename, :filetype
# Creates an image challenge.
def initialize(options = {})
super
options = {
:string => config['words'] ? config['words'][rand(config['words'].size)] : WORDS[rand(WORDS.size)],
:dir => config['default_dir'] || DEFAULT_DIR,
:filetype => config['default_filetype'] || DEFAULT_FILETYPE
}.update(options)
self.string = Digest::SHA1.hexdigest(Time.now.to_s)[0..4].upcase #options[:string]
self.dir = options[:dir]
self.filetype = options[:filetype]
self.filename = options[:filename] || generate_filename
write_to_store
end
# Generates the image.
def generate(options = {})
options = {
:fontsize => 50,
:padding => 20,
:color => ‘#000′,
:background => ‘#fff’,
:fontweight => ‘bolw’,
:rotate => true
}.update(options)
options[:fontweight] = case options[:fontweight]
when ‘bold’ then 700
else 400
end
#added
text = Array.new
0.upto(4) do |i|
text[i] = Magick::Draw.new
text[i].pointsize = options[:fontsize]
text[i].font_weight = 600 #options[:fontweight]
text[i].fill = ‘black’ #options[:color]
text[i].gravity = Magick::CenterGravity
text[i].rotation = (rand(2)==1 ? rand(30) : -rand(30)) if options[:rotate]
end
metric = text[2].get_type_metrics(self.string)
#add bg
canvas = Magick::ImageList.new
fill = Magick::HatchFill.new(’white’,'black’)
x = metric.width+options[:padding]
y = metric.height+options[:padding]
#ADDING NOISE
img1 = Magick::Image.new(x,y,fill)
gc = Magick::Draw.new
gc.stroke_linejoin(’round’)
gc.stroke(’black’)
gc.stroke_width(1)
100.times do |i|
x1 = rand(x)
y1 = rand(y)
gc.circle(x1,y1,x1.next,y1)
end
gc.draw(img1)
canvas << img1
0.upto(4) do |i|
canvas << Magick::Image.new(metric.width+options[:padding], metric.height+options[:padding]){
self.background_color = ‘#000F’
y_loc = rand(y)
}.annotate(text[i], 0, 0, (i-2)*30, rand(y/4), self.string[i,1]) #.wave(5, 20)
end
canvas << Magick::Image.new(metric.width+options[:padding], metric.height+options[:padding]){
#changed
p = Magick::Pixel.from_color(options[:background])
p.opacity = Magick::MaxRGB
self.background_color = p
} #.add_noise(Magick::LaplacianNoise)
self.image = canvas.flatten_images.blur_image(1)
end
# Writes image to file.
def write(dir = self.dir, filename = self.filename)
self.image.write(File.join(WRITE_DIR, dir, filename))
end
# Determine if the supplied +string+ matches
# that used when generating the image.
def correct?(string)
string.downcase == self.string.downcase
end
# The full path to the image file, relative
# to <tt>public/images</tt>.
def file_path
File.join(dir,filename)
end
class << self
# Deletes old image files. Also calls CaptchaChallenge.prune
def prune
store.transaction{
if store.root?(:captchas)
store[:captchas].each_with_index{|c,i|
if Time.now > c.created_at+c.ttl
if File.exists?(File.join(WRITE_DIR, c.file_path))
begin
File.unlink(File.join(WRITE_DIR, c.file_path))
rescue Exception
end
end
end
}
end
}
super
end#prune
end#class << self
private
def generate_filename #:nodoc:
self.id+’.'+self.filetype
end
def image=(i) #:nodoc:
@image = i
end
end
end
visit Here to view the customized use of the plugin validates_captcha in RoR.