Native Captcha for Your Form in Magento 1.7
Nick Kravchuk Avatar

Magento 1.7 came with a lot of changes and new features – one substantial module that was added by default is captcha. So, we would like to shed the light on this amazing feature. You know how many robots/spam bots browse the internet searching unprotected forms. Argh.. Therefore, if you have opened form for unregistered users you need to protect it with captcha to avoid spam attacks :)In this article we’ll show you how to add captcha to the form you want. Let’s start.
First of all, we should register our captcha module, note that captcha functionality also can be a part of your own modules – but we would like to create the separate one. This is registration file Atwix_Captcha.xml:

<config>
    <modules>
        <Atwix_Captcha>
            <active>true</active>
            <codePool>community</codePool>
        </Atwix_Captcha>
    </modules>
</config>

The next step is creating the config.xml file under app/code/community/Atwix/Captcha/etc. Actually, we need to declare only blocks, layout and controllers. Here you go:

<?xml version="1.0"?>
<config>
    <global>
        <blocks>
            <atwix_captcha>
                <class>Atwix_Captcha_Block</class>
            </atwix_captcha>
        </blocks>
    </global>
    <frontend>
        <routers>
            <atwix_captcha>
                <use>standard</use>
                <args>
                    <module>Atwix_Captcha</module>
                    <frontName>atwix-captcha</frontName>
                </args>
            </atwix_captcha>
        </routers>
        <layout>
            <updates>
                <atwix_captcha>
                    <file>atwix_captcha.xml</file>
                </atwix_captcha>
            </updates>
        </layout>
    </frontend>
</config>

After this, we need to create two blocks, which are called Captcha.php and Captcha/Zend.php. See below how to do it.
Captcha.php:

class Atwix_Captcha_Block_Captcha extends Mage_Captcha_Block_Captcha
{
    /**
     * Renders captcha HTML (if required)
     *
     * @return string
     */
    protected function _toHtml()
    {
        $blockPath = 'atwix_captcha/captcha_zend';
        $block = $this->getLayout()->createBlock($blockPath);
        $block->setData($this->getData());
        return $block->toHtml();
    }
}

Captcha/Zend.php:

class Atwix_Captcha_Block_Captcha_Zend extends Mage_Captcha_Block_Captcha_Zend
{
    /**
     * Renders captcha HTML (if required)
     *
     * @return string
     */
    protected function _toHtml()
    {
        $this->getCaptchaModel()->generate();

        if (!$this->getTemplate()) {
            return '';
        }
        $html = $this->renderView();

        return $html;
    }

    /**
     * Returns URL to controller action which returns new captcha image
     *
     * @return string
     */
    public function getRefreshUrl()
    {
        return Mage::getUrl(
            Mage::app()->getStore()->isAdmin() ? 'adminhtml/refresh/refresh' : 'atwix-captcha/captcha/refresh',
            array('_secure' => Mage::app()->getStore()->isCurrentlySecure())
        );
    }
}

Look through the getRefreshUrl() function, it calls controller that we should create to provide refreshing captcha image:

class Atwix_Captcha_CaptchaController extends Mage_Core_Controller_Front_Action
{
    /**
     * Refreshes captcha and returns JSON encoded URL to image (AJAX action)
     * Example: {'imgSrc': 'http://example.com/media/captcha/67842gh187612ngf8s.png'}
     *
     * @return null
     */
    public function refreshAction()
    {
        $formId = $this->getRequest()->getPost('formId', false);
        if ($formId) {
            $captchaModel = Mage::helper('captcha')->getCaptcha($formId);
            $this->getLayout()->createBlock('atwix_captcha/captcha_zend')->setFormId($formId)->setIsAjax(true)->toHtml();
            $this->getResponse()->setBody(json_encode(array('imgSrc' => $captchaModel->getImgSrc())));
        }
        $this->setFlag('', self::FLAG_NO_POST_DISPATCH, true);
    }
}

That’s it, functionality that allows us to use captcha is ready, the next task will be creating form. Supposing that we have layout XML and template with form, take a look at the following example:

<?xml version="1.0"?>
<layout>
    <atwix_captcha_test_form>
        <reference name="root">
            <action method="setTemplate"><template>page/1column.phtml</template></action>
        </reference>
        <reference name="head">
            <action method="addJs"><file>mage/captcha.js</file></action>
        </reference>
        <reference name="content">
            <block type="core/template" name="atwix.test" template="atwix.phtml">
                <block type="atwix_captcha/captcha" name="captcha">
                    <action method="setFormId">
                        <id>form-validate-captcha</id>
                    </action>
                    <action method="setImgWidth">
                        <width>300</width>
                    </action>
                    <action method="setImgHeight">
                        <height>40</height>
                    </action>
                </block>
            </block>
        </reference>
    </atwix_captcha_test_form>
</layout>

Let’s get across XML below:

<block type="atwix_captcha/captcha" name="captcha">
    <action method="setFormId">
        <id>form-validate-captcha</id>
    </action>
    <action method="setImgWidth">
        <width>300</width>
    </action>
    <action method="setImgHeight">
        <height>40</height>
    </action>
</block>

That is captcha block, moreover – setImgHeight and setImgWidth functions allow us to set captcha size, the setFormId function defines unique identificator for captcha that’s required. Note, that such form id is not actual form id. So, make sure that <form id=”test” and <action method=”setFormId”><id>form-validate-captcha</id> are not the same values.

You can see that we have template atwix.phtml with form HTML, and following code snippet allows us to render captcha:

<div><?php echo $this->getChildHtml('captcha') ?></div>

By the way, for rendering this page we need to declare controller TestController.php under app/code/community/Atwix/Captcha/controllers, example:

class Atwix_Captcha_TestController extends Mage_Core_Controller_Front_Action
{
    public function formAction()
    {
        $this->loadLayout();
        $this->renderLayout();
    }
}

Note: if you run Magento Enterprise edition, captcha won’t work on the CMS page because of the cache. To get captcha working with Magento’s Full page cache just add the following code after form closing tag:

<script type="text/javascript">
    //<![CDATA[
    $('form-validate-captcha').captcha.refresh($('catpcha-reload'));
    //]]>
</script>

And finally, you should add captcha validation in the controller that processes your form:

$_data = $this->getRequest()->getPost();
$_captcha = Mage::getModel('customer/session')->getData('form-validate-captcha_word');
if ($_captcha['data'] == $_data['captcha']['form-validate-captcha']) {
    echo 'Well Done!';
} else {
    echo 'You\'re disgusting robot!';
}

That’s all.

Thanks for reading and best regards from the Atwix team :)