The spamming bots are annoying. And they can OCR too!
Ever get bored of the old 'type the number|word you see above|below' business when completing an online form? I did. And it probably annoys users on sites where this is installed. But
as annoying as it is, it stops bots from automatically submitting spam through forms on pages. The real loser is the end user who needs to take the burden of our own spam protection.
The practice of asking people to 'prove' they are, indeed, human is now known as 'CAPTCHA IMAGE VERIFICATION'. Since the discovery that bots can use optical character recognition - OCR, much like flatbed scanners, people have started to REALLY obtuse the text, making it nearly impossible to make out. Here are a few examples I collected within 5 Min's of my Google search, showing just how difficult to read it can become:
You have got to be kidding me?
Now, even if you could read the first one, you may be able to guess your way around the second one... and you'd still have to carefully type them. And then there's the 3rd one--which aside from being hard to make out--is also a bit longer to type.
I suffer from a slight
astigmatism and certain letters, shapes or combinations of letters and rounded shapes, clustered together, present me with a real accessibility problem. People shouldn't have strain themselves and spend minutes filling out a "humanity" test!
The captcha alternative
All this and more is why I wrote hOOmanTest - to provide an alternative way of differentiating bots from humans. Here it is in action below:
How difficult is that in comparison to using the one that's so popular around the web?
*edit*: I really do hope it helps somebody, here is the first site that uses it out there--in a quotation webform on the
cleaning 4u site, click the free quote banner to view.
I should also add I saw the idea on another site, accomplished through jQuery and jQuery UI.
*edit* It is called Ajax Fancy Captcha and weighs in at a total of
435Kb for the pleasure.
I am not sure which is worse, getting your users to download nearly half a meg extra or getting them to strain their eyesight with traditional captcha images.
Nevertheless, very popular within the jQuery community, head over heels for this they were. So here we are a while later, sat with a brand new version that works in mootools 1.2+.
Obviously, we do not need MochaUI to get this working so our version can be as low as 120k total in size (inclusive of the framework files).
Using the hOOmanTest mootools class
Instigating the class is easy, within the domready you do:
var noBots = new hOOmanTest($("demo"), {
callback: function(state) {
if (state) {
// success!
this.instructions.set("html", "We appreciate it, you can now continue and submit your form.");
// add a field to the form that can show the processor the test has passed.
$("someForm").adopt(new Element("input", {
"type": "hidden",
"name": "captcha",
"value": this.mover.name
}));
// do something else like, enable the submit button.
}
else // dropped it elsewhere, tease / lead them.
this.instructions.set("html", "No, no, no! Drag and drop the "+this.mover.name+" into the BOX!");
}
});
The 'callback' function is important, it is where you should fit your ways of making your forms work. For example, you can use the
function to set the
action property of your form (having had it blank).
Resources
Get
mootools 1.2+ and
hOOmanTest.js
The background images:
There is some CSS as well:
.botMessage {
width: 180px;
position: relative;
float: right;
top: 10px;
font-size: 10px;
font-family: verdana;
}
.botMessage strong {
color: #500;
}
.dropper {
position: relative;
width: 49px;
height: 49px;
top: 34px;
margin-right: 11px;
clear: right;
float: right;
}
.captcha {
float: left;
padding-right: 10px;
}
.captcha img {
background: #fff;
border: 1px solid #000;
padding: 1px;
margin-top: 8px
}
The hOOmanTest mootools class source itself
// class: hOOmanTest
// version: 0.9
// dependencies: mootools 1.2.3 core, 1.2.3 more (Drag.js)
// tested on: FireFox 3, IE7, Safari 4 (beta), Opera 9.60
// last updated: 26/06/2009
// url: http://fragged.org/
// author: dimitar chrostoff
// authorised use: modify and use as you deem fit. any link back appreciated :)
var hOOmanTest = new Class({
Implements: [Events,Options],
initialize: function(el, options) {
// set default options...
this.setOptions($merge({
messageHtml: "Prove you're human and drag the [what] below into the BOX",
messageClass: "botMessage", // needed in css
images: [{ // images to be dragged and their names
name: "CUBES",
src: "images/cubes.png"
},
{
name: "PAPER",
src: "images/news.png"
},
{
name: "PLUS",
src: "images/plus.png"
},
{
name: "CONE",
src: "images/cone.png"
}],
background: {
url: "images/nobots.gif",
width: 289,
height: 118
},
callback: $empty // a function to run after drop, args: human(bool), this(bound object instance)
}, options));
this.element = $(el); // the target element
this.createTest();
},
createTest: function() {
// figure out what to move first
if (this.container)
this.container.dispose();
this.human = false;
if (!this.element)
return false;
// need two that show
this.mover = this.options.images.getRandom();
this.dummy = this.options.images.erase(this.mover).getRandom();
this.container = new Element("div", {
styles: {
background: "url("+this.options.background.url+") no-repeat",
width: this.options.background.width,
height: this.options.background.height
}
});
this.instructions = new Element("div", {
html: this.options.messageHtml.replace("[what]", this.mover.name)
}).addClass(this.options.messageClass).inject(this.container);
this.dropper = new Element("div", {
"class": "dropper"
}).inject(this.container);
this.container.inject(this.element);
(function() {
var coords = this.dropper.getCoordinates();
this.mover.object = new Element("div", {
styles: {
background: "url("+this.mover.src+") no-repeat",
width: 48,
height: 48,
position: "absolute",
top: coords.top,
left: coords.left - 120,
cursor: "move"
}
}).injectAfter(this.dropper);
this.dummy.object = new Element("div", {
styles: {
background: "url("+this.dummy.src+") no-repeat",
width: 48,
height: 48,
position: "absolute",
top: coords.top,
left: coords.left - 65
}
}).injectAfter(this.dropper);
if (Browser.Engine.trident)
this.mover.object.setOpacity(1);
else
this.mover.object.fade(0,1);
var myDrag = new Drag.Move(this.mover.object, {
droppables: [this.dropper],
container: this.container,
onDrop: function(el, droppable, event) {
if (!droppable) {
this.options.callback.run(false, this);
return false;
}
droppable.adopt(el.clone().setStyles({
top: 0,
left: 0,
position: "relative",
cursor: "default"
}));
this.human = true;
this.mover.object.dispose();
this.options.callback.run(true, this);
this.fireEvent("passed");
}.bind(this),
onEnter: function(el, droppable) {
}
});
}).delay(1000, this);
},
passed: function() {
this.fireEvent("passed");
}
});