yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.91k forks source link

Could yii\captcha\Captcha::$captchaAction default value set '/site/captcha' #1992

Closed callmez closed 10 years ago

callmez commented 10 years ago

If use captcha in module. captcha well get wrong refreshUrl.

jQuery('#contactform-verifycode-image').yiiCaptcha({"refreshUrl":"\/Code\/web\/module\/site\/captcha?refresh=1","hashKey":"yiiCaptcha\/site\/captcha"});
callmez commented 10 years ago

and the same setting yii\captcha\CaptchaValidator::$captchaAction

callmez commented 10 years ago

when set yii\captcha\CaptchaValidator::$captchaAction = ' /site/captcha'........

 Error – yii\base\ErrorException  
Invalid CAPTCHA action ID: /site/captcha

#0 E:\wamp\www\Code\vendor\yiisoft\yii2\captcha\CaptchaValidator.php(88): yii\captcha\CaptchaValidator->createCaptchaAction()
cebe commented 10 years ago

This is a route that is valid application wide so it does not have leading slash.

callmez commented 10 years ago

sorry, my bad, I did not give more details about this scenario. i'm not sure it is a bug. so i'll ask help. for example: there is a user module, PasswordResetController must use captcha to verify user behavior. as you said, if i chang yii\captcha\CaptchaValidator::$captchaAction and yii\captcha\Captcha::$captchaAction values to "/site/captcha". first error

Error – yii\base\ErrorException  
Invalid CAPTCHA action ID: /site/captcha

#0 E:\wamp\www\Code\hj\vendor\yiisoft\yii2\captcha\CaptchaValidator.php(88): yii\captcha\CaptchaValidator->createCaptchaAction()

and i change back yii\captcha\Captcha::$captchaAction to default "site/captcha"

//views code
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
        'captchaAction' => '/site/captcha',
        'options' => [
            'class' => 'form-control input-lg',
            'placeholder' => '填写验证码',
        ],
        'template' => '<div class="row"><div class="col-lg-7">{input}</div><div class="col-lg-5">{image}</div></div>',
    ]) ?>
//client side js code
jQuery(document).ready(function() {
    jQuery('#user-verifycode-image').yiiCaptcha({
        "refreshUrl": "\/Code\/hj\/web\/site\/captcha?refresh=1",
        "hashKey": "yiiCaptcha\/\/site\/captcha" //1. and 2.  shuld be same
    });
    jQuery('#login-form').yiiActiveForm({
        "verifyCode": {
            "validate": function(attribute, value, messages) {
                yii.validation.captcha(value, messages, {
                    "hash": 674,
                    "hashKey": "yiiCaptcha\/site\/captcha", //2. and 1. shuld be same
                    "caseSensitive": false,
                    "message": "\u9a8c\u8bc1\u7801\u4e0d\u6b63\u786e\u3002"
                });
            },
            "name": "user-verifycode",
            "validateOnChange": true,
            "validateOnType": false,
            "validationDelay": 200,
            "container": ".field-user-verifycode",
            "input": "#user-verifycode",
            "error": ".help-block"
        }
    },
    {
        "errorSummary": ".error-summary",
        "validateOnSubmit": true,
        "errorCssClass": "has-error",
        "successCssClass": "has-success",
        "validatingCssClass": "validating",
        "ajaxVar": "ajax"
    });
});

the second error is at client side, when user click the captcha img to switch captcha code.

///yii.captcha.js will refresh the code and record hashKey
        refresh: function () {
            var $e = this,
                settings = this.data('yiiCaptcha').settings;
            $.ajax({
                url: $e.data('yiiCaptcha').settings.refreshUrl,
                dataType: 'json',
                cache: false,
                success: function(data) {
                    $e.attr('src', data.url);
                    $('body').data(settings.hashKey, [data.hash1, data.hash2]); // this will use 1. hashKey value
                }
            });
        },
//yii.validation.js
captcha: function (value, messages, options) {
            if (options.skipOnEmpty && isEmpty(value)) {
                return;
            }

            // CAPTCHA may be updated via AJAX and the updated hash is stored in body data
            var hash = $('body').data(options.hashKey); // this will use 2. hashKey value, will use old captcha code and can't verify user input captcha code
            if (hash == null) { 
                hash = options.hash;
            } else {
                hash = hash[options.caseSensitive ? 0 : 1];
            }
            var v = options.caseSensitive ? value : value.toLowerCase();
            for (var i = v.length - 1, h = 0; i >= 0; --i) {
                h += v.charCodeAt(i);
            }
            if (h != hash) {
                addMessage(messages, options.message, value);
            }
        },

I try my best to describe this problem. please tell me some thing if i was wrong. thinks very mush.

cebe commented 10 years ago

To which controller have you added captcha action?

callmez commented 10 years ago

Can we only use siteController::actionCaptcha as default captcha?