I was just browsing through my old posts. Hmm. it looks okay. I've started newly with Cake (CakePHP), so, I'm to really learn a lot myself. Anyway, as I'm through my process of learning, I thought it would be great to keep track of what I'm actually reading to get me into the GAME quickly.
My today's task was to learn about a simple user registration system. Once again, I had to go through the CakePHP book and some other references. Instead of listing every detailed step, I would prefer to refer to those MUST read links, which just work like a CHARM in creating a User Management/Registration System using Cake.
Step: 1 Set up CakePHP Console
The console works like a charm. If you had problem in using this console in windows environment, simply, follow the step-by-step method given here.
Step: 2 Follow the CakePHP Simple ACL Control Application
This complete tutorial will guide you through the process of creating your user management system. But before going through this tutorial, please, make sure to understand basic working principles of Cake nicely. The tutorial makes full use of different Cake's core components like Acl Component & Auth Component.
Step: 3 Set custom routing
file: // app/config/routes.php
Copy paste following codes:
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/register', array('controller' => 'users', 'action' => 'register'));
This will show login form, when someone types http://caketest.local/login and likewise.
Step: 3 Create a dynamic login/logout menu
The Cakebook tutorial does not include creating a dynamic login/logout menu. So, you need to create one.
1. Create a new file.
2. Copy-paste the following code.
<?php
if(!$session->check('Auth.User')){
echo $html->link('Login','/login');
} else {
$username = $session->read('Auth.User.username');
echo " Hello ". $username ." ";
echo $html->link("(logout)", "/logout", array(), null, false);
}
?>
3. Save this file as '/app/views/elements/login_menu.ctp'
4. Open '/app/views/layouts/default.ctp'
5. Copy-paste the following code.
<?php echo $this-> element('login_menu'); ?>
6. Save this file.
Now you can see the login/logout option.
Notice I have used SESSION variables to control login/logout option. To learn more about CakePHP session, please visit this page. For a formatted output of contents inside session variables, use pr($_SESSION) - STRICTLY for DEBUG;
Step 4: Ban a user account
1.Fire the following SQL query:
ALTER TABLE `users` ADD `is_banned` TINYINT NOT NULL DEFAULT '0';
This adds a field 'is_banned' in the 'users' table. Set default values to zero.
2. Now copy-paste following code in UsersController::beforeFilter()
file:// app/controllers/users_controller.php
$this->Auth->userScope = array('User.is_banned' => 0);
3. Done. Cake will not allow users to login, when you have set 'is_banned' = 1.
Step 5: Email Validation during user registration
The code is pretty long and nicely explained here. To run with my User model (based on CakePHP's default ACL Component), I needed to make some small adjustment. So, I think it is better to give the codes intact here.
file:// app/controllers/users_controller.php
<?php
uses('sanitize');
class UsersController extends AppController {
var $name = 'Users';
var $components = array('Email','Auth');
/* "Email' component will handle emailing tasks, 'Auth' component will handle User Management */
var $helpers = array('Html', 'Form');
/* ..... member functions will go here ... */
}
function beforeFilter()
/* CakePHP CallBack methods */
function beforeFilter() {
parent::beforeFilter();
$this->Email->delivery = 'debug'; /* used to debug email message */
$this->Auth->autoRedirect = false; /* this allows us to run further checks on login() action.*/
$this->Auth->allow('register', 'thanks', 'confirm', 'logout');
$this->Auth->userScope = array('User.is_banned' => 0); /* admin can ban a user by updating `is_banned` field of users table to '1' */
}
function register()
// Allows a user to sign up for a new account
function register() {
if (!empty($this->data)) {
// Applying Auth Components's Password Hashing Rules
/*
We have commented the following field as this was double-hashing password.
$this->Auth->password($this->data['User']['passwrd']);
*/
// $this->data['User']['passwrd'] = $this->Auth->password($this->data['User']['passwrd']);
$this->User->data = Sanitize::clean($this->data);
// Successfully created account – send activation email
if ($this->User->save()) {
$this->__sendActivationEmail($this->User->getLastInsertID());
// pr($this->Session->read('Message.email')); /*Uncomment this code to view the content of email FOR DEBUG */
// this view is not show / listed – use your imagination and inform
// users that an activation email has been sent out to them.
$this->redirect('/users/thanks');
}
// Failed, clear password field
else {
$this->data['User']['passwrd'] = null;
}
}
$groups = $this->User->Group->find('list');
$this->set(compact('groups'));
}
Function login()
function login() {
// Check for incoming login request.
//pr($this->data);
if ($this->data) {
// Use the AuthComponent's login action
if ($this->Auth->login($this->data)) {
// Retrieve user data
$results = $this->User->find(array('User.username' => $this->data['User']['username']), array('User.active'), null, false);
// Check to see if the User's account isn't active
if ($results['User']['active'] == 0) {
// Uh Oh!
$this->Session->setFlash('Your account has not been activated yet!');
$this->Auth->logout();
$this->redirect('/users/login');
}
// Cool, user is active, redirect post login
else {
$this->redirect('/');
}
}
}
}
function logout()
function logout() {
$this->Session->setFlash('Good-Bye');
$this->redirect($this->Auth->logout());
}
/* function to validate activation link
*
* and to set 'active' = 1
*/
function activate()
function activate($user_id = null, $in_hash = null) {
$this->User->id = $user_id;
if ($this->User->exists() && ($in_hash == $this->User->getActivationHash())) {
if (empty($this->data)) {
$this->data = $this->User->read(null, $user_id);
// Update the active flag in the database
$this->User->set('active', 1);
$this->User->save();
$this->Session->setFlash('Your account has been activated, please log in below.');
$this->redirect('login');
}
}
// Activation failed, render '/views/user/activate.ctp' which should tell the user.
}
function __sendActivationEmail()
/* function to send activation email */
function __sendActivationEmail($user_id) {
$user = $this->User->find(array('User.id' => $user_id), array('User.email', 'User.username','User.id'), null, false);
if ($user === false) {
debug(__METHOD__." failed to retrieve User data for user.id: {$user_id}");
return false;
}
// Set data for the "view" of the Email
$this->set('activate_url', 'http://' . env('SERVER_NAME') . '/users/activate/' . $user['User']['id'] . '/' . $this->User->getActivationHash());
$this->set('username', $this->data['User']['username']);
$this->Email->to = $user['User']['email'];
$this->Email->subject = env('SERVER_NAME') . ' – Please confirm your email address';
$this->Email->from = 'noreply@' . env('SERVER_NAME');
$this->Email->template = 'user_confirm';
$this->Email->sendAs = 'text'; // you probably want to use both :)
return $this->Email->send();
}
Copy paste function getActivationHash at file:// app/models/user.php
function getActivationHash()
{
if (!isset($this->id)) {
return false;
}
return substr(Security::hash(Configure::read('Security.salt') . $this->field('created') . date('Ymd')), 0, 8);
}
Copy-paste following code in the file:// app/app_controller.php inside the function beforeFilter()
function beforeFilter() {
$this->Auth->fields = array('username' => 'username', 'password' => 'passwrd');
/* ... Rest of the function body goes here */
}
Now View Files
Registration form
file:// app/views/users/register.ctp
<h2>Create an Account</h2>
<?php
echo $form->create('User', array('action' => 'register'));
echo $form->input('username');
// Force the FormHelper to render a password field, and change the label.
echo $form->input('group_id', array('type' => 'hidden', 'value' => 'Insert-Default-Value'));
echo $form->input('passwrd', array('type' => 'password', 'label' => 'Password'));
echo $form->input('email', array('between' => 'We need to send you a confirmation email to check you are human.'));
echo $form->submit('Create Account');
echo $form->end();
?>
Notice replace 'Insert-Default-Value' with the actual value of your group_id.
Login form
file:// app/views/users/login.ctp
<?php
echo $form->create('User', array('action' => 'login'));
echo $form->input('username');
echo $form->input('passwrd', array('label' => 'Password', 'type' => 'password'));
echo $form->end('Login');
?>
user_confirm.ctp
file:// app/views/elements/email/text/user_confirm.ctp
<?php
# /app/views/elements/email/text/user_confirm.ctp
?>
Hey there <?= $username ?>, we will have you up and running in no time, but first we just need you to confirm your user account by clicking the link below:
<?= $activate_url ?>
Here are some more stuff I found helpful:
CakePHP Auth Component variables.
Understanding CakePHP Session
Saving data in CakePHP found in book.cakephp.org
Debuggable.com - this post explains how to debug CakePHP email.
My today's task was to learn about a simple user registration system. Once again, I had to go through the CakePHP book and some other references. Instead of listing every detailed step, I would prefer to refer to those MUST read links, which just work like a CHARM in creating a User Management/Registration System using Cake.
Step: 1 Set up CakePHP Console
The console works like a charm. If you had problem in using this console in windows environment, simply, follow the step-by-step method given here.
Step: 2 Follow the CakePHP Simple ACL Control Application
This complete tutorial will guide you through the process of creating your user management system. But before going through this tutorial, please, make sure to understand basic working principles of Cake nicely. The tutorial makes full use of different Cake's core components like Acl Component & Auth Component.
Step: 3 Set custom routing
file: // app/config/routes.php
Copy paste following codes:
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/register', array('controller' => 'users', 'action' => 'register'));
This will show login form, when someone types http://caketest.local/login and likewise.
Step: 3 Create a dynamic login/logout menu
The Cakebook tutorial does not include creating a dynamic login/logout menu. So, you need to create one.
1. Create a new file.
2. Copy-paste the following code.
<?php
if(!$session->check('Auth.User')){
echo $html->link('Login','/login');
} else {
$username = $session->read('Auth.User.username');
echo " Hello ". $username ." ";
echo $html->link("(logout)", "/logout", array(), null, false);
}
?>
3. Save this file as '/app/views/elements/login_menu.ctp'
4. Open '/app/views/layouts/default.ctp'
5. Copy-paste the following code.
<?php echo $this-> element('login_menu'); ?>
6. Save this file.
Now you can see the login/logout option.
Notice I have used SESSION variables to control login/logout option. To learn more about CakePHP session, please visit this page. For a formatted output of contents inside session variables, use pr($_SESSION) - STRICTLY for DEBUG;
Step 4: Ban a user account
1.Fire the following SQL query:
ALTER TABLE `users` ADD `is_banned` TINYINT NOT NULL DEFAULT '0';
This adds a field 'is_banned' in the 'users' table. Set default values to zero.
2. Now copy-paste following code in UsersController::beforeFilter()
file:// app/controllers/users_controller.php
$this->Auth->userScope = array('User.is_banned' => 0);
3. Done. Cake will not allow users to login, when you have set 'is_banned' = 1.
Step 5: Email Validation during user registration
The code is pretty long and nicely explained here. To run with my User model (based on CakePHP's default ACL Component), I needed to make some small adjustment. So, I think it is better to give the codes intact here.
file:// app/controllers/users_controller.php
<?php
uses('sanitize');
class UsersController extends AppController {
var $name = 'Users';
var $components = array('Email','Auth');
/* "Email' component will handle emailing tasks, 'Auth' component will handle User Management */
var $helpers = array('Html', 'Form');
/* ..... member functions will go here ... */
}
function beforeFilter()
/* CakePHP CallBack methods */
function beforeFilter() {
parent::beforeFilter();
$this->Email->delivery = 'debug'; /* used to debug email message */
$this->Auth->autoRedirect = false; /* this allows us to run further checks on login() action.*/
$this->Auth->allow('register', 'thanks', 'confirm', 'logout');
$this->Auth->userScope = array('User.is_banned' => 0); /* admin can ban a user by updating `is_banned` field of users table to '1' */
}
function register()
// Allows a user to sign up for a new account
function register() {
if (!empty($this->data)) {
// Applying Auth Components's Password Hashing Rules
/*
We have commented the following field as this was double-hashing password.
$this->Auth->password($this->data['User']['passwrd']);
*/
// $this->data['User']['passwrd'] = $this->Auth->password($this->data['User']['passwrd']);
$this->User->data = Sanitize::clean($this->data);
// Successfully created account – send activation email
if ($this->User->save()) {
$this->__sendActivationEmail($this->User->getLastInsertID());
// pr($this->Session->read('Message.email')); /*Uncomment this code to view the content of email FOR DEBUG */
// this view is not show / listed – use your imagination and inform
// users that an activation email has been sent out to them.
$this->redirect('/users/thanks');
}
// Failed, clear password field
else {
$this->data['User']['passwrd'] = null;
}
}
$groups = $this->User->Group->find('list');
$this->set(compact('groups'));
}
Function login()
function login() {
// Check for incoming login request.
//pr($this->data);
if ($this->data) {
// Use the AuthComponent's login action
if ($this->Auth->login($this->data)) {
// Retrieve user data
$results = $this->User->find(array('User.username' => $this->data['User']['username']), array('User.active'), null, false);
// Check to see if the User's account isn't active
if ($results['User']['active'] == 0) {
// Uh Oh!
$this->Session->setFlash('Your account has not been activated yet!');
$this->Auth->logout();
$this->redirect('/users/login');
}
// Cool, user is active, redirect post login
else {
$this->redirect('/');
}
}
}
}
function logout()
function logout() {
$this->Session->setFlash('Good-Bye');
$this->redirect($this->Auth->logout());
}
/* function to validate activation link
*
* and to set 'active' = 1
*/
function activate()
function activate($user_id = null, $in_hash = null) {
$this->User->id = $user_id;
if ($this->User->exists() && ($in_hash == $this->User->getActivationHash())) {
if (empty($this->data)) {
$this->data = $this->User->read(null, $user_id);
// Update the active flag in the database
$this->User->set('active', 1);
$this->User->save();
$this->Session->setFlash('Your account has been activated, please log in below.');
$this->redirect('login');
}
}
// Activation failed, render '/views/user/activate.ctp' which should tell the user.
}
function __sendActivationEmail()
/* function to send activation email */
function __sendActivationEmail($user_id) {
$user = $this->User->find(array('User.id' => $user_id), array('User.email', 'User.username','User.id'), null, false);
if ($user === false) {
debug(__METHOD__." failed to retrieve User data for user.id: {$user_id}");
return false;
}
// Set data for the "view" of the Email
$this->set('activate_url', 'http://' . env('SERVER_NAME') . '/users/activate/' . $user['User']['id'] . '/' . $this->User->getActivationHash());
$this->set('username', $this->data['User']['username']);
$this->Email->to = $user['User']['email'];
$this->Email->subject = env('SERVER_NAME') . ' – Please confirm your email address';
$this->Email->from = 'noreply@' . env('SERVER_NAME');
$this->Email->template = 'user_confirm';
$this->Email->sendAs = 'text'; // you probably want to use both :)
return $this->Email->send();
}
Copy paste function getActivationHash at file:// app/models/user.php
function getActivationHash()
{
if (!isset($this->id)) {
return false;
}
return substr(Security::hash(Configure::read('Security.salt') . $this->field('created') . date('Ymd')), 0, 8);
}
Copy-paste following code in the file:// app/app_controller.php inside the function beforeFilter()
function beforeFilter() {
$this->Auth->fields = array('username' => 'username', 'password' => 'passwrd');
/* ... Rest of the function body goes here */
}
Now View Files
Registration form
file:// app/views/users/register.ctp
<h2>Create an Account</h2>
<?php
echo $form->create('User', array('action' => 'register'));
echo $form->input('username');
// Force the FormHelper to render a password field, and change the label.
echo $form->input('group_id', array('type' => 'hidden', 'value' => 'Insert-Default-Value'));
echo $form->input('passwrd', array('type' => 'password', 'label' => 'Password'));
echo $form->input('email', array('between' => 'We need to send you a confirmation email to check you are human.'));
echo $form->submit('Create Account');
echo $form->end();
?>
Notice replace 'Insert-Default-Value' with the actual value of your group_id.
Login form
file:// app/views/users/login.ctp
<?php
echo $form->create('User', array('action' => 'login'));
echo $form->input('username');
echo $form->input('passwrd', array('label' => 'Password', 'type' => 'password'));
echo $form->end('Login');
?>
user_confirm.ctp
file:// app/views/elements/email/text/user_confirm.ctp
<?php
# /app/views/elements/email/text/user_confirm.ctp
?>
Hey there <?= $username ?>, we will have you up and running in no time, but first we just need you to confirm your user account by clicking the link below:
<?= $activate_url ?>
With all the above scripts, you should be able to get a workable user registration system.
Here, you will have groups/ users/ and you can set group level access per controller, even per action following Cake's default mechanism!
[Acknowledgements]
My sincere regards to Jonny Revees for his wonderful work on this CakePHP user registration system. It works like a charm!
Here are some more stuff I found helpful:
CakePHP Auth Component variables.
Understanding CakePHP Session
Saving data in CakePHP found in book.cakephp.org
Debuggable.com - this post explains how to debug CakePHP email.
No comments:
Post a Comment