« Return to Thread: My_Captcha_Image

Re: My_Captcha_Image

by zendlearner :: Rate this Message:

Reply to Author | View in Thread

*SOLVED* and found a bug or strange behavior

Hi Matthew, the problem was not the use of a relative path to the font, but the fact that I needed to pass an array of options to my custom captcha image adapter. Here is what worked for me based on my previous code:

<?php
class TakeFoodOut_SignupForm extends Zend_Form
{
    public function init()
    {
        // add the captcha element
        $this->addElement('captcha', 'captcha', array(
        'label' => 'Word Verification',
        'description' => 'Please verify that you are human',
        'helper' => null,
        'order' => 4,
          'captcha' => array(
        'captcha' => 'Image',
        'wordLen' => 6,
        'timeout' => 300,
        'font' => 'pics/captcha/DeJaVuSansMono.ttf',
        'fontSize' => 30,
        'imgDir' => 'pics/captcha/img',
        'imgUrl' => 'http://takefoodout/pics/captcha/img'
                         )
                ));
                $this->getElement('captcha')
                         ->setCaptcha(new TakeFoodOut_Captcha_Image(array(
                          'captcha'=>'Image',
                          'wordLen' => 6,
        'timeout' => 300,
        'font' => 'pics/captcha/DeJaVuSansMono.ttf',
        'fontSize' => 30,
        'imgDir' => 'pics/captcha/img',
        'imgUrl' => 'http://takefoodout/pics/captcha/img'
        )));
    }
}

Note how the instance of TakeFoodOut_Captcha_Image is passed an array of options including the font. I think what confused me was that I was already passing an array of options to addElement() so I didn't think that I needed to do it again in setConfig().

Now I would like to share my preferred way of creating a captcha element using a custom captcha image adapter and addPrefixPath(). I would also like to explain a potential bug when you use this method and how to avoid the bug.  Please take a look at two versions of my code. The commented code is just another way of writing the code above it. The first one causes a bug, and the second one works fine.

Buggy:
<?php
class TakeFoodOut_SignupForm extends Zend_Form
{
    public function init()
    {
        $this->addElement(new Zend_Form_Element_Captcha('captcha', array('captcha'=>'Image')));
        // OR $this->addElement('captcha', 'captcha', array('captcha' => 'Image'));
        // OR $this->addElement('captcha', 'captcha', array('captcha'=> array('captcha' => 'Image')));
       
                $this->getElement('captcha')
                        ->addPrefixPath('TakeFoodOut_Captcha', 'TakeFoodOut/Captcha/', 'captcha')
                        ->setOptions(array(
                                'label' => 'Word Verification',
                                'description' => 'Please verify that you are human',
                                'helper' => null,
                                'order' => 4
                                ))
                        ->setCaptcha('Image', array('font'=>'images/font/DeJaVuSansMono.ttf'));
                /* OR
                $this->getElement('captcha')
                        ->addPrefixPath('TakeFoodOut_Captcha', 'TakeFoodOut/Captcha/', 'captcha')
                        ->setOptions(array(
                                'label' => 'Word Verification',
                                'description' => 'Please verify that you are human',
                                'helper' => null,
                                'order' => 4,
        'captcha' => array(
                          'captcha'=>'Image',
                          'wordLen' => 6,
        'timeout' => 300,
        'font' => 'pics/captcha/DeJaVuSansMono.ttf',
        'fontSize' => 30,
        'imgDir' => 'pics/captcha/img',
        'imgUrl' => 'http://takefoodout/pics/captcha/img'
        )
                                ));
                */
    }
}

Works fine:
<?php
class TakeFoodOut_SignupForm extends Zend_Form
{
    public function init()
    {
        $this->addElement(new Zend_Form_Element_Captcha('captcha', array('captcha'=>'Image')));
        // OR $this->addElement('captcha', 'captcha', array('captcha' => 'Image'));
        // OR $this->addElement('captcha', 'captcha', array('captcha'=> array('captcha' => 'Image')));
       
                $this->getElement('captcha')
                        ->addPrefixPath('TakeFoodOut_Captcha', 'TakeFoodOut/Captcha/', 'captcha')
                        ->setOptions(array(
                                'label' => 'Word Verification',
                                'description' => 'Please verify that you are human',
                                'helper' => null,
                                'order' => 4
                                ))
                        ->setCaptcha('Foo', array('font'=>'images/font/DeJaVuSansMono.ttf'));
                /* OR
                $this->getElement('captcha')
                        ->addPrefixPath('TakeFoodOut_Captcha', 'TakeFoodOut/Captcha/', 'captcha')
                        ->setOptions(array(
                                'label' => 'Word Verification',
                                'description' => 'Please verify that you are human',
                                'helper' => null,
                                'order' => 4,
        'captcha' => array(
                          'captcha'=>'Foo',
                          'wordLen' => 6,
        'timeout' => 300,
        'font' => 'pics/captcha/DeJaVuSansMono.ttf',
        'fontSize' => 30,
        'imgDir' => 'pics/captcha/img',
        'imgUrl' => 'http://takefoodout/pics/captcha/img'
        )
                                ));
                */
    }
}

Notice the difference between the two codes? They are exactly the same except for setConfig() method:

Buggy: setCaptcha('Image', array('font'=>'images/font/DeJaVuSansMono.ttf'));
Works fine: setCaptcha('Foo', array('font'=>'images/font/DeJaVuSansMono.ttf'));

Basically, setCaptcha('Image') calls Zend_Captcha_Image instead of TakeFoodOut_Captcha_Image, even though I added prefix path: addPrefixPath('TakeFoodOut_Captcha', 'TakeFoodOut/Captcha/', 'captcha'). To prevent this from happening, I had to rename class TakeFoodOut_Captcha_Image to class TakeFoodOut_Captcha_Foo and rename TakeFoodOut/Captcha/Image.php to  TakeFoodOut/Captcha/Foo.php. Once I made the change, it now works.

I hope this helps someone in their attempts to customize the captcha form element.  Prior to this, I thought that I can customize the captcha form element using just form decorators. However, I now realize that there are times when form decorators are insufficient and the only way is to create custom captcha adapters.






Matthew Weier O'Phinney-3 wrote:
-- zendlearner <kimbaudi@gmail.com> wrote
(on Saturday, 21 March 2009, 01:26 PM -0700):
> Thanks for your response. Unfortunately, neither 'captcha' => $captchaimage
> nor 'captcha' => 'My_Captcha_Image' works.  You seem to be on the right
> track, but I get an exception:
>
> Warning: Exception caught by form: Image CAPTCHA requires font Stack Trace:

This is telling you exactly the problem -- you either didn't specify the
font to use, or specified an invalid path. Looking further...

<snip>
>         'font' => 'pics/captcha/DeJaVuSansMono.ttf',

... the problem is you are using a relative path to the font... but
you're not saying where it's relative _to_. Specify a full path to the
font, based on some known path (document root, APPLICATION_PATH constant
if you've set it, dirname(__FILE__) from the file where you create the
form, whatever), and you should be fine.


--
Matthew Weier O'Phinney
Software Architect | matthew@zend.com
Zend Framework     | http://framework.zend.com/

 « Return to Thread: My_Captcha_Image