How to refresh captcha image on page refresh/load?

I want to force my site to refresh the captcha image everytime it loads, so I have a javascript method triggered with the onload() event. Here I have the following line:

document.getElementById('yw0_button').click;

Firebug doesn’t detect any errors, and for testing purposes I have added an alert right after the displayed line, and the alert pops up each time the page is loaded. However, the image doesn’t refresh!

  • execute code AFTER Recaptcha.reload() is finished
  • Client Server REST API captcha implementation
  • “Not a robot” recaptcha without a <form> but AJAX instead
  • how to Validate captcha before submit a form in joomla
  • ReCaptcha API v2 Styling
  • Pressing enter key submit the form?
  • This is what I believe is relevant about the view file:

    <?php if(extension_loaded('gd')): ?>
        <div class="row">
            <?php echo $form->labelEx($model,'verifyCode'); ?>
            <div>
                <?php
                $this->widget('CCaptcha',
                              array('showRefreshButton'=>true,
                                    'buttonType'=>'button',
                                    'buttonOptions'=>
                                                        array('type'=>'image',
                                                              'src'=>"/path/images/refresh-icon.png",
                                                              'width'=>30,
                                                        ),                                                            
                                    'buttonLabel'=>'Refrescar imagen'),
                              false); 
                ?>
                <br>
                <?php echo $form->textField($model,'verifyCode'); ?>
            </div>
        <div class="hint">
            Porfavor ingrese las letras como las ve en la imagen superior.
            <br/>No hay distincion entre minúsculas y mayúsculas.</div>
        </div>
    <?php endif; ?>
    

    Any ideas?


    @k to the z just saw this! Yes sure, if you could help me find a more proper solution it would be awesome! This is what i believe is relevant about the view file:

    <?php if(extension_loaded('gd')): ?>
            <div class="row">
                <?php echo $form->labelEx($model,'verifyCode'); ?>
                <div>
                    <?php
                    $this->widget('CCaptcha',
                                  array('showRefreshButton'=>true,
                                        'buttonType'=>'button',
                                        'buttonOptions'=>
                                                            array('type'=>'image',
                                                                  'src'=>"/path/images/refresh-icon.png",
                                                                  'width'=>30,
                                                            ),                                                            
                                        'buttonLabel'=>'Refrescar imagen'),
                                  false); 
                    ?>
                    <br>
                    <?php echo $form->textField($model,'verifyCode'); ?>
                </div>
            <div class="hint">
                Porfavor ingrese las letras como las ve en la imagen superior.
                <br/>No hay distincion entre minúsculas y mayúsculas.</div>
            </div>
        <?php endif; ?>
    

    In the controller I grant authorized users permission in the accessRules() method to the captcha action, and thats about all. Is there something else I could post?

  • How can I resize the recaptcha in Greasemonkey?
  • Verify google reCaptcha fails
  • Detect if user is human without captcha or useragent
  • “Not a robot” recaptcha without a <form> but AJAX instead
  • How to stop CasperJS execution and let the user input some value and then continue to execute?
  • Using Captcha with Meteor's accounts-ui-bootstrap-3
  • 8 Solutions collect form web for “How to refresh captcha image on page refresh/load?”

    In case anyone goes through a similar problem whilst getting started with Yii.. This is how I resolved the CAPTCHA issue triggering a click: I have an event triggered the the onload event, which has the following code:

    $(‘#yw0_button’).click();

    There surely must be a better way, im open to suggestions! However as a temporary solution this works just fine, refreshing the captcha image each time the page is loaded. Good luck!

    EDIT: What I did was handle the onload event for my html page like this

    <body onload="initialize()"> 
    .. 
    </body> 
    

    Then in my js file:

    function initialize() 
    { 
         $('#yw0_button').click(); 
    } 
    

    I hope I can propose a better way to solve the problem mentioned by Soph. I know this is not JavaScript-related solution this question is addicted to but as I can see this one is the most right way to go.

    I faced the same requirement – to refresh the caption on page refresh but preserve this one when user’s input is invalid on other fields because repeating a new verification code on each validation’s fail is annoying. So this task looks like to not refresh the caption on POST request and refresh it otherwise (GET request). A solution proposed by Soph by himself can’t achieve this – as one could know POST requests are sent to server and their data cannot be analyzed by client-side JavaScript.

    Therefore I decided to look at Yii’s captcha implementation. It consists of two classes located in system.web.widgets.captcha package. The former is CCaptcha extended from CWidget and that we use in our view to add a captcha to web form in the manner like this:

    <?php 
        $this->widget("CCaptcha", array(
        'buttonLabel' => "Generate another code",
        'showRefreshButton' => false,
        'clickableImage' => true
    ));
    ?>
    

    The latter is CCaptchaAction that does the most significant work to provide a captcha by generating a verification code and creating an image. Taking into account that Yii is designed to be object-oriented we can create a couple of our own classes Captcha and CaptchaAction extended from CCaptcha and CCaptchaAction relatively and place them in components subdirectory of our web application’s directory.

    My implementation of both these classes is below.

    run() method of CCaptchaAction is overriden and is quite similar to original one excepting that there is one additional if-branch executing when render_refreshed GET-parameter is set and where new verification code is being generated on the fly and corresponding new image is being rendered and returned as action’s result.

    A public refresh variable has been introduced in Captcha class and defaults to false meaning widget’s behavior is similar to CCaptcha‘s one. Overriding renderImage method we alter a code responsible for preparing widget’s output HTML code. To be more precisive it’s where a link to captcha action is prepared used as src attribute of an img tag. In the case of refresh member is set to true an additional render_refreshed parameter is appended to this link.

    Here is CaptchaAction.php:

    <?php
    
    Yii::import("system.web.widgets.captcha.CCaptchaAction");
    
    class CaptchaAction extends CCaptchaAction
    {
        const RENDER_REFRESHED_GET_VAR = "render_refreshed";
    
        public function run()
        {
            if (isset($_GET[self::REFRESH_GET_VAR]))  // AJAX request for regenerating code
            {
                $code = $this->getVerifyCode(true);
                echo CJSON::encode(array(
                    'hash1' => $this->generateValidationHash($code),
                    'hash2' => $this->generateValidationHash(strtolower($code)),
                    // we add a random 'v' parameter so that FireFox can refresh the image
                    // when src attribute of image tag is changed
                    'url'=> $this->getController()->createUrl($this->getId(), array(
                        'v' => uniqid()
                    )),
                ));
            }
            else if (isset($_GET[self::RENDER_REFRESHED_GET_VAR]))
            {
                $this->renderImage($this->getVerifyCode(true));
            }
            else
                $this->renderImage($this->getVerifyCode());
            Yii::app()->end();
        }
    }
    

    And this is Captcha.php:

    <?php
    
    Yii::import("web.system.widgets.CCaptcha");
    
    class Captcha extends CCaptcha
    {
        public $refresh = false;
    
        protected function renderImage()
        {
            if (!isset($this->imageOptions['id']))
                $this->imageOptions['id'] = $this->getId();
    
            if ($this->refresh)
            {
                $url = $this->getController()->createUrl($this->captchaAction, array(
                    'v' => uniqid(),
                    CaptchaAction::RENDER_REFRESHED_GET_VAR => 1
                ));
            }
            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);
        }
    }
    

    So the usage is quite simple. In action preparing model’s data for site’s page do the following:

    ...
    
    // Creating order model's instance
    $model = new MyModel();
    $refreshCaptcha = true;
    
    if (isset($_POST['MyModel']))
    {
        $refreshCaptcha = false;
        ...
    }
    
    ...
    
    $this->render("myView", array(
        'model' => $model,
        'refreshCaptcha' => $refreshCaptcha
    ));
    

    After that modify captcha’s widget call in myView template of this page’s action:

    <?php 
        $this->widget("Captcha", array(
        'buttonLabel' => "Generate another code",
        'showRefreshButton' => false,
        'clickableImage' => true,
        'refresh' => $refreshCaptcha
    ));
    

    and don’t forget to modify actions method of page’s controller by replacing CCaptchaAction class by CaptchaAction:

    public function actions()
    {
        return array(
            'captcha'=>array(
                'class'=>'CaptchaAction',
                'backColor'=>0xFFFFFF
            )
        );
    }
    

    Seems to me that it works as expected. Hope this will help somebody.

    I’d like to add something to the Ezze’s answer:

    To make clientValidation working, you can use custom captcha validation:

    class CaptchaValidatorRefresh extends CCaptchaValidator
    {
        public function clientValidateAttribute($object,$attribute)
    {
        $js="";
    
        if(!$this->allowEmpty)
        {
            $message=$this->message!==null ? $this->message : Yii::t('yii','The verification code is incorrect.');
    
            $js="
                if($.trim(value)=='') {
                    messages.push(".CJSON::encode($message).");
                }
            ";
        }       
        return $js;
        }
    }
    

    and then

    public function rules()
    {
        return array(
            array('verifyCode', 'CaptchaValidatorRefresh', 'on'=>'request', 'allowEmpty'=>!CCaptcha::checkRequirements()),                          
        );
    }
    

    Add this javascript:

    jQuery(document).ready(function() {
        jQuery.ajax({
            'success':function(html){jQuery("#yw0").attr("src",html)},
            'url':'/checkout/finish/captcha?refresh=1',
            'cache':false
        });
        return false;
    });
    

    Here’s another (correct?) way to do it (discussion):

    Yii::app()->getController()->createAction('captcha')->getVerifyCode(true);
    

    I have used : http://www.yiiframework.com/extension/captcha-extended/

    and change CaptchaExtendedAction.php (path: extensions/captchaExtended)

    in line 154

    $this->renderImage($this->getVerifyCode());  
    

    to

    $this->renderImage($this->getVerifyCode(true));
    

    You can write the script before form beginWedget.

    on every page load generate the new captcha code.

      $script=' $(document).ready(function() {
    
                document.getElementById("yw0_button").click();
        });';
      Yii::app()->clientScript->registerScript('yw0_button', $script);
    
      $form=$this->beginWidget('CActiveForm', array(
        'id'=>'test-form',
        'action'=>Yii::app()->createUrl('controllerName/actionName'),
        'enableClientValidation'=>true, 
        'clientOptions'=>array(
            'validateOnSubmit'=>true,
        ),
      ));
    

    it’s work for me.

    I hope it’s also work for you

    I have a better solution for you guys:

    public function beforeAction($action)
    {
        if($action->id == 'captcha'){
            $action->getVerifyCode(true);
        }
        return parent::beforeAction($action); 
    }
    

    Put these codes into the controller which you include captcha action!