Tutorial: Using Zend_Captcha_Image
by Sankho on Dec.17, 2008, under Tutorials, Zend Framework
Update - check out the post at AmpTools, if you’re using a copy of Zend Framework version 1.7.8 or above - the below code may not work for you.
—–
Recently on a project I was developing using the Zend Framework, I needed to validate a form using a CAPTCHA image.
For those who don’t know, CAPTCHA stands for Completely Automated Public Turing test to tell Computers and Humans Apart. Ever been to a website and seen an image like the one to the right? Basically, it’s a way to make sure a human is filling out the form and not just some robot. How? Robots can’t decifer what words *might* be from an image - only a human can.
Zend Framework has a set of great classes included to take away a lot of the headaches involved with setting up a CAPTCHA system. The one I use is Zend_Captcha_Image, which creates an image for you and sets up a Session so you will be able to validate all information appropriately. Problem is, there’s little documentation out there on this.
The best example I found was on Robert Basic’s Blog. My only gripe about it was that it used Zend_Form.
Zend_Form is a great class and all, but if you’re like me, you don’t like using it because you give up the control you get over Form creation + validation. It’s a great way to skip writing HTML for a form - but what if your client wants a very specific design attached to their form? Then Zend_Form becomes a hassle to design to a specification. And yes, Zend_Form makes validation easy, but what if your client wants to set up very specific validation messages? Again, Zend_Form becomes more trouble than it’s worth. Yes, it is flexible enough as a class to edit it any way you want, but I feel NOT using Zend_Form will ultimately make your forms more flexible.
So, beyond the break, I’ll show you everything you need to know to use Zend_Captcha_Image WITHOUT Zend_Form! If you’d like to learn the implementation using Zend_Form, please visit Robert Basic’s Blog.
Here’s a list of what we need to do to get our instance of Zend_Captcha_Image up and running.
- Make sure we have GD installed.
- Make a new folder in our web directory with 777 permissions. This will store the generated CAPTCHA images.
- Write generateCaptcha() function
- Write validateCaptcha() function
- Show a quick example, bask in Zend Framework aided CAPTCHA awesomeness, and stop fearing robots until the Matrix comes true
1.) Make sure we have GD installed.
The first thing you need to be sure of is that you have GD running on your copy of PHP. This is pretty easy. Just run this code on any PHP page to find out:
I should hope this is pretty self-explanatory. If you don’t have GD installed, contact your hosting provider for more info. More on GD installation later should future comments find them necessary!
Anyways, hopefully you have the GD library installed. It’s an image manipulation library very commonly used by PHP programmers to make images & thumbnails “on-the-fly”, or in the background unbenknownst to your user.
2.) Make CAPTCHA images folder
So you have GD installed, and you’re good to go. Before we can get to the code, you need to create a folder for the captcha images within your public/ directory and chmod it to 777 (all file permissions open).
This should be pretty simple, and to clarify, by your public/ directory I of course mean whatever folder your server is pointing to. This is so the captcha images can be accessible by HTTP request, for example through the folder http://www.your-site.com/images/captcha/
I hope you’re deep enough in the game for that to make sense. After you’ve made that folder, take note of it, for you’ll use it in step 3.
So now what? Let’s generate the two functions that will serve as the base for our Captcha code. One is called generateCaptcha() and the other is called validateCaptcha(). Let’s look over generateCaptcha() first.
3.) Write generateCaptcha() function
-
//generates an instance of Zend_Captcha
-
//returns ID of captcha session
-
function generateCaptcha() {
-
-
$captcha = new Zend_Captcha_Image();
-
-
$captcha->setTimeout(‘300′)
-
->setWordLen(‘6′)
-
->setHeight(‘80′)
-
->setFont(‘/path/to/your/fontFile.ttf’)
-
->setImgDir(‘/path/to/your/image/captchaDirectory’);
-
-
$captcha->generate(); //command to generate session + create image
-
-
return $captcha->getId(); //returns the ID given to session & image
-
-
} //end function generateCaptcha
So, let’s go over this function. First we instantiated a new Object of class Zend_Captcha_Image. Then we used it’s functions to feed it some basic information. $captcha->setTimeout(’300′) sets the time the session will stay active, in seconds. So, upon loading the form, the user has 5 minutes to respond. ->setWordLen(’6′), pretty obviously sets how many characters are used in the CAPTCHA image. 6 is pretty decent, as shown in the example above. ->setHeight(’80′) sets the heigh of the image. The default may be good for you; I only chose it because my font file was a bit big.
->setFont(’/path/to/your/fontFile.ttf’) points to which font you want to use for the image. I’d recommend a san serif font, as others may be too hard for humans to read. Do a quick google search for .ttf files, you should find one online without too much trouble. Contact me if you want one that I used though!
Finally, ->setImgDir(’/path/to/your/image/captchaDirectory’) should point to the directory you created in step 2.
Let’s talk abit about what the Zend Framework is doing for us with the generate(); command. Basically, it makes a random string of numbers and lower case letters and makes an image out of this using your font and some GD trickery/artistry to make it look funny, and more importantly - (even more) non robot readable. Then, it stores all the information in a session called up by…
4.) Write validateCaptcha() function
-
//validates captcha response
-
function validateCaptcha($captcha) {
-
$captchaId = $captcha[‘id’];
-
$captchaInput = $captcha[‘input’];
-
$captchaSession = new Zend_Session_Namespace(‘Zend_Form_Captcha_’ . $captchaId);
-
$captchaIterator = $captchaSession->getIterator();
-
$captchaWord = $captchaIterator[‘word’];
-
if( $catchaWord ) {
-
if( $captchaInput != $captchaWord ){
-
return false;
-
} else {
-
return true;
-
}
-
} else {
-
return false;
-
}
-
}
vaidateCaptcha() is pretty simple as well. First, you get data sent by the form through the function in $captcha, an array you set up in the controller later on. It contains 2 pieces of information, - the CAPTCHA session’s id, and what the user (hopefully human!) entered into the form. Using the id, it accesses the session, and gets the correct word. The word is compared to what the input entered, and the function returns appropriately.
5.) This is where you make it clap
Here’s a quick example of what the code would look like in the backend + frontend. I’ll write the code using Zend’s MVC standards if someone requests, but I think you guys can figure this out.
-
//setup CAPTCHA
-
$captchaId = generateCaptcha(); //generates CAPTCHA image and session, returns session’s ID
-
-
$captcha = $_POST[‘captcha’]; //get array sent in $_POST form
-
if( validateCaptcha($captcha) ) {
-
//if a true value is sent, process form
-
} else {
-
//captcha invalid, text doesn’t match
-
}
-
}
And now the frontend.
-
<!–?=$_SERVER[‘PHP_SELF’] ?–><form action="<?=$_SERVER['PHP_SELF'] ?>" method="POST">
-
<img src="/your/captchaDirectory/<!–?=$captchaId ?–><?=$captchaId ?>.png" alt=""/><br />
-
What’s the word above say? <input type="text" name="captcha[input]" />
-
<input type="hidden" value="<!–?=$captchaId ?–><?=$captchaId ?>" name="captcha[id]"/>
-
<input type="submit" value="test me"/>
-
</form>
-
And that’s it! Hopefully this is useful to someone on the internet!







December 17th, 2008 on 12:56 am
Hi mate!
Thanks for the pingback
I’ll update my example to link back to yours, if someone wants it this way
Until then, I submitted your post to dzone.com: http://www.dzone.com/links/tutorial_using_zendcaptchaimage.html
Cheers!
December 17th, 2008 on 1:09 am
[...] #2: Here’s an example of using Zend_Captcha without the whole Zend Framework [...]
December 17th, 2008 on 2:30 am
Realy useful tutorial
December 19th, 2008 on 12:33 pm
I recently needed a quick captcha generation code for a project, so I did pretty much what you’re doing here.
However, the problems began when I didn’t want to use Zend_Session. There just was absolutely no way it would work without Zend_Session, so I just ended up gutting Zend_Captcha_Image and Zend_Captcha_Word into a single class with everything related to Zend_Session removed.
Tricky. Hope they add a way to generate captchas without those dependencies.
December 19th, 2008 on 10:30 pm
Jani - thanks for commenting!
I looked into what you said, and you don’t necessarily have to use Zend_Session. Instead you can access all the necessary info through the $_SESSION variable.
You just need the captchaId given in the $_POST to get to it. Try:
$sessionName = ‘Zend_Form_Captcha_’ . $captchaId;
$captchaArray = $_SESSION[$sessionName];
$realWord = $captchaArray['word'];
The Zend Framework names the captcha array simply “Zend_Form_Captcha_” + the captcha Id given upon initial generation.
This seemed to work for me, and I didn’t have to call an instance of Zend_Session_Namespace that way.
BTW, the way I figured out what the Session was called was by running a quick var_dump($_SESSION) and taking a peek at the array!
Hope this helps!
December 19th, 2008 on 11:03 pm
[...] Zend_Captcha без связки с Zend_Form, вам будет полезна статья Using Zend_Captcha_Image, опубликованная в блоге Sankho [...]
December 20th, 2008 on 4:36 pm
[...] Tutorial: Using Zend_Captcha_Image [...]
December 23rd, 2008 on 3:47 pm
I found your site on faves.com bookmarking site.. I like it ..gave it a fave for you..ill be checking back later
January 22nd, 2009 on 7:04 pm
What I did for the MVC part was use baseUrl(); ?>/images/captcha/captchaId ?>.png for the image url (having already set baseUrl). And then of course sending the image to the view with $this->view->captchaId
Thanks for your help!
January 26th, 2009 on 8:52 pm
Hi….
Its a very good example, and running good on my local server, but i m facing these errors, while runing it on line….
can i get some help???
Warning: imageftbbox() [function.imageftbbox]: Could not find/open font in /home/.lujak/abc/abc.com/project/library/Zend/Captcha/Image.php on line 483
Warning: imagefttext() [function.imagefttext]: Could not find/open font in /home/.lujak/abc/abc.com/project/library/Zend/Captcha/Image.php on line 486
Warning: imagepng() [function.imagepng]: Unable to open ‘/sharanbrar.com/zumlink/public/images/captcha/2aff183d0435671b6974ea492d77d037.png’ for writing: No such file or directory in /home/.lujak/abc/abc.com/project/library/Zend/Captcha/Image.php on line 557
January 30th, 2009 on 12:54 pm
Navdeep,
It would appear to me that you don’t have the GD library installed.
Did you run phpinfo() on a test php page? If a section about the GD image library didn’t come up, or it’s clearly indicated as not being installed, you need to install the GD library.
It’s not too hard; takes some editing of your php.ini file, hopefully you won’t have to install the actual package files yourself. They are usually installed in most copies of PHP these days.
Do a quick google search for the how-to’s; but if you can’t find any I’ll write a post about it, just comment again.
Hope that helps!
February 2nd, 2009 on 11:43 am
Hi Navdeep Singh , Sankho
I was having same problems, it is not GD think it is in setting correct directory path with DOT… I found this in zend manual, you must put dot before path…
./images/captcha/
setImgDir($imgDir) and getImgDir() allow you to specify the directory in which captcha images are stored. This defaults to “./images/captcha/”, which should look relative to the bootstrap script.
thanks alot for tutorial!
Jan from cz
February 4th, 2009 on 7:41 pm
Благодарю!!!У Вас часто появляются очень интересные посты! Очень поднимаете мое настроение.
February 7th, 2009 on 1:50 pm
вы шутите…21 век на дворе, неужели нет ничего достойного внимания, как энциклопедия.Милые мои, вот нет снега в
гордах, это тоже тема и история, пересмотрите темы.Я почту просматриваю, мне шлют не пойми что, не знаю кто, столько мусора, может оно и нужно, но не в дневнике.Я так понимаю, дневник это часть твоей души.Нам дается право выбирать - пользуйтесь. А информация бесполезной не бывает
February 7th, 2009 on 8:21 pm
У вас RSS в кривой кодировке!
February 8th, 2009 on 3:02 am
Очень понравилось, даже не ожидала.
February 8th, 2009 on 10:28 am
А Вы не задумывались о том, чтобы параллельно завести еще один блог, на смежную тему? У Вас неплохо получается
February 8th, 2009 on 7:17 pm
Delete captcha images generated affer validate
February 8th, 2009 on 9:33 pm
Опубликовал на своем блоге вашу статью, и напечатол там конечно-же обратную ссылку на вас. Но вот зашел посмотреть поевился ли трекбек, а его нет…
February 9th, 2009 on 7:04 am
Неплохой пост, но много лишнего.
February 9th, 2009 on 1:55 pm
Очень интересно!!! Только не очень могу понять как часто обновляется ваш блог?
February 9th, 2009 on 3:52 pm
Классная статья, кстати автору хочу предложить установить от яндекс.денег фишку на сайт “Дай рубль”. Я бы дал, так сказать на поддержание.
February 10th, 2009 on 12:58 am
Ваш пост навел меня на думки *ушел много думать* …
February 10th, 2009 on 5:15 pm
Опутеть как интересно, во задвигаете. Класс!
February 11th, 2009 on 8:16 am
Неплохой пост, но много лишнего.
February 11th, 2009 on 1:35 pm
Great suggestion mr925; when I have some time I’ll update the post to include this.
How would you go about it, and where?
February 20th, 2009 on 1:46 pm
Thanks!
this was most helpful. Me too, I do not really like Zend_Form. As we say in Sweden, most of the time it is “crossing the river to get a bucket of water”.
Regarding the deletion of pngs, question raised by mr925, I guess Zend_Captcha has a garbage collection built in.
But if you go for your own deletion, I think the best would be to run garbage collection. Deleting after validation will only catch the cases who came all the way to validation.
February 20th, 2009 on 7:52 pm
Опубликовал на своем блоге вашу статью, и напечатол там конечно-же обратную ссылку на вас. Но вот зашел посмотреть поевился ли трекбек, а его нет…
March 7th, 2009 on 12:42 am
The Zend tutorial was usefull. But is it possible that you can send me the MVC standards. I’m sorta struggling over here with the arrangement. Hope you can help me out. thanks
March 18th, 2009 on 11:12 pm
Спасибо! У Вас часто появляются очень интересные посты! Однако я бы убрал пару тройку фраз.
March 26th, 2009 on 2:28 am
Hi, great tutorial.
I have everything working fine however I’m wondering how secure this way is?
For example if someone edited the $_POST variable before it hits the website and removes 1 of the inputs (for example - name=”captcha[id]“)
Then when it hits the server it triggers (Undefined index: input ) and the captcha validates even if the codes dont match due to the error .
Hope that makes sense.
April 3rd, 2009 on 2:54 am
проба пера
April 19th, 2009 on 10:31 am
The interesting information. Thanks
April 26th, 2009 on 8:03 am
Thank you! Very informative article!
April 27th, 2009 on 10:36 pm
Thanks for your help!
April 29th, 2009 on 8:14 pm
Neller, I believe I understand what you are saying, and there’s a fairly easy fix to this - I should of realized this possibility earlier. Thanks for commenting!
In line 5 of my example function validateCaptcha, we instantiate the PHP session created by the captcha on your server earlier, in the previous generateCaptcha function. To access the correct PHP session, we need the $captcha array sent through the POST - but you took it away.
Since we can’t access the session, we can’t get the correct word, and the variable representing this - $captchaWord - ultimately ends up with a null value.
The value for $captchaInput also becomes null. Yep - it’s because it was held in the removed $captcha array.
So then, in the last step of the function, it checks if $captchaInput and $captchaWord are equal - and they are. They’ve both become null.
I’m rewriting that step with a quick fix for this. If the session isn’t found, the function returns false. This should lock down the Captcha. Test it out and let me know!
April 29th, 2009 on 8:20 pm
Johnny,
I’ll try to write an article on developing under an MVC environment soon.
Basically, it’s largely a custodial thing. But if you stay with an app for log enough, MVC becomes more valuable as your site starts to requires consistent change. And of course, change is a consistent thing for the web.
It’s also great if you need others to edit your code later on; it decreases the learning curve required to get comfortable with someone else’s code.
I’ll try and shoot you an email when I get around to writing this article. Thanks for the comment and request!
May 28th, 2009 on 8:17 pm
Warning: imageftbbox() [function.imageftbbox]: Invalid font filename in C:\wamp\www\tribarter\library\Zend\Captcha\Image.php on line 483
Warning: imagefttext() [function.imagefttext]: Invalid font filename in C:\wamp\www\tribarter\library\Zend\Captcha\Image.php on line 486
Warning: imagepng() [function.imagepng]: Unable to open ‘images/captcha/604ac905d0fff65dbb081c97b9ece8b7.png’ for writing: No such file or directory in C:\wamp\www\tribarter\library\Zend\Captcha\Image.php on line 557
May 28th, 2009 on 8:18 pm
getting these errors
May 31st, 2009 on 2:16 pm
Kumar,
Those errors are occurring because you haven’t downloaded a .ttf font file for the Captcha generator to use, and you haven’t made a directory for the images to be created and visible to the public. When I wrote in “/path/to/your/fontFile.ttf” I literally meant the path to YOUR font file - not mine. That’s some code you need to write in yourself.
So go download a .ttf file somewhere, and place it in a directory on your server, then point to that file in the code. Then, create a folder underneath your site’s root directory and chmod it to 775 so it’s writeable by the server + others can view it.
Hope this makes sense… pretty standard stuff you’re gonna have to learn how to do if you haven’t yet.
June 24th, 2009 on 10:21 am
[...] posts, I don’t think google is catching them. I did find some useful code on this blog, sankhomalik’s tutorial on using the zend image captcha. It does make some decent notes, so please go read this post first (and thank him, cause so far he [...]