So I am going to show how to implement a “remember me” feature in CakePHP 2 while utilizing Cake’s Auth.

I assume that you already have a working installation of CakePHP 2 and that the controller which you are using for authentication is called: User. Also, that your username and password fields in the ‘users’ table are called respectively ‘username’ and ‘password’( this should be the case if you want Auth to handle things automatically for you ). If you don’t have Auth configured and working you can go here and follow the instructions there.

So firstly, add the following code to your login form view. This is just using CakePHP form helper to output the “remember me” checkbox and a label. You can style it however you like.

<?php echo $this->Form->input('rememberMe', array('type' => 'checkbox', 'label' => 'Remember me')); ?>

Next, add the following code to your login functionality after you’ve logged in the user. It will just check if the user has selected the “remember me” box and if so it will get the password from the posted data, hash and store it in a cookie on the user’s computer:

if ($this->request->data['User']['rememberMe'] == 1) {
        // After what time frame should the cookie expire
        $cookieTime = "12 months"; // You can do e.g: 1 week, 17 weeks, 14 days

	// remove "remember me checkbox"
	unset($this->request->data['User']['rememberMe']);
				
	// hash the user's password
	$this->request->data['User']['password'] = $this->Auth->password($this->request->data['User']['password']);
				
	// write the cookie
	$this->Cookie->write('rememberMe', $this->request->data['User'], true, $cookieTime);
}

Depending on how your login function is implemented the code above should be used in a similar manner:

if ($this->Auth->login()) {
    // The previous piece of code goes here

    $this->redirect('/users/profile');
}

Next, add the following code in the beforeFilter() method of your AppController class( which resides in app/controller/AppController.php ) so it should look like the following:

class AppController extends Controller {
    // Our code follows from here
    public function beforeFilter() {
	// set cookie options
	$this->Cookie->httpOnly = true;
	
	if (!$this->Auth->loggedIn() && $this->Cookie->read('rememberMe')) {
	     $cookie = $this->Cookie->read('rememberMe');

             $this->loadModel('User'); // If the User model is not loaded already
	     $user = $this->User->find('first', array(
	            'conditions' => array(
	                'User.username' => $cookie['username'],
	                'User.password' => $cookie['password']
	            )
	     ));
	
	     if ($user && !$this->Auth->login($user['User'])) {
	            $this->redirect('/users/logout'); // destroy session & cookie
	     }
     }

     // The rest of AppController goes here
}

Updating the logout function accordingly. Add this to any controller which you want to handle the logout poccess. Note the use of $this->Cookie->delete(‘rememberMe’).

public function logout() {
	$this->Session->setFlash("You've been logged out");
	$this->Cookie->delete('rememberMe');
	$this->redirect($this->Auth->logout());
}

That’s it. You can go ahead and test it now. Note that I’ve tested this on CakePHP 2.2.5 but it should work on anything upwards of 2.0(inclusive)

TIP: When creating new controllers and you are overriding the beforeFilter() method you should add the following code at the beginning of your beforeFilter() method. This ensures that the last piece of code always gets executed:

parent::beforeFilter();

TIP: Remember to load the Cookies component in you AppController as follows:

public $components = array(
                    ‘Cookie’
                    // Load other components
);
Categories: PHP
  • http://www.dereuromark.de mark

    I usually prefer using a component or a auth adapter for this to keep the code outside of the controller/model as much as possible. it is easier to test and maintain than mingling it into the rest of the application code :) see http://www.dereuromark.de/2012/02/02/more-persistent-sessions-in-cake2-x/
    but the basic idea always stays the same, of course.

  • admin

    I’d rather agree but I haven’t thought doing that as I am new to CakePHP I guess. However, I would considering making another post and wrapping the code in a component.

  • DR

    When I try to use this script, I get the following error:

    Notice (8): Indirect modification of overloaded property CakeErrorController::$Cookie has no effect [APP\Controller\AppController.php, line 48]
    Warning (2): Creating default object from empty value [APP\Controller\AppController.php, line 48]
    Fatal error: Call to a member function read() on a non-object in APP\Controller\AppController.php on line 50

    Logging in and out was working fine before trying to add remember me, but now I can’t log in.

    Line 48 is:
    $this->Cookie->httpOnly = true;
    Line 50:
    if (!$this->Auth->loggedIn() && $this->Cookie->read(‘rememberMe’)) {

    Any assistance?

    • DR

      Nevemind, fixed it. You need to define the cookie component like this:
      public $components = array(‘Cookie’);

  • admin

    As well as any other components that you want to access from your controllers.

  • AhdaAhda

    One should also delete the cookie $this->Cookie->delete(‘rememberMe’) when user logs out, otherwise they would get logged right back in from the cookie after they log out

    • moonshots

      Yes, you are right. I’ve update my post to include that.

  • Pingback: Remember me not loading all information cakePHP | BlogoSfera