""Things which are complicated tend to disappear and get lost. Simplicity is difficult, not easy. Beauty is simple. All unnecessary elements are removed - only essence remains." -- Alan Hovhaness, American Composer
I don't know about you, but I absolutely loathe Captchas. It seems they're almost always "overdone", and they're difficult to complete correctly in many cases. As a case in point, Jeff Atwood has simply had a captcha image with the word "Orange" (see very bottom of page) on his blog for the longest time, and he claims a 99% success rate in keeping out spam. Not only does this image never change -- it is easy to read!
Captcha widgets have promulgated over the internet because of the human folly of people mindlessly doing something they've seen somewhere else without stopping to ask the important question "What effect will this have on my users?". The result is that they get less spam - but they've also unwittingly succeeded in making the site less accessible.
Here is a simple way to wire up a "sum the 2 numbers" Captcha that will prove very effective. Also, it's a heck of a lot easier on the eyes to your users! First, the sample code, in a script-only page:
<%@ Import Namespace="System.Drawing"%>
<script runat="server" language="C#">
protected void Page_Load(object sender, EventArgs e)
{
// if the page is just requested we need to initialize our numbers:
if (!IsPostBack)
{
System.Random rand = new Random((int) DateTime.Now.Ticks);
int num1 = rand.Next(1, 10);
int num2 = rand.Next(1, 10);
int total = num1 + num2;
Session["total"] = total;
lblNum1.Text = num1.ToString();
lblNum2.Text = num2.ToString();
}
// any additional code here
}
protected void Button1_Click(object sender, EventArgs e)
{
// 1. First, make sure user entered a number in the sum textbox:
int sum = 0;
if( !int.TryParse(txtSum.Text,out sum))
{
Label2.Visible = true;
Label2.Text = "Need to put a sum in the textbox, Captain.";
Label2.BackColor = Color.Red;
return;
}
// 2. Compare their entry with the stored sum of the two numbers:
if (sum !=(int)Session["total"])
{
// They got it wrong...
Label2.Visible = true;
Label2.BackColor = Color.Red;
Label2.Text = "Failed Bot check. Please try again.";
return;
}
else
{
// They got it right:
Label2.Visible = true;
Label2.BackColor = Color.LightGreen;
Label2.Text = "Success!";
}
// your business logic code goes here
}
</script>
<HTML>
<head>
<style>
.Yellowborder
{
BORDER-RIGHT: #ffcc00 1px solid; BORDER-TOP: #ffcc00 1px solid;
FONT-WEIGHT: normal; FONT-SIZE: 11px; BORDER-LEFT: #ffcc00 1px solid;
COLOR: #000000; BORDER-BOTTOM: #ffcc00 1px solid;
FONT-FAMILY: Verdana, Helvetica, sans-serif;
BACKGROUND-COLOR: white; overflow:hidden;
width:350px;
text-align:center;
}
</style>
</head>
<body>
<BaseFont face="Verdana" />
<Form runat="server" id="Form1">
<!-- This is where all your regular formfields would go. We just have one sample "email" field here. -->
<asp:Label runat=server Text="Enter your email:"/>
<asp:TextBox runat=Server id=email />
<br />
<div class="Yellowborder" >
<asp:Label ID="Label3" runat="server" Text="Please enter the sum of these numbers:"></asp:Label>
<asp:Label ID="lblNum1" runat="server"></asp:Label>
<asp:Label ID="Label4" runat="server" Text="+"></asp:Label>
<asp:Label ID="lblNum2" runat="server"></asp:Label>
<asp:Label ID="Label5" runat="server" Text="="></asp:Label>
<asp:TextBox ID="txtSum" runat="server" Width="21px"></asp:TextBox>
</div>
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" Width="120px" />
<br />
<asp:Label ID="Label2" runat="server" Width="400px" Visible="False"></asp:Label>
</Form>
</body>
</HTML>Okay, what do we have here? First, when the page is just requested and there hasn't been a postback (form post), we initialize a couple of random numbers from 1 to 10. We total them, and store the sum in Session.
Then we display the two numbers in the Captcha problem label fields.
Now when a user fills out your form, they are asked to complete the sum of these two numbers and place it in a TextBox. This simply becomes another Form field that gets posted when they click your "Submit" button.
The rest is just simple validation. If the user doesn't enter anything there, we handle that.
If their answer is wrong, we abort form processing and provide a message. Finally, if their answer is correct, we can continue processing of the form post.
Easy, simple, effective - and easy to read! Here is a live sample of the same code:
SumCaptchaForm Example