Yii Framework Forum: CAPTCHA custom Validation - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

CAPTCHA custom Validation Rate Topic: ***** 1 Votes

#1 User is offline   Darwell.J 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 23-April 11

Posted 14 July 2011 - 11:43 AM

Hello,

Currently I'm doing a log-in form with behaviour similar to GMail's. That means - the CAPTCHA appears only on unsuccessful log-in.
First of all, I have tested the CAPTCHA - it works. Then I added a new variable to the CFormModel:
public $verifyCodeRequired = false;

I have changed the action to look like this:
	public function actionLogin()
	{
		$model=new LoginForm;

		// collect user input data
		if(isset($_POST['LoginForm']))
		{
			$model->attributes=$_POST['LoginForm'];
			// validate user input and redirect to the previous page if valid
			if($model->validate() && $model->login()) 
			{
				$this->redirect(Yii::app()->user->returnUrl);
			}
			[b]$model->verifyCodeRequired = true;[/b]
		}
		// display the login form
		$this->render('login', array('model'=>$model));
	}

There is a validation rule:
array('verifyCode', 'captcha', 'allowEmpty'=>!$this->verifyCodeRequired),

So, the verifyCodeRequired gets a value TRUE, but the validator still passes the field when it's empty. I have also tried making a custom validator:
array('verifyCode', 'validateCaptcha')

        public function validateCaptcha()
	{
		var_dump($this->verifyCodeRequired);
		if($this->verifyCodeRequired)
		{
			$validator = new CCaptchaValidator();
			$validator->attributes = array("verifyCode");
			return $validator->validate($this);
		}
		else {
			return true;
		}
	}

I always get FALSE. How should I achieve desired behaviour?

EDIT: Nevermind, I understood how to achieve that :)

Kind regards,
Darwell
0

#2 User is offline   andy_s 

  • Random Member Title
  • Yii
  • Group: Moderators
  • Posts: 1,526
  • Joined: 22-June 09
  • Location:Russia, Kostroma

Posted 14 July 2011 - 12:18 PM

Quote

EDIT: Nevermind, I understood how to achieve that

Share with others? ;)

And validation rules are created before you can assign model attributes. Using scenarios is the solution.
1

#3 User is offline   Darwell.J 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 23-April 11

Posted 14 July 2011 - 01:45 PM

View Postandy_s, on 14 July 2011 - 12:18 PM, said:

Share with others? ;)

And validation rules are created before you can assign model attributes. Using scenarios is the solution.


I just used a CHttpSession component to store the same value. Could you please tell me more about this being solved with scenarios?
Thanks.
0

#4 User is offline   andy_s 

  • Random Member Title
  • Yii
  • Group: Moderators
  • Posts: 1,526
  • Joined: 22-June 09
  • Location:Russia, Kostroma

Posted 14 July 2011 - 02:34 PM

View PostDarwell.J, on 14 July 2011 - 01:45 PM, said:

I just used a CHttpSession component to store the same value. Could you please tell me more about this being solved with scenarios?
Thanks.

Using sessions is a right solution, because you need to store a value somewhere which indicates that a user was trying to login before. But putting this logic into a model is a wrong way. A model should be independent from sessions.

Scenario is a model's property: http://www.yiiframew...scenario-detail
You can have different validation rules for different scenarios:

public function rules()
{
    return array(
        array('verifyCode', 'captcha', 'on'=>'captchaRequired'),
    );
}

Now verifyCode won't be validated while the current scenario is not "captchaRequired".

Setting a scenario is easy:

$model = new LoginForm;
// if a user already tried to login, then set a scenario:
$model->scenario = 'captchaRequired';


Rules without "on" property will be applied to all scenarios.
Hope this helps ;)
0

#5 User is offline   Darwell.J 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 23-April 11

Posted 14 July 2011 - 03:26 PM

View Postandy_s, on 14 July 2011 - 02:34 PM, said:

Using sessions is a right solution, because you need to store a value somewhere which indicates that a user was trying to login before. But putting this logic into a model is a wrong way. A model should be independent from sessions.

Scenario is a model's property: http://www.yiiframew...scenario-detail
You can have different validation rules for different scenarios:

public function rules()
{
    return array(
        array('verifyCode', 'captcha', 'on'=>'captchaRequired'),
    );
}

Now verifyCode won't be validated until the current scenario won't be "captchaRequired".

Setting a scenario is easy:

$model = new LoginForm;
// if a user already tried to login, then set a scenario:
$model->scenario = 'captchaRequired';


Rules without "on" property will be applied to all scenarios.
Hope this helps ;)

That's great! Thank you :)
0

#6 User is offline   Darwell.J 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 23-April 11

Posted 20 July 2011 - 05:43 AM

Hello once again,

I still have some issues about this solution:
First of all, I don't think that the scenarios WOULD BE enough for second-attempt-captcha-validation, because if I re-open the same URL - I see the form without CAPTCHA and it is not necessary to enter one. Refreshing the page works as expected - I still see CAPTCHA, but re-opening the same URL just makes an easy way to avoid the CAPTCHA. Spambots would benefit from this :)
Second - I can't get it to work. Basically because I am setting the captchaRequired scenario AFTER the form is validated. So it means that the next time I create a model instance, the scenario is not named until the validation passes. I can't think a way how to get the scenario name before errors occur (not CAPTCHA errors, because I can't catch them this way).

So, my final solution is this:
combine scenarios with sessions. Store a scenario name of the model in session and re-name the scenario BEFORE the validation like this:
	public function actionLogin()
	{
		$model = new LoginForm;
		if(Yii::app()->session->contains("loginCaptchaRequired"))
		{
			$model->setScenario("captchaRequired");
		}
		if(isset($_POST['LoginForm']))
		{
			$model->attributes = $_POST['LoginForm'];
			if($model->validate() && $model->login()) 
			{
				echo "Successful login";
				Yii::app()->session->remove("loginCaptchaRequired");
			}
			Yii::app()->session->add("loginCaptchaRequired", "true");
			$model->setScenario("captchaRequired");
		}
		$this->render('login', array('model' => $model));
	}


Please tell me if this method is good enough.
0

#7 User is offline   za_al 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 53
  • Joined: 06-March 12

Posted 10 July 2012 - 07:03 AM

View Postandy_s, on 14 July 2011 - 02:34 PM, said:

Using sessions is a right solution, because you need to store a value somewhere which indicates that a user was trying to login before. But putting this logic into a model is a wrong way. A model should be independent from sessions.

Scenario is a model's property: http://www.yiiframew...scenario-detail
You can have different validation rules for different scenarios:

public function rules()
{
    return array(
        array('verifyCode', 'captcha', 'on'=>'captchaRequired'),
    );
}

Now verifyCode won't be validated while the current scenario is not "captchaRequired".

Setting a scenario is easy:

$model = new LoginForm;
// if a user already tried to login, then set a scenario:
$model->scenario = 'captchaRequired';


Rules without "on" property will be applied to all scenarios.
Hope this helps ;)


tanks .i have same problem .when save model by this soulution.it works. :rolleyes:
0

#8 User is offline   Kailas P. Bedarkar 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 14-December 13

Posted 17 December 2013 - 05:14 AM

public function rules()
{
    return array(
        array('verifyCode', 'captcha', 'on'=>'captchaRequired'),
    );
}

Now verifyCode won't be validated while the current scenario is not "captchaRequired".

Setting a scenario is easy:

$model = new LoginForm;
// if a user already tried to login, then set a scenario:
$model->scenario = 'captchaRequired';


it's working but on view doesn't show validation message. how to show validation message on view.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users