The problem above have successfully solved,below is code:
[size="3"]Source Code:[/size]
file position:D:\phpwork\news\models\RegisterForm.php
class RegisterForm extends Model{
public function rules()
{
return [
['verifyCode', 'codeVerify'],
......
];
}
//verify with function codeVerify(),avoid bug with Yii2 captcha's validation.
public function codeVerify($attribute) {
//Param:'captcha',is name 'captcha' in actions() of controller;Yii::$app->controller,the controller that call this function
$captcha_validate = new \yii\captcha\CaptchaAction('captcha',Yii::$app->controller);
if($this->$attribute){
$code = $captcha_validate->getVerifyCode();
if($this->$attribute!=$code){
$this->addError($attribute, 'The verification code is incorrect.');
}
}
}
file position:D:\phpwork\news\controllers\SiteController.php
class SiteController extends CommonController{
public function actions(){
return [
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
],
];
}
public function actionRegister()
{
$model = new RegisterForm();
if ($model->load(Yii::$app->request->post())) {
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return \yii\widgets\ActiveForm::validate($model);
}
if($model->validate()){
$error=$model->save();
if($error) {
return $this->errorDisplay($error);
}else{
//After data save successful,must generate new verify code.
$captcha_validate = new \yii\captcha\CaptchaAction('captcha',$this);
$captcha_validate->getVerifyCode(true);
Yii::$app->session->setFlash('success');
return $this->refresh();
}
}else{
return $this->errorDisplay($model->getErrors());
}
}else{
return $this->render('register', [
'model' => $model,
]);
}
}
file position:D:\phpwork\news\views\site\register.php
<?php
/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model app\models\ContactForm */
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
$this->title = 'User Register';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-contact">
<h1><?= Html::encode($this->title) ?></h1>
<?php if (Yii::$app->session->hasFlash('success')): ?>
<div class="alert alert-success">
Register successful!
</div>
<p>
You can now <a href="/site/login">Login</a>.
</p>
<?php else: ?>
<div class="row">
<div class="col-lg-6">
<?php $form = ActiveForm::begin([
'id' => 'contact-form',
]); ?>
<?= $form->field($model, 'member',['enableAjaxValidation'=>true])->textInput(['autofocus' => true])->hint('Can be chinese,grapheme or number.Only use to login,not public display!') ?>
<?= $form->field($model, 'memkey')->passwordInput() ?>
<?= $form->field($model, 'memkey_repeat')->passwordInput() ?>
<?= $form->field($model, 'nickname',['enableAjaxValidation'=>true])->textInput()->hint('Can be chinese,grapheme or number,can have blank space.For public display only!') ?>
<?= $form->field($model, 'verifyCode',['enableAjaxValidation'=>true])->widget(Captcha::className(), [
'captchaAction'=>'site/captcha',
'imageOptions'=>['id'=>'captchaimg','alt'=>'click change image','title'=>'click change image', 'style'=>'cursor:pointer'],
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
<?php endif; ?>
</div>
[size=“3”]Yii2 Captcha Bug validation’s reason[/size]
First time validation with Ajax is true,so $this->getVerifyCode(true); will run,that new VerifyCode will be generated;Second time validation with $model->verify() will failure,Below is Yii2 source file:
file position:D:\phpwork\news\vendor\yiisoft\yii2\captcha\CaptchaAction.php
public function validate($input, $caseSensitive)
{
$code = $this->getVerifyCode();
$valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0;
$session = Yii::$app->getSession();
$session->open();
$name = $this->getSessionKey() . 'count';
$session[$name] = $session[$name] + 1;
//Bug is produced by these code:
if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) {
$this->getVerifyCode(true);
}
return $valid;
}
[size="3"](end)[/size]