PHP Recoverable Error – yii\base\ErrorException

I need some help please I am having this error and I don’t understand





1. in C:\wamp\www\yiibasic\vendor\yiisoft\yii2\web\User.php at line 232

223224225226227228229230231232233234235236237238239240241


     * in this case.

     *

     * @param IdentityInterface $identity the user identity (which should already be authenticated)

     * @param integer $duration number of seconds that the user can remain in logged-in status.

     * Defaults to 0, meaning login till the user closes the browser or the session is manually destroyed.

     * If greater than 0 and [[enableAutoLogin]] is true, cookie-based login will be supported.

     * Note that if [[enableSession]] is false, this parameter will be ignored.

     * @return boolean whether the user is logged in

     */

    public function login(IdentityInterface $identity, $duration = 0)

    {

        if ($this->beforeLogin($identity, false, $duration)) {

            $this->switchIdentity($identity, $duration);

            $id = $identity->getId();

            $ip = Yii::$app->getRequest()->getUserIP();

            if ($this->enableSession) {

                $log = "User '$id' logged in from $ip with duration $duration.";

            } else {

                $log = "User '$id' logged in from $ip. Session not enabled.";









sorry but what is it?

line number?!!

You might want to try the advanced app, it gives you a working user model out of the box. You need to follow the directions here. To get it to work, you have to follow the instructions very carefully, including running the migration to intialize, however they are very complete instructions, so you should be able to do it. A lot of your other questions can be answered by the guide.

Personally, I found that by playing with the advanced template, I was able to learn a lot about the basic structure of the user model, instead of trying to figure out how to create the user model from scratch. The advanced template gives you a working registration, login, and forgot password out of the box. Then you can modify it how you want after you understand the structure.

Means your app\models\User model should implement yii\web\IdentityInterface.

Is this correct




<?php


namespace app\models;


use Yii;


/**

 * This is the model class for table "user".

 *

 * @property integer $id

 * @property string $username

 * @property string $password

 */

class User extends \yii\db\ActiveRecord implements yii\web\IdentityInterface

{

    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return 'user';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['username', 'password'], 'required'],

            [['username', 'password'], 'string', 'max' => 50]

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'id' => 'ID',

            'username' => 'Usernames',

            'password' => 'Passwords',

        ];

    }


    public static function findIdentity($id)

    {

        return static::findOne($id);

    }


    /**

     * Finds an identity by the given token.

     *

     * @param string $token the token to be looked for

     * @return IdentityInterface|null the identity object that matches the given token.

     */

    public static function findIdentityByAccessToken($token, $type = null)

    {

        return static::findOne(['access_token' => $token]);

    }


    /**

     * @return int|string current user ID

     */

    public function getId()

    {

        return $this->id;

    }


    /**

     * @return string current user auth key

     */

    public function getAuthKey()

    {

        return $this->auth_key;

    }


    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

        return $this->getAuthKey() === $authKey;

    }







    public static function findByUsername($username)

    {

        /*foreach (self::$users as $user) {

            if (strcasecmp($user['username'], $username) === 0) {

                return new static($user);

            }

        }*/


        $user = User::find()->where(['username' => $username])->one();


        return $user;

    }


    public function validatePassword($password)

    {

        return $this->password === $password;

    }







}






@samdark,I get fatal error if I Implements the IdentityInterface

yii\web\IdentityInterface → \yii\web\IdentityInterface

Okay I change it to your suggestion but I am getting this error.





1. in C:\wamp\www\yiibasic\vendor\yiisoft\yii2\web\User.php at line 232




     * in this case.

     *

     * @param IdentityInterface $identity the user identity (which should already be authenticated)

     * @param integer $duration number of seconds that the user can remain in logged-in status.

     * Defaults to 0, meaning login till the user closes the browser or the session is manually destroyed.

     * If greater than 0 and [[enableAutoLogin]] is true, cookie-based login will be supported.

     * Note that if [[enableSession]] is false, this parameter will be ignored.

     * @return boolean whether the user is logged in

     */

    public function login(IdentityInterface $identity, $duration = 0)//[b]The error is pointing here[/b]

    {

        if ($this->beforeLogin($identity, false, $duration)) {

            $this->switchIdentity($identity, $duration);

            $id = $identity->getId();

            $ip = Yii::$app->getRequest()->getUserIP();

            if ($this->enableSession) {

                $log = "User '$id' logged in from $ip with duration $duration.";

            } else {

                $log = "User '$id' logged in from $ip. Session not enabled.";






here is User.php




<?php


namespace app\models;


use Yii;

use \yii\db\ActiveRecord;

use \yii\web\IdentityInterface;


/**

 * This is the model class for table "user".

 *

 * @property integer $id

 * @property string $username

 * @property string $password

 */

class User extends ActiveRecord implements IdentityInterface

{

    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return 'user';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['username', 'password'], 'required'],

            [['username', 'password'], 'string', 'max' => 50]

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'id' => 'ID',

            'username' => 'Usernames',

            'password' => 'Passwords',

        ];

    }


    public static function findIdentity($id)

    {

        return static::findOne($id);

    }


    /**

     * Finds an identity by the given token.

     *

     * @param string $token the token to be looked for

     * @return IdentityInterface|null the identity object that matches the given token.

     */

    public static function findIdentityByAccessToken($token, $type = null)

    {

        return static::findOne(['access_token' => $token]);

    }


    /**

     * @return int|string current user ID

     */

    public function getId()

    {

        return $this->id;

    }


    /**

     * @return string current user auth key

     */

    public function getAuthKey()

    {

        return $this->auth_key;

    }


    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

        return $this->getAuthKey() === $authKey;

    }







    public static function findByUsername($username)

    {

        /*foreach (self::$users as $user) {

            if (strcasecmp($user['username'], $username) === 0) {

                return new static($user);

            }

        }*/


        $user = User::find()->where(['username' => $username])->one();


        return $user;

    }


    public function validatePassword($password)

    {

        return $this->password === $password;

    }







}




LoginForm.php




<?php


namespace app\models;


use Yii;

use yii\base\Model;


/**

 * LoginForm is the model behind the login form.

 */

class LoginForm extends Model

{

    public $username;

    public $password;

    public $rememberMe = true;


    private $_user = false;


    /**

     * @return array the validation rules.

     */

    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'],

        ];

    }


    /**

     * Validates the password.

     * This method serves as the inline validation for password.

     *

     * @param string $attribute the attribute currently being validated

     * @param array $params the additional name-value pairs given in the rule

     */

    public function validatePassword($attribute, $params)

    {

        if (!$this->hasErrors()) {

            $user = User::findByUsername($this->username);





            if (!$user || !$user->validatePassword($this->password,['password', 'validatePassword'])) {

                $this->addError($attribute, 'Incorrect username or password.'.$this->password);

            }

        }

    }


    /**

     * Logs in a user using the provided username and password.

     * @return boolean whether the user is logged in successfully

     */

    public function login()

    {

        if ($this->validate()) {

            return Yii::$app->user->login($this->username, $this->rememberMe ? 3600*24*30 : 0);

        } else {

            return false;

        }

    }


    /**

     * Finds user by [[username]]

     *

     * @return User|null

     */

    public function getUser()

    {

        if ($this->username === false) {

            $this->username = User::findByUsername($this->username);

        }


        return $this->username;

    }

}




What’s error message?

This is the error

Call to a member function validatePassword() on a non-object

And this how my LoingForm.php


<?php


namespace app\models;


use Yii;

use yii\base\Model;


/**

 * LoginForm is the model behind the login form.

 */

class LoginForm extends Model

{

    public $username;

    public $password;

    public $rememberMe = true;


    private $_user = false;


    /**

     * @return array the validation rules.

     */

    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'],

        ];

    }


    /**

     * Validates the password.

     * This method serves as the inline validation for password.

     *

     * @param string $attribute the attribute currently being validated

     * @param array $params the additional name-value pairs given in the rule

     */

    public function validatePassword($attribute, $params)

    {

        if (!$this->hasErrors()) {

            $user = $this->getUser();


            if (!$user || !$user->validatePassword($this->password)) {//This line is error

                $this->addError($attribute, 'Incorrect username or password.');

            }

        }

    }


    /**

     * Logs in a user using the provided username and password.

     * @return boolean whether the user is logged in successfully

     */

    public function login()

    {

        if ($this->validate()) {

            return Yii::$app->user->login($this->username, $this->rememberMe ? 3600*24*30 : 0);

        } else {

            return false;

        }

    }


    /**

     * Finds user by [[username]]

     *

     * @return User|null

     */

    public function getUser()

    {

        if ($this->username === false) {

            $this->username = User::findByUsername($this->username);

        }


        return $this->username;

    }

}



Well, that means you’ve tried logging in with username that does not exist. You haven’t handled it properly in validatePassword() method.

can you help me please how to handled it.Is there some code that I miss in validatePasssword() method ?.

here is the User.php I forgot to post.




<?php


namespace app\models;


use Yii;

use \yii\db\ActiveRecord;

use \yii\web\IdentityInterface;


/**

 * This is the model class for table "user".

 *

 * @property integer $id

 * @property string $username

 * @property string $password

 */

class User extends ActiveRecord implements IdentityInterface

{

    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return 'user';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['username', 'password'], 'required'],

            [['username', 'password'], 'string', 'max' => 50]

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'id' => 'ID',

            'username' => 'Username',

            'password' => 'Password',

        ];

    }


    public static function findIdentity($id)

    {

        return static::findOne($id);

    }


    /**

     * Finds an identity by the given token.

     *

     * @param string $token the token to be looked for

     * @return IdentityInterface|null the identity object that matches the given token.

     */

    public static function findIdentityByAccessToken($token, $type = null)

    {

        return static::findOne(['access_token' => $token]);

    }


    /**

     * @return int|string current user ID

     */

    public function getId()

    {

        return $this->id;

    }


    /**

     * @return string current user auth key

     */

    public function getAuthKey()

    {

        return $this->auth_key;

    }


    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

        return $this->getAuthKey() === $authKey;

    }







    public static function findByUsername($username)

    {

        /*foreach (self::$users as $user) {

            if (strcasecmp($user['username'], $username) === 0) {

                return new static($user);

            }

        }*/


        $user = User::find()->where(['username' => $username])->one();


        return $user;

    }


    public function validatePassword($password)

    {

        return $this->password === $password;

    }


}






Just a suggestion, but I noticed on your getUser method, you are confusing $username with $_user. Shouldn’t it be:


 public function getUser()

    {

        if ($this->_user === false) {

            $this->_user = User::findByUsername($this->username);

        }


        return $this->_user;    }

Also, on login method, try calling $this->getUser(), instead of $username. I believe that is the problem because you are trying to reference the username without actually running the function that returns it and you are confusing the form input with the value in the DB. At least that’s what it looks like to me…

Hi I change it now.but it won’t logging me in.It always says Invalid username or passsword.but I inputted correcly the password and username,the password in database is not encrypted it is just plain text.but why is it always invalid username or password.I think the validating password is failing and I don’t know why.


<?php


namespace app\models;


use Yii;

use yii\base\Model;


/**

 * LoginForm is the model behind the login form.

 */

class LoginForm extends Model

{

    public $username;

    public $password;

    public $rememberMe = true;


    private $_user = false;


    /**

     * @return array the validation rules.

     */

    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'],

        ];

    }


    /**

     * Validates the password.

     * This method serves as the inline validation for password.

     *

     * @param string $attribute the attribute currently being validated

     * @param array $params the additional name-value pairs given in the rule

     */

    public function validatePassword($attribute, $params)

    {

        if (!$this->hasErrors()) {

            $user = $this->getUser();




            if (!$user || !$user->validatePassword($this->password)) {

                $this->addError($attribute, 'Incorrect username or password.');

            }

        }

    }


    /**

     * Logs in a user using the provided username and password.

     * @return boolean whether the user is logged in successfully

     */

    public function login()

    {

        if ($this->validate()) {

            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);

        } else {

            return false;

        }

    }


    /**

     * Finds user by [[username]]

     *

     * @return User|null

     */

    public function getUser()

    {

        if ($this->_user === false) {

            $this->_user = User::findByUsername($this->username);

        }


        return $this->_user;

    }

}



User.php


<?php


namespace app\models;


use Yii;

use \yii\db\ActiveRecord;

use \yii\web\IdentityInterface;


/**

 * This is the model class for table "user".

 *

 * @property integer $id

 * @property string $username

 * @property string $password

 */

class User extends ActiveRecord implements IdentityInterface

{

    /**

     * @inheritdoc

     */

    public $id;

    public $username;

    public $password;


    public static function tableName()

    {

        return 'user';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['username', 'password'], 'required'],

            [['username', 'password'], 'string', 'max' => 50]

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'id' => 'ID',

            'username' => 'Username',

            'password' => 'Password',

        ];

    }


    public static function findIdentity($id)

    {

        return static::findOne($id);

    }


    /**

     * Finds an identity by the given token.

     *

     * @param string $token the token to be looked for

     * @return IdentityInterface|null the identity object that matches the given token.

     */

    public static function findIdentityByAccessToken($token, $type = null)

    {

        return static::findOne(['access_token' => $token]);

    }


    /**

     * @return int|string current user ID

     */

    public function getId()

    {

        return $this->id;

    }


    /**

     * @return string current user auth key

     */

    public function getAuthKey()

    {

        return $this->auth_key;

    }


    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

        return $this->getAuthKey() === $authKey;

    }







    public static function findByUsername($username)

    {

        /*foreach (self::$users as $user) {

            if (strcasecmp($user['username'], $username) === 0) {

                return new static($user);

            }

        }*/


        $user = User::find()->where(['username' => $username])->one();


        return $user;

    }


    public function validatePassword($password)

    {

        return  $this->password === $password;

    }


}



I don’t know why that doesn’t work. But you could try adding these two methods to your user model:







    /**

 	* Validates password

 	*

 	* @param string $password password to validate

 	* @return boolean if password provided is valid for current user

 	*/

    public function validatePassword($password)

    {

        return Yii::$app->security->validatePassword($password, $this->password_hash);

    }


    /**

 	* Generates password hash from password and sets it to the model

 	*

 	* @param string $password

 	*/

    public function setPassword($password)

    {

        $this->password_hash = Yii::$app->security->generatePasswordHash($password);

    }



Then make sure your user table has a field named password_hash varchar(255) not null

remove the password field, you will not need it.

I’m not sure if this will work, but it’s worth a try. You can see in the validate method above, the framework is looking to validate against this password_hash field name, not password. It’s not a good idea to build a site without password encryption anyway.

Okay I will try this…Can I ask the User.php is implementing IdentityInerface should I also add column access_token in my table user ? what about the auth_key ?..sorry to ask this but I am really confuse in implementing the login on how to get this work.

Thank you in advance.

You will need two fields auth_key varchar(32) Not Null and password_reset_token varchar(255) Nullable. So looking over your user model, I can see differences that will cause it not to work properly. We can try to add the methods and patch it together or you can try the advanced template. I will give you what I have that you will need:





public static function findIdentity($id)

    {

        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);

    }


    /**

 	* @inheritdoc

 	*/

   public static function findIdentityByAccessToken($token, $type = null)

    {

        return static::findOne(['auth_key' => $token]);

    }


    /**

 	* Finds user by username

 	*

 	* @param string $username

 	* @return static|null

 	*/

    public static function findByUsername($username)

    {

        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);

    }


    /**

 	* Finds user by password reset token

 	*

 	* @param string $token password reset token

 	* @return static|null

 	*/

    public static function findByPasswordResetToken($token)

    {

        $expire = Yii::$app->params['user.passwordResetTokenExpire'];

        $parts = explode('_', $token);

        $timestamp = (int) end($parts);

        if ($timestamp + $expire < time()) {

            // token expired

            return null;

        }


        return static::findOne([

            'password_reset_token' => $token,

            'status' => self::STATUS_ACTIVE,

        ]);

    }


    /**

 	* @inheritdoc

 	*/

    public function getId()

    {

        return $this->getPrimaryKey();

    }


    /**

 	* @inheritdoc

 	*/

    public function getAuthKey()

    {

        return $this->auth_key;

    }


    /**

 	* @inheritdoc

 	*/

    public function validateAuthKey($authKey)

    {

        return $this->getAuthKey() === $authKey;

    }


 /**

 	* Generates "remember me" authentication key

 	*/

    public function generateAuthKey()

    {

        $this->auth_key = Yii::$app->security->generateRandomString();

    }


    /**

 	* Generates new password reset token

 	*/

    public function generatePasswordResetToken()

    {

        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();

    }


    /**

 	* Removes password reset token

 	*/

    public function removePasswordResetToken()

    {

        $this->password_reset_token = null;

    }


At the top of the file, you will need the following constant:


const STATUS_ACTIVE = 10;






There are some other contstants that are supposed to be there, but I forget what they are, and I have modified my user model, so I don’t need them. I could do a fresh install of the advanced template to find it, but I don’t have time for that, and you can easily do that yourself. Even if you don’t use it, you could have it for reference, for things like this. There are two additional form models, PasswordResetRequestForm.php and ResetPasswordForm.php, which will need to be in place, if you do not already have them. Reference the advanced template for how to implement. That’s the best I can do. Maybe someone else can do more, but that’s it for me, good luck.

Hi,Thank you.I make my login works.I just comment this two functions




  public function getAuthKey()

    {

      //  return $this->auth_key;

    }


    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

      //  return $this->getAuthKey() === $authKey;

    }



and also I remove those property that I declared on top,this the cause why validatingPassword is failing.

Since,I make this work out.I will try to put auth_key,as what you have suggested.

Thank you for your advice and helping me I appreciated it. :)