Customization captcha in Zend Framework 2

Component Zend\Captcha can take many forms, including ask logical questions, to generate distorted fonts, and upload multiple images by installing the link between them. Zend\Captcha aims to provide a variety of server solutions that can be used either in standalone mode or in combination with Zend\Form component.

The element has more than one Captcha fields, which are rendered one after the other. Built-in image generator captcha (Zend\Captcha\Image.php) uses its own helper (Zend\Form\View\Helper\Captcha\Image.php) to create the image. So, in Zend\Captcha\Image.php is method 'getHelperName'. This method passes the name of the helper to render an image captcha. Default is 'getHelperName' reports 'captcha/image' is an instance of class Zend\Form\View\Helper\Captcha\Image.php. If you delve through the debugger, you can see that the instance property phpRenderer::__helpers, invokablesClasses is a helper 'captchaimage'. This is Zend\Form\View\Helper\Captcha\Image.php mentioned earlier. Roughly speaking — you simply create the image and everything else is done for you by the renderer using the helper, although this situation does not suit everybody.

When you create a form element Captcha (Zend\Form\Element\Captcha.php), you pass the image captcha(Zend\Captcha\Image.php). The Captcha form element, in turn, has its own helper (Zend\Form\View\Helper\FormCaptcha.php). In the render method of this helper you will see that the image captcha (Zend\Captcha\Image.php) is loaded with ElementInterface:

the
//Zend\Form\View\Helper\FormCaptcha.php
public function render(ElementInterface $element)
{
$captcha = $element- > getCaptcha();


then calls the helper method with 'getHelperName':

the
$helper = $captcha->getHelperName();


In the end we get an instance of the helper class through the instance of PhpRenderer and return performance:

the
$helper = $renderer- > plugin($helper);
return $helper($element);


We need to be clear in the distinction between 'form element Captcha and his helper' and 'the image Captcha is also with his helper'. We will give the 'captcha image' 'the form element Captcha', who already has tied a helper. Method render 'form element Captcha' build instance 'image Captcha', which we delivered using the helper to generate the image and return the view. All you need to do is to transfer the 'image Captcha' new helper that will display the view as we want and to rewrite Zend\Captcha\Image.php, so he got our new helper, not your default.

Before you begin, let's notice a few details:
helper Zend\Form\View\Helper\Captcha\Image.php to display the captcha defines a pattern as %s%s%s:

the
$pattern = '%s%s%s';


Thus, the first thing you need is our custom helper with its own pattern. Let's create it in the module Application:

the
//module\Application\src\Application\View\Helper\Form\Captcha\ViewHelperCaptcha.php
<?php

namespace Application\View\Helper\Form\Captcha;

use Zend\Form\View\Helper\Captcha\AbstractWord;
use Application\View\Helper\Form\Captcha\CustomCaptcha as CaptchaAdapter;
use Zend\Form\ElementInterface;
use Zend\Form\Exception;

class ViewHelperCaptcha extends AbstractWord
{
/**
* Override
*
* Render the captcha
*
* @param ElementInterface $element
* @throws Exception\DomainException
* @return string
*/
public function render(ElementInterface $element)
{
//We can here set the separator between the picture and the input field.
$this->setSeparator(")
$captcha = $element- > getCaptcha();
if ($captcha === null || !$captcha instanceof CaptchaAdapter) {
throw new Exception\DomainException(sprintf(
'%s requires that the element has a "captcha" attribute of type Zend\Captcha\Image; none found',
__METHOD__
));
}
//How long to store the image (default 600).
$captcha- > setExpiration(10);

//How often to clean files(default 10). In this configuration, the oldest file is overwritten with the newly created.
$captcha- > setGcFreq(1);

$captcha->generate();
$imgAttributes = array(
'width' => $captcha->getWidth(),
'height' => $captcha->getHeight(),
'alt' => $captcha->getImgAlt(),
'src' => $captcha- > getImgUrl() . $captcha->getId() . $captcha- > getSuffix(),
);
$closingBracket = $this->getInlineClosingBracket();

'<img %s%s',
$this->createAttributesString($imgAttributes),
$closingBracket
);
$position = $this->getCaptchaPosition();
$separator = $this- > getSeparator();
$captchaInput = $this->renderCaptchaInputs($element);

//Our modified pattern
$pattern = '<div class="captcha_image">
%s</div>
%s<div class="captcha_input">
%s</div>'

if ($position == self::CAPTCHA_PREPEND) {
return sprintf($pattern, $captchaInput, $separator, $img);
}
return sprintf($pattern, $img, $separator, $captchaInput);
}
}


Our class helper duplicates the class Zend\Form\View\Helper\Captcha\Image.php with minor changes. Our helper does not use the Zend\Captcha\Image.php to generate the image, unlike the original. Remember that Zend\Captcha\Image.php provides a method 'getHelperName' which returns a hard-coded name of the helper 'captcha/image', so when the form will generate the image, it will get for this is not your helper by default, and that we've just created. What else is needed is to transfer to the phpRenderer our custom helper and generate a new captcha image that will extend the original class Zend\Captcha\Image.php and overwrite the method 'getHelperName' setting the name of the helper we created.

So, let's add our class to the configuration helper invokables phpRenderer. Implement it in module.config.php:

the
//module\Application\config\module.config.php
...
'view_helpers' => array(
'invokables' => array(
'viewhelpercaptcha' => 'Application\View\Helper\Form\Captcha\ViewHelperCaptcha', 
),
),


The next step will be to create a captcha image, which will return our helper added to the module configuration as invokables phpRenderer class. There is no need to override the whole class Zend\Captcha\Image.php, sufficient to indicate the method 'getHelperName' our custom class for the helper as a parameter. To do this, create a class and name it, for example, CustomCaptcha.php in your module\Application\src\Application\View\Helper\Form\Captcha. We are going to expand the original class Zend\Captcha\Image.php and override the method 'getHelperName' to give our helper 'viewhelpercaptcha'. Can't hurt to override error messages in the property $messageTemplates. At your discretion.

the
//module\Application\src\Application\View\Helper\Form\Captcha\CustomCaptcha.php
<?php

namespace Application\View\Helper\Form\Captcha;

//Original class that we extend.
use Zend\Captcha\Image as CaptchaImage;

//New version of the class in which we will change only what is necessary.
class CaptchaImage extends CustomCaptcha
{ 
protected $messageTemplates = array(
self::MISSING_VALUE = > 'Missing value',
self::MISSING_ID => 'ID Field is missing',
self::BAD_CAPTCHA => 'invalid value',

public function getHelperName()
{
return 'viewhelpercaptcha';
} 
}


The last thing we need to do is use our CustomCaptcha image in the form. To do this, create two folders: one for the font (zf2folder/data/fonts), which you will need to generate the captcha words, and another for storing files of image captchas (zf2folder/public/img/captcha). Of course, in the folder fonts copy font *.ttf, e.g. arial.ttf.

For example, you can take the form from the official tutorial:

the
<?php

namespace Album\Form;

use Zend\Form\Form;
use Application\Form\View\Helper\Captcha\CustomCaptcha;

class AlbumForm extends Form
{
public function __construct($name = null)
{
//The name of the form you can ignore
parent::__construct('album');
$this->setAttribute('method', 'post');

//Here are standard items
...

//Here we create the Captcha

$dirdata = './data';

//Create a new CustomCaptcha class
$captchaImage = new CustomCaptcha(array(
'font' => $dirdata . '/fonts/arial.ttf',
'width' => 120,
'height' => 60,
'fsize' => 20,
'wordLen' = > 5,
'dotNoiseLevel' => 25,
'lineNoiseLevel' => 2
));

//Assign a directory to store files
$captchaImage- > setImgDir('public/img/captcha/');

//Assign path to download files captcha
$captchaImage- > setImgUrl('/img/captcha/');
$captchaImage- > setImgAlt('are You human or robot?');

//Create a Captcha form element where we will add our CustomCaptcha created above

$this->add(array(
'type' => 'Zend\Form\Element\Captcha',
'name' = > 'captcha',
'options' => array(
'captcha' => $captchaImage,
),
'attributes' => array(
'class' = > 'some_class',
)
));

$this->add(array(
'name' => 'submit',
'attributes' => array(

'value' => 'Go',
'id' => 'submitbutton',
),
));
}
}


Add to the file element of our captcha

the
echo $this->formRow($form->get('captcha')) . PHP_EOL; 


Examining the structure of an html document, the resulting output, you will see that now the image and captcha input field wrapped in div's. We got a more streamlined design.

Sources used:
framework.zend.com/manual/2.2/en/modules/zend.captcha.intro.html
framework.zend.com/manual/2.2/en/modules/zend.captcha.operation.html
framework.zend.com/manual/2.2/en/modules/zend.captcha.adapters.html
framework.zend.com/manual/2.2/en/user-guide/forms-and-actions.html
zendtemple.blogspot.com/2012/12/zend-framework-2-zf2-creating-view.html
samsonasik.wordpress.com/2012/09/12/zend-framework-2-using-captcha-image-in-zend-form
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Integration of PostgreSQL with MS SQL Server for those who want faster and deeper

Custom database queries in MODx Revolution

Parse URL in Zend Framework 2