reset password validation in Yii2 - yii2

I have a form in which I am trying to reset the password. I have 3 fields password, changepassword and re-enterpassword.
First I need to check whether the password field matches with database password.
While user signup I have used the default Yii2 functionality which generates random password and saves that password into database. Also I used the default login functionality while user login.
And now, for validating the password, I am trying to use the same default Yii2 validation which is used in login. But, it is not working fine. It is always giving validation true when I had echoed and checked in the controller with $user->validate(), which you will find in the below code.
I have a view resetProfilePassword.php in which I have a form
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?php
echo $form->field($resetpasswordmodel, 'password');
echo $form->field($resetpasswordmodel, 'changepassword');
echo $form->field($resetpasswordmodel, 'reenterpassword');
?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
I have a model resetProfilePasswordForm.php
<?php
namespace frontend\models;
use common\models\User;
use yii\base\Model;
class ResetProfilePasswordForm extends Model
{
public $password;
public $changepassword;
public $reenterpassword;
public function rules()
{
return [
['password', 'validatePassword'],
['changepassword', 'required'],
['reenterpassword', 'required'],
['reenterpassword', 'compare', 'compareAttribute'=>'changepassword', 'message'=>"Passwords don't match" ]
];
}
public function attributeLabels()
{
return [
//'user_profile_id' => 'User Profile ID',
//'user_ref_id' => 'User Ref ID',
'password' => 'Password',
'changepassword' => 'Change Password',
'reenterpassword' => 'Re-enter Password',
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
protected function getUser()
{
if ($this->_user === null) {
$this->_user = User::findByUsername($this->username);
}
return $this->_user;
}
}
This is controller ProfileController.php
public function actionResetProfilePassword()
{
$resetpasswordmodel = new ResetProfilePasswordForm();
if ($resetpasswordmodel->load(Yii::$app->request->post())) {
$user = User::find()->where(['id' => Yii::$app->user->identity->id])->one();
if($user->validate()){
$user->save(false);
}
}
return $this->render('ResetProfilePassword', [
'resetpasswordmodel' => $resetpasswordmodel
]);
}
Please help me where I am facing the issue.
If this is not the right way to validate, please help me in providing the better way to validate password

To apply resetpasswordmodel validation - just run the validate() method and then - update user model like that:
public function actionResetProfilePassword()
{
$resetpasswordmodel = new ResetProfilePasswordForm();
if ($resetpasswordmodel->load(Yii::$app->request->post())) {
$user = User::find()->where(['id' => Yii::$app->user->identity->id])->one();
# here we run our validation rules on the model
if ($resetpasswordmodel->validate()) {
# if it is ok - setting the password property of user
$user->password = $resetpasswordmodel->changepassword;
# and finally save it
$user->save();
}
return $this->render('ResetProfilePassword', [
'resetpasswordmodel' => $resetpasswordmodel
]);
}

you can create new hash and replace it in database with older password
*note: salt is your email account that you want restore it.
$salt= 'omid.ahmadyani#Outlook.com';
$pass = crypt('00000000',$salt);
die($pass);
my new password is 00000000
and my hashed pass is omXXQw/O/i1po
S F My English!

Related

Display validation errors without page refresh

Is there any way I can just display validation errors in Yii2 without a redirect or refresh?
This is my default controller code performing the login action, I would like to highlight the text fields when the data entered does not match the data in the database, a simple validation against the database.
public function actionLogin()
{
/** #var \amnah\yii2\user\models\forms\LoginForm $model */
$model = $this->module->model("LoginForm");
// load post data and login
$post = Yii::$app->request->post();
if ($model->load($post) && $model->validate()) {
$returnUrl = $this->performLogin(
$model->getUser(), $model->rememberMe
);
return $this->redirect($returnUrl);
}
return $this->render('login', compact("model"));
}
You can do it this way:
form login
<?php $form = ActiveForm::begin([
'validationUrl' => Url::toRoute(['site/login-validate']),
'action' => Url::toRoute(['site/login']),
'options' => [
'class' => 'form login'
],
]); ?>
Site Controller
public function actionLoginValidate(){
if(Yii::$app->request->isAjax){
$model = new Login();
if($model->load(Yii::$app->request->post())){
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
}
throw new BadRequestHttpException("This action is not allowed.");
}

how to addError function in yii2 model

i want make form for change password, with field old password and new password like this
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'old_password')->textInput()->label('Old Password ') ?>
<?= $form->field($model, 'password')->passwordInput()->label(' New Password ') ?>
<?= $form->field($model, 'confirm_password')->passwordInput()->label('Confirm new password') ?>
<div class="form-group">
<?= Html::submitButton('Change', ['class' => 'btn btn-primary btn-fill']) ?>
</div>
<?php ActiveForm::end(); ?>
I have controller like this
public function actionPass()
{
$id=Yii::$app->user->id;
$modelUser = $this->findModel($id);
try {
$model = new \frontend\models\ChangePasswordForm($id);
} catch (InvalidParamException $e) {
throw new \yii\web\BadRequestHttpException($e->getMessage());
}
if ($model->load(\Yii::$app->request->post())) {
if ( $model->validate() && $model->changePassword()) {
Yii::$app->session->setFlash('success', 'Password success to change ');
return $this->render('index', [
'model' => $model,
'modelUser' => $modelUser,
]);
} else {
Yii::$app->session->setFlash('error', 'Password failed to change!');
return $this->render('index', [
'model' => $model,
'modelUser' => $modelUser,
]);
}
}
i have model to manage change password process
class ChangePasswordForm extends Model
{
public $id;
public $password;
public $confirm_password;
public $old_password;
/**
* #var \common\models\User
*/
private $_user;
/**
* Creates a form model given a token.
*
* #param string $token
* #param array $config name-value pairs that will be used to initialize the object properties
* #throws \yii\base\InvalidParamException if token is empty or not valid
*/
public function __construct($id, $config = [])
{
$this->_user = User::findIdentity($id);
if (!$this->_user) {
throw new InvalidParamException('Unable to find user!');
}
$this->id = $this->_user->id;
parent::__construct($config);
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['password','confirm_password'], 'required'],
[['password','confirm_password'], 'string', 'min' => 8],
['confirm_password', 'compare', 'compareAttribute' => 'password'],
['old_password','findPasswords'],
];
}
/**
* Changes password.
*
* #return boolean if password was changed.
*/
public function changePassword()
{
$user = $this->_user;
$user->setPassword($this->password);
//$user->ps=$this->password;
return $user->save();
}
public function findPasswords($attribute, $params, $validator)
{
$user = User::findOne(Yii::$app->user->id);
if (!Yii::$app->getSecurity()->validatePassword($this->old_password, $user->password_hash))
$this->addError($attribute, 'The Old Password not match.');
}
}
the error validation for new password and confirm new password works, but not for old password field, the error not show in form when i fill password that not match with old password. Any help?
Shouldn't it be like this?
public function findPasswords($attribute, $params, $validator)
{
$user = User::findOne(Yii::$app->user->id);
if (!Yii::$app->getSecurity()->validatePassword($this->old_password, $user->password_hash))
$this->addError($attribute, 'The Old Password not match.');
return false;
}
return true;
}

Login access not working in yii2

Im using yii2 for my project. I need to use two different tables for login (Login page is same). I have two models Admin and User. And i have one LoginFrom for login.
I can login properly but the problem is after logged in i cannot get whether the admin is logged in or the user is logged in.
I have set it in config file (web.php) like below:
'admin' => [
'identityClass' => 'app\models\Admin',
'enableAutoLogin' => false,
'class' => 'yii\web\User',
'authTimeout' => 1200, // in Seconds. 1200 seconds means 20 mins
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => false,
'authTimeout' => 1200
],
So im getting logged in user details by using below method:
\Yii::$app->admin->identity;
\Yii::$app->user->identity;
My problem is if im logged in as admin i can get user values also by using this : \Yii::$app->user->identity; or if im logged in as user i can get admin values by using this : \Yii::$app->admin->identity;.
My LoginForm.php is :
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user = false;
public function rules()
{
return [
// username and password are both required
[['username', 'password'], 'required'],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// password is validated by validatePassword()
['password', 'validatePassword'],
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
public function login()
{
if ($this->validate()) {
if(!empty($this->getUser()['phone_number'])) {
return Yii::$app->admin->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
} else {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
}
return false;
}
public function getUser()
{
if ($this->_user === false) {
$this->_user = User::findByUsername($this->username);
if(!$this->_user) {
$this->_user = Admin::findByUsername($this->username);
}
}
return $this->_user;
}
}
I cant find the problem and if i logged in identity creating for both the users so i could'nt write access rules in particular controller to allow admin only to access the controller.Please help me :(
From reading the comments I think you should just create a unifying table for the two identities where they both get their IDs from. Then make that the identity class. The reason you are able to see the details in both identity classes is that they have the same ID.

captcha not working using scenarios in yii2

I am trying to add captcha validation based on scenario, for which I am first retrieving number of failed attempts from database. For which I am using checkattempts() function. Based on the result I am displaying captcha in view and adding scenario condition in controller as below.
In LoginForm model:
public function rules()
{
return [
[['username', 'password'], 'required', 'on'=>'loginpage'],
[['username', 'password'], 'required', 'on'=>'withCaptcha'],
[['reference_url'], 'safe'],
[['verifyCode'], 'captcha', 'skipOnEmpty' => true,'on'=>'withCaptcha'],
['username','email', 'on'=>'loginpage', 'message'=> 'Please enter a valid email address'],
['password', 'validatePassword', 'on'=>'loginpage'],
['password', 'validatePassword', 'on'=>'withCaptcha'],
];
}
public function checkattempts($uname)
{
$user = \frontend\models\User::findByEmail($uname);
$ip = $this->get_client_ip();
if($user){
$data = (new Query())->select('*')
->from('login_attempts')
->where(['ip' => $ip])->andWhere(['user_ref_id' => $user->id])
->one();
if($data["attempts"] >=3){
return true;
}else{
return false;
}
}
return false;
}
in SiteController.php controller
public function actionLogin() {
if (!\Yii::$app->user->isGuest) {
return $this->redirect(Yii::$app->getUrlManager()->getBaseUrl() . '/../../');
}
$model = new \common\models\LoginForm();
$model->scenario = 'loginpage';
$captcha = false;
if(Yii::$app->request->post()){
$post_variables =Yii::$app->request->post('LoginForm');
if ($model->checkattempts($post_variables['username'])) {
$model->scenario = 'withCaptcha';
$captcha = true;
}
}
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->login(); print_r($model->getErrors()); exit;
} else {
return $this->render('login', [
'model' => $model, 'captcha' => $captcha,
]);
}
In my login.php view:
<?php if($captcha) { ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(),
['template' => '<div class="captcha_img">{image}</div>'
. '<a class="refreshcaptcha" href="#">'
. Html::img('/images/imageName.png',[]).'</a>'
. 'Verification Code{input}',
])->label(FALSE); ?>
<?php } ?>
In my controller when I am tring to print model errors at $model->login() function it is giving below error everytime even though the verification code is correct.
Array ( [verifycode] => Array ( [0] => The verification code is incorrect. ) )
Why is it failing every time. Is there any mistake in the code written?
Thanks in advance

Yii2 framework - Email Validation in Ajax Form

I'm having an issue validation whether a submitted Email Address is Unique in the database.
When the User registers I need to validate whether the email address exists all of the other validation is working fine.
Is there a step missing when you are validating a using an Ajax form in Yii 2.
A User clicks on CTA to register on site/index
use yii\bootstrap\Modal;
use frontend\models\Register;
use yii\helpers\Html;
use yii\helpers\Url;
...
Modal::begin([
'id' => 'modal',
'size'=>'modal-lg',
'clientOptions' => ['backdrop' => 'static', 'keyboard' => FALSE],
]);
echo "<div id='modalContent'></div>";
Modal::end();
?>
<?= Html::button('Register', ['value' => Url::to(['register/create']), 'title' => 'Register', 'class' => 'btn btn-success','id'=>'modalButton']); ?>
This opens up a modal (register/create)
Model Register
class Register extends User
{
...
public function rules()
{
return [
['Email', 'filter', 'filter' => 'trim'],
['Email', 'required'],
['Email', 'email'],
['Email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'],
];
}
public function signup()
{
$user = new User();
if ($this->validate()) {
$user->Email = $this->Email;
if ($user->save()) {
return $user;
}
} else {
return;
}
}
Register Controller
public function actionCreate()
{
$model = new Register(['scenario' => 'signup']);
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
Yii::error($model);
return $model->validate();
}
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->renderAjax('create', [
'model' => $model,
]);
}
The View file
<?php $form = ActiveForm::begin(['id'=> 'register', 'enableClientValidation'=>true, 'enableAjaxValidation'=>true, 'validateOnChange'=> true, 'validationUrl' => Url::to(['register/create'])] ); ?>
<div class="form-group">
<?= $form->field($model, 'Email') ?>
</div>
Javascript file
$script = <<< JS
$('body').on('beforeSubmit', 'form#register', function (event, jqXHR, settings) {
var form = $(this);
// return false if form still have some validation errors
if (form.find('.has-error').length) {
return false;
}
// submit form
$.ajax({
url: form.attr('action'),
type: 'GET',
data: form.serialize(),
success: function (response) {
// do something with response
$(document).find('#modal').modal('hide');
}
});
return false;
});
JS;
$this->registerJs($script);
I was facing a similar issue where my email field was not triggering the "unique" rule in the javascript validation, but the "unique" rule was getting triggered on the form submit.
It's awesome that you came up with a solution for your question that gets the job done, but I think what I just learned could also shed some insight on this question for others.
The key for me was learning/realizing that the "unique" validation rule must use a database lookup to verify if the user input is unique, thus it must use ajax. Other validation rules, such as "required" or "email" don't need ajax to validate. They just use javascript in the client to validate, so they are client validation, whereas the "unique" validator is actually ajax validation.
Note: my code below is not really addressing your code directly, but is intended to communicate the overall understanding and code structure that is needed to answer your question. Some of these steps you already have, but some are missing :)
First, you need a model with a field that requires a 'unique' rule, such as an email address for a user account.
In your Model
public function rules()
{
$rules = [
[['email'], 'unique'],
// ... and all your other rules ...
];
}
When using \yii\widgets\ActiveForm, client validation is enabled by default, but ajax validation is not.
So, next you need to directly turn on ajax validation in the view. This can be done either for the entire form, or just for a single field. The Yii2 Validation docs explain this best, but in my case, I chose to just enable ajax validation on my email field.
In your View
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($user, 'email', ['enableAjaxValidation' => true])->textInput();
//... other form fields and such here ...
<?php ActiveForm::end(); ?>
Next, you also need to handle the ajax validation in your controller, so your controller method could look something like this:
public function actionRegister()
{
$user = new User();
$post = Yii::$app->request->post();
$userLoaded = $user->load($post);
// validate for ajax request
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($user);
}
// vaidate for normal request
if ($userLoaded && $user->validate()) {
$user->save();
return $this->redirect(['view', 'id' => $user->id]);
}
// render
return $this->render('create', ['user' => $user]);
}
And then here's the catch ... everything above is what you would need when working with a normal (non-ajax) form. In your question, you are working on a form in a modal window that is being submit via ajax, so the above controller method will not work. With ajax forms, it becomes pretty tricky to handle the ajax form validation and the ajax form submit in the same controller method.
As usual, Yii has this all figured out for us, and the validationUrl form parameter will save the day. All you have to do is create a new method in your controller that is specifically for ajax validation, and reference the controller/action URL in your form. Something like this should do the trick:
In your View
<?php $form = ActiveForm::begin([
'id' => 'form-id', // always good to set a form id, especially when working with ajax/pjax forms
'validationUrl' => ['user/validate-email'], //['controller/action'],
]); ?>
In your Controller
public function actionRegister()
{
$user = new User();
$post = Yii::$app->request->post();
// vaidate for normal request
if ($user->load($post) && $user->validate()) {
$user->save();
return $this->redirect(['view', 'id' => $user->id]);
}
// render
return $this->render('create', ['user' => $user]);
}
public function actionValidateEmail()
{
// validate for ajax request
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
$user = new User();
$post = Yii::$app->request->post();
$user->load($post);
return ActiveForm::validate($user);
}
}
Cheers!
I managed to solve this myself by using Javascript to make an Ajax request and PHP to receive the quest and check whether the Email already exists in the database.
function checkEmail(){
var email_check;
// Get the value of the email input field
var input_value = document.getElementById('register-email').value;
// Send the value to a PHP page to check
$.ajax({
url: 'checkemail.php/',
type: 'POST',
data: {
email_check: input_value
},
success: function(response) {
// If we have a repsonse we need to check whether it is True or False
email_check = response;
if (email_check == 1) {
// If True add error class
$('.field-register-email').addClass('has-error');
$('.field-register-email .help-block').text('The email supplied has already been used');
} else {
$('.field-register-email').removeClass('has-error');
$('.field-register-email .help-block').text(' ');
}
}
});
};
This will send a POST request to the checkemail.php which will check whether the email address is in the database