User Registration and Login With CakePHP 1.2.x

I’m going to create a simple user registration form with a confirm password field!

Features of this implementation:

  • Uses AuthComponent
  • Confirm password field
  • Ensures unique usernames
  • User feedback if any errors occur
  • Remember me feature (cookies)

Prerequisites

I assume you have a database structure similar to the following:

Users and Groups tables

Note: CakePHP automagically updates the created and modified fields.

App Controller

Place the following code in /app/controllers/app_controller.php

<?php

class AppController extends Controller {
	var $components = array( 'Auth', 'RememberMe' );

	function beforeFilter() {
		$this->Auth->logoutRedirect =  '/';
		$this->Auth->loginRedirect = '/';
		$this->RememberMe->check();
	}
}
?>

The two lines $this->Auth->log*** determine where the user is directed after they login. Another option (instead of ‘/’), is $this->referer(). That will bring the user back to the page they were just at (sweet)!

What’s this remember me crap though?

Remember Me

This guy wrote an excellent component that you can simply pop in your /app/controllers/components folder and you’re ready to go.

The Form

Place the following code in /app/views/users/register.ctp

<?php
	echo $form->create('User', array( 'url' => array( 'action' => 'register' ) ) );
	echo $form->input('username',
					 	array('after' => $form->error('username_unique', 'The username is taken. Do try again!' ) ) );
	echo $form->input('password');
	echo $form->input('confirm_password', array( 'type' => 'password' ) );
	echo $form->input('email');
	echo $form->end('Sign-up');
?>

The only tricky piece right now should be in the username piece. In the second parameter, I specified ‘after’ that associates with a $form->error(…). The username_unique property is something I will define in the User Model shortly.

Users Controller

Place the following code in /app/controllers/users_controller.php inside your UsersController class.

	function beforeFilter()
	{
		parent::beforeFilter();

		// This allows our login() function to execute
		$this->Auth->autoRedirect = false;
	}

	// Note, this function is called AFTER Auth has handled it, but BEFORE redirecting to the afterLogin redirect specified (because of the flag we set in beforeFilter)
	// Basically, this means the password field is already encrypted and the session was already created. Easy! =)
	function login()
	{
		// Check if Auth got a hold of it and created a session
		if( $this->Auth->user() )
		{
			// If form data was sent, set the remember_me cookie IF they checked the box
			if( isset( $this->data ) )
			{
				if( empty( $this->data['User']['remember_me'] ) || $this->data['User']['remember_me'] == 0 )
				{
					$this->RememberMe->delete();
				}
				else
				{
					$this->RememberMe->remember(
								$this->data['User']['username'],
								$this->data['User']['password'] );
				}

				$this->Session->setFlash('You are logged in!');
			}

			// Redirect to our loginRedirect page specified
			$this->redirect($this->Auth->redirect());
		}
	}

	function logout(){
		// Set logout message and call auth component's logout
		$this->Session->setFlash('You are logged out! Good bye!');

		// Delete the cookie
		$this->RememberMe->delete();

		// Call Auth to delete our session
		$this->redirect($this->Auth->logout());
	}

	function register() {
		if ( isset($this->data) )
		{
			// Set group to regular user
			//    NOTE: This may be different for you
			$this->data['User']['group_id'] = 2;

			$this->User->create();
			if ($this->User->save($this->data))
			{
				$this->Session->setFlash( 'Thank you for registering!' );
				$this->redirect(array('action'=>'index'));
			}
			else
			{
				// Make the password fields blank
				unset($this->data['User']['password']);
				unset($this->data['User']['confirm_password']);

				$this->Session->setFlash('An error occurred, try again!');
			}
		}
	}

Excellent! Now we just have one more step… let’s validate the user’s input.

The User Model

Place the following code in /app/models/user.php

<?php
class User extends AppModel {

	var $name = 'User';

	// Prevent the input from having an id
	// Username: MUST be alphanumeric
	// Password: We specify a function that returns a bool value
	var $validate = array(
		'id' => array(
							'rule' => 'blank',
							'on' => 'create'
					 ),
		'username' => array(
							'rule' => 'alphanumeric',
							'message' => 'Please enter a valid username',
							'required' => true
						),
		'password' => array(
							'rule' => array('confirmPassword', 'password'),
							'message' => 'Passwords do not match',
							'required' => 'true'
						),
		'confirm_password' => array(
							'rule' => 'alphanumeric',
							'required' => 'true'
						),
		'email' => array( 'email',
							array( 'rule' => array('email'),
									'message' => 'Please enter a valid email!' )
						),
		'group_id' => array( 'numeric' )
	);

	function confirmPassword($data)
	{
		// We must manually hash the second piece in the same way the AuthComponent would
		// if they match, return true!
		if ($data['password'] == Security::hash(Configure::read('Security.salt') . $this->data['User']['confirm_password'])) {
			return true;
		}

		// hashed passwords did NOT match
		return false;
	}

	// Check if the username already exists by doing SELECT COUNT(*) FROM users WHERE username = 'your_username'
	function beforeValidate()
	{
		if( !$this->id )
		{
			if( $this->findCount( array('User.username' => $this->data['User']['username'] ) ) > 0 )
			{
				// If any rows are found, send an error and call it 'username_unique'
				// In our view, we can check for this by doing $form->error('username_unique','Not Unique Username!!!')
				//   As specified in the view code I placed above
				$this->invalidate('username_unique');
				return false;
			}
		}
		return true;
	}

	// Associations
	var $belongsTo = 'Group';
}
?>

Great!

Conclusion

There you have it. Something that may take you places in your projects (hopefully). Any questions?



Share this post


facebooktwittergoogle_plusredditpinterestlinkedinmail

Tags:

Comments are closed.