*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/