CCaptcha in widget

I have used CCaptcha in other widget (my own). Widget could be rendered in many places (other controllers and actions), but form attribute action is on SiteController (actionContact).

I have moved CCaptcha action on my base controller (which other controllers extends), and there is a problem…

If I send form from SiteController action - everything is fine, but if I send it from another controller, captcha isn’t valid. CCaptchaAction generates a new key (when controller is changing to SiteController - where form attribute action is lead to), and my input value key is comparing with this new key - so it is not valid everytime :(

Is there any (simple=better) way to receive this goal?

Hi.

I’ve had the same problem and solved it by extending CCaptcha class.

Below full code of my new class:




<?php

class ExtendedCCaptcha extends CCaptcha

{

    public $controllerId;

    /**

     * Renders the CAPTCHA image.

     */

    protected function renderImage()

    {

        if(isset($this->imageOptions['id']))

        $id=$this->imageOptions['id'];

        else

        $id=$this->imageOptions['id']=$this->getId();

        if (isset($this->controllerId))

        {

            $url=Yii::app()->createUrl("$this->controllerId/".$this->captchaAction,array('v'=>uniqid()));

        }

        else

        {

            $url=$this->getController()->createUrl($this->captchaAction,array('v'=>uniqid()));

        }


        $alt=isset($this->imageOptions['alt'])?$this->imageOptions['alt']:'';

        echo CHtml::image($url,$alt,$this->imageOptions);

    }


    /**

     * Registers the needed client scripts.

     * @since 1.0.2

     */

    public function registerClientScript()

    {

        $cs=Yii::app()->clientScript;

        $id=$this->imageOptions['id'];

        if (isset($this->controllerId))

        {

            $url=Yii::app()->createUrl("$this->controllerId/".$this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));

        }

        else

        {

            $url=$this->getController()->createUrl($this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));

        }


        if($this->showRefreshButton)

        {

            $cs->registerScript('Yii.CCaptcha#'.$id,'dummy');

            $label=$this->buttonLabel===null?Yii::t('yii','Get a new code'):$this->buttonLabel;

            $button=$this->buttonType==='button'?'ajaxButton':'ajaxLink';

            $html=CHtml::$button($label,$url,array('success'=>'js:function(html){jQuery("#'.$id.'").attr("src",html)}'),$this->buttonOptions);

            $js="jQuery('img#$id').after(\"".CJavaScript::quote($html).'");';

            $cs->registerScript('Yii.CCaptcha#'.$id,$js);

        }


        if($this->clickableImage)

        {

            $js="jQuery('#$id').click(function(){"

            .CHtml::ajax(array(

					'url'=>$url,

					'success'=>"js:function(html){jQuery('#$id').attr('src',html)}",

            )).'});';

            $cs->registerScript('Yii.CCaptcha#2'.$id,$js);

        }

    }

}

?>



With this it seems to work, it only requires to set property for $controllerId like any other property of CCaptcha, and its not full name of controller but its ID as You can use while making URL with Yii::app()->createUrl(…) function (that means for “SiteController” it’s “site” and for AnyController it would be “any”). If u forget to set ‘controllerId’ - it should work as CCaptcha does.

I’ve made it this way, becouse I wanted my widget (it is rendered inside of SideBar) to call through ajax only 1 function in specified controller (SiteController in my case), and with this I got it to work.

I had problem rendering the image (I have a cuiDialog in which I use renderPartial to get site/contact, found your post and it worked! Though I cant tell if the validation work yet.