I know there is a lot of text, but I don't believe this is actually a hard problem to solve. For a TLDR, check out the end of the question.
So, I am trying to implement a basic captcha-like form in my web.py app. This code is taken from http://kzar.co.uk/blog/2009/07/14/web.py-captcha. I am just showing a basic test example I am working on, trying to figure out what is going wrong in my bigger app.
What happens is, when I press enter on the index page, even if I get the code right (which I verify by printing the 'word' variable in captcha.py to terminal), I still get an error saying my captcha is invalid. I have tried everything, and checked both the session variable as well as the word variable, but no matter what I am told that my code is wrong. Here is the entire test app.
test.py:
import web
from web import form
from captcha import getCaptcha
render = web.template.render('templates/')
urls = (
'/', 'index',
'/captcha.gif', 'captcha'
)
app = web.application(urls, locals())
if web.config.get('_session') is None:
session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'captcha': ''})
web.config._session = session
else:
session = web.config._session
vcaptcha = form.Validator('Please enter the code', lambda x:x == session.captcha)
enquiry_form = form.Form(
form.Textbox("captcha", vcaptcha, description="Validation Code", pre="<img src='/captcha.gif' valign=center><br>", class_="standard", style="width:70px;"),
)
class index:
# Display the create match page
def GET(self):
form = enquiry_form()
return render.captcha(form)
# Save the data
def POST(self):
form = enquiry_form()
if not form.validates(): # If there is an issue
return render.captcha(form) # Return them to the create page
else:
return "Success!"
class captcha:
def GET(self):
web.header("Content-Type", "image/gif")
captcha = getCaptcha()
session.captcha = captcha[0]
return captcha[1].read()
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
captcha.py:
from PIL import Image, ImageDraw, ImageFont
import cStringIO, random
def getCaptcha():
im = Image.new("RGB", (175, 60))
draw = ImageDraw.Draw(im)
for x in range(0, 175):
for y in range(0, 60):
draw.point((x, y), (135, 191, 107))
font = ImageFont.truetype('static/ZXX Camo.otf', 50)
alphabet = 'abcdefghijklmnopqrstuvwxyz'
word = ''
for i in range(5):
word = word + alphabet[random.randint(0, len(alphabet) -1)]
draw.text((5, 5), word, font=font, fill=(0, 0, 0))
f = cStringIO.StringIO()
im.save(f, "GIF")
f.seek(0)
return word, f
captcha.html:
$def with (form)
<head>
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon">
</head>
<h1>Testing Captcha</h1>
<form name="main" method="post">
$:form.render()
</form>
The font I am using is available here: http://dl.dropbox.com/u/20517415/ZXX.zip
I am totally perplexed by what is happening here. I believe the code at fault here is the validation code lambda x:x == session.captcha
. I have tried many different versions of this line, and nothing seems to work. Most perplexing is that I can even change the line to be lambda x:x != session.captcha
, and it STILL doesn't work. I would appreciate your help. I have been looking at this for awhile and have no idea what is wrong.
TLDR; Some basic CAPTCHA-like code I am working with on a web.py app does not recognize a correct code entry, and I have provided the source files for you to inspect what is wrong.
For those who find this through google:
The solution was simple. I was reinitializing the app instance, which meant that I was creating a new session every time, without a session.captcha var. And because the way web.py handles the validation, it did not send out an error explaining that there was an AttributeError. So, all I had to do was remove the app declaration in __main__.
Also, this code wouldn't work without disabling debug mode, because web.py session variables are weird =/