• Subscribe to the RSS feed!
  • Subscribe by Email
  • home
  • blog
  • dev
  • Recent Posts

    • Toggler
      • on February 4, 2010
    • Book review - jQuery 1.3 with PHP
      • on January 6, 2010
    • 2009 in a few words
      • on January 2, 2010
    • Bad Firebug!
      • on December 21, 2009
    • Posterous
      • on December 2, 2009
    • Chaining routes in Zend Framework
      • on November 27, 2009
    • Zend Framework bug hunt days
      • on November 22, 2009
    • Zend Framework 1.8 Web Application Development book review
      • on November 17, 2009
    • A book review
      • on October 11, 2009
    • Playing with Zend_Navigation and routes
      • on August 9, 2009
  • Recent Comments

    • Aryashree Pritikrishna
      • on January 28th @ 9:10 am
    • Michl
      • on January 15th @ 10:09 am
    • Robert
      • on January 2nd @ 1:36 pm
    • Ivan
      • on January 2nd @ 1:33 pm
    • Keith Pope
      • on January 1st @ 11:57 am
    • Jani Hartikainen
      • on December 29th @ 8:55 am
    • johnjbarton
      • on December 22nd @ 1:01 am
    • Robert
      • on December 21st @ 11:55 pm
    • René Silva
      • on December 21st @ 11:47 pm
    • Robert van Drunen
      • on December 21st @ 6:37 pm
  • Tags

    • php
    • framework
    • zend
    • example
    • random
    • about
    • site
    • ubuntu
    • blog
    • introduction
    • book
    • wordpress
    • linux
    • apache
    • lamp
    • setup
    • review
    • open source
    • svn
    • comic
  • Categories

    • Blablabla
    • Development
    • Free time
    • Places on the web
    • Programming
    • Software
  • Archives

    • February 2010
    • January 2010
    • December 2009
    • November 2009
    • October 2009
    • August 2009
    • May 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • November 2008
    • October 2008
    • September 2008
  • Find me on

    • DZone
    • Google Code
    • Google Reader
    • Last.fm
    • StumbleUpon
    • Twitter
    • Vimeo
  • Friends and Blogs

    • Andrew Taylor
    • Andy Sowards
    • Bojan Pejić
    • Eran Galperin
    • Graham Smith
    • Jani Hartikainen
    • Jasper Tandy
    • Matthew Turland
    • Matthew Weier O’Phinney
    • Miff
    • Miloš Ćuković
    • Nebojša Radović
    • Nemanja Avramović
    • Nemanja Tobić
    • Nikola Krajačić
    • Nikola Plejić
    • Pádraic Brady
    • Rob Allen
    • Swizec Teller
    • Vladimir Stanković
    • WeAreJustCreative
    • Željko Stevanović
  • I use

    • 960 Grid System
    • jQuery
    • Notepad++
    • Subversion
    • Trac
    • Vim
    • Zend Framework

A Zend_Captcha example

by Robert Basic on October 22nd, 2008

Update: I made an error in the example code, regarding the CAPTCHA image URL. I’m sorry for any troubles caused by this mistake.

Update #2: Here’s an example of using Zend_Captcha without the whole Zend Framework stuff.

Update #3: There was an unintentional error in the captchaAction() method, Adam warned me about it in the comments. The error is fixed now. Thanks Adam.

OK, this was a bit tricky and I found no examples about it, so I thought to blog it. I’ll just show a quick example how to implement Zend_Captcha into a Zend_Form, may be useful for someone. There are several CAPTCHA types in ZF, like the Image, Figlet and Dumb. I use Image.

First of all, we’ll use sessions, so we need to change the bootstrap file a little:

// Put this line somewhere after the Zend_Loader::registerAutoload(); line
Zend_Session::start();

We need to start the session to use it, putting it close to the top will assure that there will be no “Headers already sent by…” errors caused by a wrongly placed session start.

Next we need a folder which has a 777 permission on it (Windows users, you can skip this… Or start using GNU/Linux) where we will put our captcha images for a while… This folder must be in the public folder somewhere. So create one.

How does this work? When a captcha is generated, it generates a unique ID (e.g. 539e517b0c0f4e32ef634dae92f07f77) and the word on the image. That unique ID is used for the file name of the image and for the session namespace (the namespace is like: Zend_Form_Captcha_uniqueId), so it knows which image belongs to which session. Also, the generated word is placed inside it’s own session. That ID is placed on the form in a hidden field, so when the submission is received, we can access the ID and recreate the correct session namespace and access the data in it: the word on the image.

Awesome. Now, to the fun part. I use the Zend_Form_Element_Captcha class, so no additional fooling around is needed to put the captcha in the form. Here’s the code:

public function indexAction()
{
// Our form object...
$form = new Zend_Form();
// And here's our captcha object...
$captcha = new Zend_Form_Element_Captcha(
        'captcha', // This is the name of the input field
        array('label' => 'Write the chars to the field',
        'captcha' => array( // Here comes the magic...
        // First the type...
        'captcha' => 'Image',
        // Length of the word...
        'wordLen' => 6,
        // Captcha timeout, 5 mins
        'timeout' => 300,
        // What font to use...
        'font' => '/path/to/font/FontName.ttf',
        // Where to put the image
        'imgDir' => '/var/www/project/public/captcha/',
        // URL to the images
        // This was bogus, here's how it should be... Sorry again :S
        'imgUrl' => 'http://project.com/captcha/',
)));
// Add the captcha element to the form...
$form->setAction('/index/captcha/')
        ->setMethod('post')
        // Add the captcha to the form...
        ->addElement($captcha)
        ->addElement('submit','Submit')
// Pass the form to the view...
$this->view->form = $form;
}

On the other side, it goes something like this:

public function captchaAction()
{
  $request = $this->getRequest();
  // Get out from the $_POST array the captcha part...
  $captcha = $request->getPost('captcha');
  // Actually it's an array, so both the ID and the submitted word
  // is in it with the corresponding keys
  // So here's the ID...
  $captchaId = $captcha['id'];
  // And here's the user submitted word...
  $captchaInput = $captcha['input'];
  // We are accessing the session with the corresponding namespace
  // Try overwriting this, hah!
  $captchaSession = new Zend_Session_Namespace('Zend_Form_Captcha_'.$captchaId);
  // To access what's inside the session, we need the Iterator
  // So we get one...
  $captchaIterator = $captchaSession->getIterator();
  // And here's the correct word which is on the image...

  $captchaWord = $captchaIterator['word']
  // Now just compare them...
  if($captchaInput == $captchaWord)
  {
  // OK
  }
  else
  {
  // NOK
  }
}

Easy, ain’t it?

Happy hacking :)

Tip: Using a monospace or a serif font for the words on the image (like FreeMono.ttf found by default on Ubuntu), makes the word quite unreadable — with the FreeMono.ttf about 8 out of 10 is UNreadable — so use a sans-serif font.

Share this post:
  • Digg
  • description
  • del.icio.us
  • StumbleUpon
  • Facebook
  • Reddit
  • TwitThis
  • Google
  • E-mail this story to a friend!
Other posts you might be interested in: Starting with Zend Framework - part 2, Starting with Zend Framework, MyUrl view helper for Zend Framework, Login example with Zend_Auth, Playing with Zend_Navigation and routes, or just wonder on through the archives...
If you liked this post, you can buy me a cup of coffee!
Tags: captcha, example, framework, php, zend.
Categories: Development, Programming, Software.
Subscribe to the feed.

Comments: 35

Grab the comments feed

  • Jani Hartikainen

  • October 23rd, 2008

Unless I’m mistaken, you could simply do $form->isValid($_POST) to check if the CAPTCHA element (and any other elements) in the form was valid or not. You would of course need to recreate the form, but you could probably delegate that to a method in the controller so you could easily use it in both actions.

  • Simple CAPTCHA Tutorial with Zend Framework | eKini: Web Developer Blog

  • October 24th, 2008

[...] 2008-10-24 This guy has an updated post for Zend_Captcha. Mine is old an [...]

  • Robert

  • October 24th, 2008

Hi Jani!

Yes, it can be done that way also, but I just wanted to show how the session can be recreated and the captcha validated “by hand”. Soon as I get some time, I’ll update the post to show the validation with the isValid() method also.

Thanks for the feedback :)

Regards,
Robert

  • Robert Basic’s Blog: A Zend_Captcha example : WebNetiques

  • October 24th, 2008

[...] and Zend_Form components of the Zend Framework “a bit tricky” and decided to share an example he’s come up with to help others out [...]

  • Robert Basic’s Blog: A Zend_Captcha example : Dragonfly Networks

  • October 24th, 2008

[...] and Zend_Form components of the Zend Framework “a bit tricky” and decided to share an example he’s come up with to help others out [...]

  • Links interesantes

  • October 29th, 2008

[...] A Zend_Captcha exaple - Robert Basic [...]

  • Mike

  • November 2nd, 2008

Hi,

nice example, how i can get the /var/www/project/public/captcha/ without hard coding if i only extends Zend_Form. i.e.

class Form_Message extends Zend_Form
{
public function init()
{
$captcha = new Zend_Form_Element_Captcha(
‘captcha’, // This is the name of the input field
array(’label’ => ‘Write the chars to the field’,
‘captcha’ => array( // Here comes the magic…
// First the type…
‘captcha’ => ‘Image’,
// Length of the word…
‘wordLen’ => 6,
// Captcha timeout, 5 mins
‘timeout’ => 300,
// What font to use…
‘font’ => ‘/path/to/font/FontName.ttf’,
// Where to put the image
‘imgDir’ => ‘/var/www/project/public/captcha/’,
// URL to the images
‘imgUrl’ => ‘/var/www/project/public/captcha/’,
)));
}
}

Thanks,

Mike

  • Robert

  • November 2nd, 2008

Hi Mike!

Sorry but I don’t understand what you want to do. What hard-coding?

  • Mike

  • November 3rd, 2008

Hi Robert,

many thanks for fast response. What i mean is that in Zend_Form_Element_Captcha it requires the path and file for font, imgDir and imgUrl. Is it possible that i can pass like a baseURL ($this->baseUrl) rather than hard-coded path (/var/www/project/public/captcha/). The class declartion i set was

class myForm extends Zend_form
{
public class init(){
// my form here with captcha
}
}

Thanks again,

Mike

  • Robert

  • November 3rd, 2008

Sure you can Mike!

Zend_Controller_Front::getInstance()->getBaseUrl() will get you the base URL.
You can also define the paths in some config file and load it from there.
I’m short on time so I just can give you where to look in the manual:
8.4.2.2. Base Url and Subdirectories
6.3. Zend_Config_Ini

Cheers!

  • Mike

  • November 3rd, 2008

Hi Robert,

many thanks, it works, $_SERVER['DOCUMENT_ROOT'] and Zend_Registry is fine with me

setAction(’/message’)
->setMethod(’post’)
->setName(’frmMessage’)
->setAttribs(array(’id’ => ‘frmMessage’, ‘onSubmit’ => ‘return validateMessage();’));

$name = new Zend_Form_Element_Text(’name’);
$name->setLabel(’Name’)
->setRequired(true)
->addValidator(’NotEmpty’, true)
->setValue(’Guess’)
->setDecorators(array(
‘ViewHelper’,
‘Description’,
‘Errors’,
array(’HtmlTag’, array(’tag’ => ‘div’)),
array(’Label’, array(’tag’ => ‘div’)),
));

$message = new Zend_Form_Element_Textarea(’message’);
$message->setLabel(’Message’)
->setRequired(true)
->addValidator(’NotEmpty’)
->setAttribs(array(’rows’ => ‘1′, ‘cols’ => ‘15′))
->setDecorators(array(
‘ViewHelper’,
‘Description’,
‘Errors’,
array(’HtmlTag’, array(’tag’ => ‘div’)),
array(’Label’, array(’tag’ => ‘div’)),
));

$captcha = new Zend_Form_Element_Captcha(
‘captcha’, // This is the name of the input field
array(’label’ => ‘Write the chars to the field’,
‘captcha’ => array( // Here comes the magic…
// First the type…
‘captcha’ => ‘Image’,
// Length of the word…
‘wordLen’ => 3,
// Captcha timeout, 5 mins
‘timeout’ => 300,
// What font to use…
‘font’ => $_SERVER['DOCUMENT_ROOT'] . ‘/captcha/times.ttf’,
// Where to put the image
‘imgDir’ => $_SERVER['DOCUMENT_ROOT'] . ‘/captcha/’,
// URL to the images
‘imgUrl’ => Zend_Registry::getInstance()->configuration->webhost . ‘/captcha/’,
)));

$captcha->setDecorators(array(
‘Description’,
‘Errors’,
array(’HtmlTag’, array(’tag’ => ‘div’)),
array(’Label’, array(’tag’ => ‘div’)),
));

$submit = new Zend_Form_Element_Submit(’submit’);
$submit->setLabel(’Submit’)
->setDecorators(array(
‘ViewHelper’,
‘Description’,
‘Errors’,
array(’HtmlTag’, array(’tag’ => ‘div’)),
));

$this->addElements(array($name, $message,
$captcha, $submit));
}
}

thanks,

Mike

  • Mussawir

  • November 26th, 2008

I am really thankful to you for this tutorial I have found it the best among all the tutorial published by any one including zend

  • HardCoder

  • December 16th, 2008

Good example!!!! A lot of thanx to you!!!!

  • Tutorial: Using Zend_Captcha_Image - SankhoMallik.com

  • December 17th, 2008

[...] best example I found was on Robert Basic’s Blog. My only gripe about it was that it used [...]

  • Adam

  • December 20th, 2008

Hey mate, nice tutorial.
Just wanted to let you know that on line 3 of the captchaAction() code snippet it ought to be
$request = $this->getRequest();
instead of
$request->$this->getRequest();

cheers.

  • Использование Zend_Captcha | Zend Framework по-русски

  • December 20th, 2008

[...] Если вы используете Zend_Form, то вам понадобится статья Zend_Captcha example, автор Robert Basic. В случае, если вы хотите использовать [...]

  • Robert

  • December 20th, 2008

Hi Adam!

Thanks for the heads up, fixed now :)

Cheers!

  • gimly

  • December 21st, 2008

Thanks alot - great tutorial! I got it running in no time.

  • gsx

  • December 30th, 2008

Robert thanks

But if I want to add more fonts and random generate it what should I do ?

  • BradGman

  • December 31st, 2008

A little confusing towards the end there …

Just to clarify Zend_Form’s built in isValid functionality will confirm the validity of captchas as well.

  • James

  • January 23rd, 2009

I don’t know if I’m going crazy. Why doesn’t this work for me?

I seem to have problem storing value of $captchaIterator['word'] into $captchaWord on line 20 that says $captchaWord = $captchaIterator['word'];
I believe this line is causing an error b/c I tried to echo $captchaIterator['word'] out to the screen, but it says “Undefined index”

I did add a semi-colon at the end of this line since I do believe I needed it.

Everything else works great for me.

I don’t know if it has anything to do with the fact that I changed from ‘captcha’ => ‘Image’ to ‘captcha’ => ‘figlet’. I also commented out the following lines:
‘font’ => ‘/path/to/font/FontName.ttf’,
// Where to put the image
‘imgDir’ => ‘/var/www/project/public/captcha/’,
// URL to the images
// This was bogus, here’s how it should be… Sorry again :S
‘imgUrl’ => ‘http://project.com/captcha/’,

I’m really a noob.
Hope you can point out where I went wrong.

  • Richard Knop

  • January 25th, 2009

Hey Robert, great post!

I’ve started to learn to use Zend Framework just recently (have been using my own framework so far but it is beginning to get a little insufficient) and image captcha was one of the first things I wanted to try but I was not quite sure how to do it from the official documentation.

Thanks ;)

  • colleen

  • February 2nd, 2009

so then how do you do this if you want to do a recaptcha. It is just a javascript thing.

  • Robert

  • February 2nd, 2009

ReCaptcha is a service, for which you need to make an account. Never worked with it, so all I can give you is the link to the manual page: http://framework.zend.com/manual/en/zend.service.recaptcha.html
It shouldn’t be too hard to implement.

  • Anees

  • February 11th, 2009

Hi,
when i tried with your sample code am getting an error message as
Fatal error: Call to undefined method ReflectionClass::newInstanceArgs() in D:\xampp\htdocs\zendtest\library\Zend\Form\Element\Captcha.php on line 72

Do you have any Idea about this?

Regards
Anees

  • Charlie

  • March 17th, 2009

I had some hassle getting Zend to work with my PHP setup but once that worked, I managed to follow this tutorial in no time! My new app is now captcha-fied!

  • Serega

  • March 19th, 2009

Good example!!!! A lot of thanx to you!!!!

  • dude

  • March 19th, 2009

thanks alot ! now it works like a charm

  • Ron

  • March 20th, 2009

That Zend stuff always confused me lol. Thanks for this clearly laid out and excellent tutorial. Noobs like me really really appreciate this kind of stuff. It makes me feel thankful that the internet exists because otherwise where the hell would I get the little tidbits I need now and again. Thanks again Robert.

Ron

  • Jan Viehweger

  • April 22nd, 2009

thanx for the good example!!!

@Anees
I’ve had the same error. I could fix it by making a new instance of Zend_Captcha_Image. Look at my workaround:

public function indexAction()
{
// Our form object…
$form = new Zend_Form();
// And here’s our captcha object…

$captchaImage = new Zend_Captcha_Image(array(
‘wordLen’ => 6,
// Captcha timeout, 5 mins
‘timeout’ => 300,
// What font to use…
‘font’ => ‘/path/to/font/FontName.ttf’,
// Where to put the image
‘imgDir’ => ‘/var/www/project/public/captcha/’,
// URL to the images
‘imgUrl’ => ‘http://project.com/captcha/’
));

$captchaElement = new Zend_Form_Element_Captcha(
‘captcha’, // This is the name of the input field
array(’label’ => ‘Write the chars to the field’,
‘captcha’ => $captchaImage));

// Add the captcha element to the form…
$form->setAction(’/captcha/captcha/’)
->setMethod(’post’)
// Add the captcha to the form…
->addElement($captchaElement)
->addElement(’submit’,'Submit’);
// Pass the form to the view…
$this->view->form = $form;
}

hope this helps …

jan

  • igor

  • June 7th, 2009

Used your example on my site, but getting only the background with dots and lines, no text. Here’s the code

$captcha = new Zend_Form_Element_Captcha(’captcha’, array(
‘label’ => ‘Prove you are human:’,
‘captcha’ => array(
‘captcha’ => ‘Image’,
‘wordlen’ => 6,
‘timeout’ => 300,
‘font’ => $_SERVER['DOCUMENT_ROOT'] . ‘/zf_whitenet/public/fonts/arial.ttf’,
‘imgDir’ => ‘captcha’,
‘imgUrl’ => ‘http://localhost/zf_whitenet/public/captcha’)));

$this->addElement($captcha);

  • slawek

  • June 11th, 2009

Great tutorial - thank you.
I have one problem - when I refresh my page after giving wrong captcha code I get following error: “Notice: Undefined index: word in E:\program\www\myapp\application\controllers\IndexController.php”
I tryied to fix it with “try” but it doesn’t work. Any ideas to solve this annoying problem. Gretz.

  • vietanhit

  • July 17th, 2009

getting these errors (ZF 1.8.4):

Warning: imageftbbox() [function.imageftbbox]: Invalid font filename in C:\wamp\www\Zend_Framework\zf_captcha\library\Zend\Captcha\Image.php on line 489

Warning: imagefttext() [function.imagefttext]: Invalid font filename in C:\wamp\www\Zend_Framework\zf_captcha\library\Zend\Captcha\Image.php on line 492

Warning: imagepng() [function.imagepng]: Unable to open ‘/Zend_Framework/zf_captcha/public/img/ffa6e2ec474d49875ff2b131806c704c.png’ for writing: No such file or directory in C:\wamp\www\Zend_Framework\zf_captcha\library\Zend\Captcha\Image.php on line 563

  • vietanhit

  • July 17th, 2009

I use “arial.ttf” font, put it in public/img folder:

$baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl();
// Our form object…
$form = new Zend_Form();
// And here’s our captcha object…
$captcha = new Zend_Form_Element_Captcha(
‘captcha’, // This is the name of the input field
array(’label’ => ‘Write the chars to the field’,
‘captcha’ => array( // Here comes the magic…
// First the type…
‘captcha’ => ‘Image’,
// Length of the word…
‘wordLen’ => 6,
// Captcha timeout, 5 mins
‘timeout’ => 300,
// What font to use…
‘font’ => $baseUrl . ‘/img/arial.ttf’,
// Where to put the image
‘imgDir’ => $baseUrl . ‘/img/’,
// URL to the images
// This was bogus, here’s how it should be… Sorry again :S
‘imgUrl’ => ‘http://project.com/captcha/’,
)));

  • vietanhit

  • July 17th, 2009

I’ve solved the problem, replace

‘font’ => $baseUrl . ‘/img/arial.ttf’,
‘imgDir’ => $baseUrl . ‘/img/’,
‘imgUrl’ => ‘http://project.com/captcha/’,

with this:

‘font’ => “./img/arial.ttf”,
‘imgdir’ => “./img”,
‘imgurl’ => “./img”

Don’t want to use $baseUrl .
Thanks this tutorial ! :)

Leave a Reply

 

Robert Basic © 2008 — 2010
Design & graphics by: Livia Radvanski
Coded by: Robert Basic
Home page last updated on November 30th, 2009.
Frameworks used: Zend Framework, jQuery, 960 Grid System
Blog is powered by Wordpress
Subscribe: Entries — RSS & Comments — RSS