Why?
The purpose of Captcha is to distinguish humans from machines. And the popular way of doing it is to ask the user to write down what he see's. But then the machines got better, so the captcha were made harder to read. Except now its harder for both machines and humans to read.Examples:
http://www.robotnine.com/2009/05/captcha-words-worst-ones-ever.html
http://www.johnmwillis.com/other/top-10-worst-captchas/
How?
There's 3 parts to this- Creating the Math Question & Answer
- Creating the Image from the Math Question
- Verifying if the user responded properly
Now define a view in django that will output our image and the code for the view is
from django.conf import settings
from django.http import HttpResponse
from StringIO import StringIO
import random, os
import Image, ImageFont, ImageDraw
def index(request):
# Load a random font
fontslocation = settings.MEDIA_ROOT + "notes/captcha/"
fonts = os.listdir(fontslocation)
font = ImageFont.truetype(fontslocation + random.choice(fonts), 25)
# Create the image with 400x50 size
image = Image.new("RGBA", (400, 50), (255,255,255, 0))
draw = ImageDraw.Draw(image)
# Draw the text we get from getBasicMath
draw.text((0, 0), getBasicMath(request), font=font, fill="#000000")
# Create a StringIO that we can use to save the image
data = StringIO()
image.save(data, format="PNG")
# Return the image directly from memory
data.seek(0)
return HttpResponse(data.read(), mimetype="image/png")
def getBasicMath(request):
# The 3 types of operators we'll support
operator = random.choice(["+", "-", "x"])
# If its multiplication, lets use smaller numbers
if (operator == "x"):
num1 = random.randint(0, 10)
num2 = random.randint(0, 10)
# Store the correct answer in session
request.session['captcha_answer'] = num1 * num2
else:
num1 = random.randint(20, 40)
num2 = random.randint(0, 20)
# Store the correct answer in session
if (operator == "+"):
request.session['captcha_answer'] = num1 + num2
else:
request.session['captcha_answer'] = num1 - num2
# This is our output
return str(num1) + operator + str(num2) + "=";
At the beginning we try to load a random font, you need to find some ttf fonts to use and place them in a folder in the MEDIA_ROOT. As you can see I put all my fonts in the "notes/captcha/" folder. To find free ttf fonts you can try 1001 Free Fonts. And that is all you need to set up, you can change the questions in the getBasicMath function.
To verify the answer
In the getBasicMath function we set the answer in session "captcha_answer", so next time someone answers the captcha question just verify if their answer matches with that session object.Example
Improvement
There is a LOT of room for improvement- Add a background image
- Transform the image
- Changing from numbers to words. Ex: five + ten =