What will we learn in this episode
In this episode we will learn about setting the CodeIgniter framework to work with sessions and importing the necessary files of the Ion Auth library and create the login form.
Setting up CodeIgniter to work with sessions
Just to make sure everything is OK, we will start by having a fresh install of CodeIgniter. We will install it directly inside the htdocs or www (assuming you have XAMMP installed or some other kind of wamp or lamp stack installed). This way we can access the site by typing : “http://localhost/” in our browser. If you already installed sessions correctly, you can skip this step.
OK. We’ve downloaded the CodeIgniter, we’ve removed the index.php from the URLs, and we’ve done the final settings for our framework. Now it’s time to enable the sessions.
We will use the database driver for keeping the session data. In order to do this we will go to our config file (application/config/config.php) and look for the following lines (more or less…):
$config['sess_driver'] = 'files'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_save_path'] = NULL; $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE;
In here we need to change the “sess_driver” value and the “sess_save_path”. The “sess_driver” value should be set to database, while the “sess_save_path” should have the name of the table used for sessions. If we read the great manual of CodeIgniter we will see what values we should put in there:
$config['sess_driver'] = 'database'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_save_path'] = 'ci_sessions'; $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE;
Now, let’s go to our autoload.php (application/config/autoload.php) and autoload the session library. Look for the line:
$autoload['libraries'] = array();
…and add session as an element of the array:
$autoload['libraries'] = array('session');
While we’re here, let’s also activate the url helper:
$autoload['helper'] = array('url');
If now we visit our website from the browser we will see that an error has appeared:
Why? Because we’ve promised the framework a table to keep our session data, but we didn’t create that specific table. So let’s create that table. Do you have a database set up for your website? If not, follow this tutorial on how to set up a database.
Returning to our sessions, in order to use them we need to create a table named ci_sessions. The table structure is also presented in the fine manual of CodeIgniter:
CREATE TABLE IF NOT EXISTS `ci_sessions` ( `id` varchar(40) NOT NULL, `ip_address` varchar(45) NOT NULL, `timestamp` int(10) unsigned DEFAULT 0 NOT NULL, `data` blob NOT NULL, KEY `ci_sessions_timestamp` (`timestamp`) );
The one above is an sql command. You can simply copy it and paste it using PHPMyAdmin’s interface. I sure hope you know how to create a table in MySQL…
Now, after we’ve created the table, if we again visit our homepage from our browser we should be greeted by the CodeIgniter.
Great… We finished setting up the sessions. Now to the Ion Auth library.
Installing Ion Auth
In order to install Ion Auth we first need to… download it. We do this from it’s Github repository: https://github.com/benedmunds/CodeIgniter-Ion-Auth.
Once we’ve downloaded it, we only need to copy/paste some files:
config/ion_auth.php
We need to put this file inside our application/config directory.
language/english/ion_auth_lang.php
We need to put this in our application/language/english directory. If you’ve set another language for your application inside the config.php file, you should copy that language in the appropriate language directory.
libraries/Ion_auth.php and libraries/Bcrypt.php
We should copy these too, inside application/libraries directory.
models/ion_auth_model.php
Copy this file inside the application/models directory. Make sure you copy it by renaming the file so that it starts with upper-case letter: Ion_auth_model.php
Once we did all the copy/pasting we need to set up the tables needed for Ion Auth to work. In order to do this look for a directory named “sql” inside the library’s zip archive. In there we will find an sql command for creating the tables necessary for the library: ion_auth.sql.
Configuring the Ion Auth library
Now that we’ve imported the files and created the tables, we need to configure the library. To do this, we go to our application/config/ion_auth.php.
What should we change here?
We can change $config[‘site_title’], the $config[‘admin_email’] (preferably with a valid email).
Now the important parts.
Identity
Identity is simply asking you what should be used as identity when someone logs in. Some people prefer to use an username, other people prefer email, other people prefer some other type of uniquely identifying value like social security number, badge number, etc. If for example you want to use a social security number in order to identify the users, you should create another field in the “users” table, let’s say “security_number”. Once you’ve done this, you should also change the $config[‘identity’] = ‘security_number’.
For this tutorial we will use username as identity column: $config[‘identity’] = ‘username’.
Email activation
You want Ion Auth to send an email activation code to make sure that the user wants to create the account? Then set this to true.
Manual activation
You want only administrators to activate accounts? Then set this to true.
Remember users
You want to use a “Remember me” on your login form? Set this to true.
Track login attempts
If you want to make sure that on failed login the authentication system remembers how many failed logins have been on a particular account, you should set $config[‘track_login_attempts’] to true. If you set this to true, you should also take a look at $config[‘maximum_login_attempts’] which will lock out an account if the maximum of login attempts has been reached. The lockout period is stated in the $config[‘lockout_time’] (in seconds). That means that after the maximum login attempts has been reached the user is allowed to try one more time every 600 seconds.
Use CI email
As a personal preference I would set $config[‘use_ci_email’] to true;
For now, everything else seems ok.
Create the User controller
We will create a bare-bone controller named User.php inside application/controllers. As you will see, we will load the Ion Auth library inside the constructor in order to use its methods:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class User extends MY_Controller { function __construct() { parent::__construct(); $this->load->library('ion_auth'); } public function index() { $this->load->view('welcome_message'); } public function login() { echo 'Here we will make the login form'; } public function logout() { echo 'here we will do the logout'; } }
We will also need to create a controller that will be accessible only to those users that are logged in. So let’s create a Dashboard.php file inside our application/controllers. This will extend a controller named Auth_Controller:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Dashboard extends Auth_Controller { public function index() { echo 'Hello from the dashboard'; } }
The Auth_Controller that we will create soon will be verifying if the users are logged in. If they aren’t, they will be redirected to the login() method of the User controller.
Creating the MY_Controller and the Auth_Controller
I really like the way I’ve wrote the MY_Controller in my previous tutorials. So we will do this again. Let’s create a MY_Controller.php file inside application/core:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Controller extends CI_Controller { protected $data = array(); function __construct() { parent::__construct(); $this->data['page_title'] = 'CI App'; $this->data['page_description'] = 'CI_App'; $this->data['before_closing_head'] = ''; $this->data['before_closing_body'] = ''; } protected function render($the_view = NULL, $template = 'public_master') { if($template == 'json' || $this->input->is_ajax_request()) { header('Content-Type: application/json'); echo json_encode($this->data); } elseif(is_null($template)) { $this->load->view($the_view,$this->data); } else { $this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view, $this->data, TRUE); $this->load->view('templates/' . $template . '_view', $this->data); } } }
What we’ve done here is some basic templating for our pages. Also we’ve passed some default data that will be passed to the views like the page title and the page description. Now, if some controller extends the MY_Controller, he will pass the data to the views by using $this->data[‘variable_name’], and will render the page by calling $this->render(‘the_view’). Simple enough.
Now we will need to create the Auth_Controller. We will create the class in the same MY_Controller.php file, just after the definition of the MY_Controller class.
class Auth_Controller extends MY_Controller { function __construct() { parent::__construct(); $this->load->library('ion_auth'); if($this->ion_auth->logged_in()===FALSE) { redirect('user/login'); } } protected function render($the_view = NULL, $template = 'auth_master') { parent::render($the_view, $template); } }
As you can see, Auth_Controller will take over the data from the MY_Controller. Also, you may observe the fact that inside the constructor, the class verifies that the user is logged in by using the Ion Auth method logged_in() (more on this method can be found here: http://benedmunds.com/ion_auth/#logged_in). If the user is not logged in, he is redirected to the user/login page.
Now let’s visit the dashboard (“http://localhost/dashboard”). If everything went ok we should be automatically redirected to the “login form”… or at least to what will be holding the login form.
Cool… So far so good.
Creating the basic template views
But how do we create the login form? As you can see from our MY_Controller, we created some render() method that will create the views. Also, the default template is named “public_master_view” and is called from the application/views/templates directory. So let’s create one.
We will save a public_master_view.php file inside views/templates directory (which we will create…). The public master view will simply call a public header view and a public footer view from templates/parts directory:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $this->load->view('templates/_parts/public_master_header_view'); ?> <?php echo $the_view_content;?> <?php $this->load->view('templates/_parts/public_master_footer_view');?>
Now we will create the public_master_header_view.php inside application/views/templates/_parts directory:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title><?php echo $page_title;?></title> <meta name="description" value="<?php echo $page_description;?>" /> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <?php echo $before_closing_head;?> </head> <body>
…and the public_master_footer_view.php inside the same application/views/templates/_parts directory:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <footer> <div class="container"> <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </div> </footer> <?php echo $before_closing_body;?> </body> </html>
We also need to create the template views for the authenticated users. So simply duplicate auth_master_view.php and replace the names of the header and footer views with auth_master_header_view.php and respectively auth_master_footer_view.php.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $this->load->view('templates/_parts/auth_master_header_view'); ?> <?php echo $the_view_content;?> <?php $this->load->view('templates/_parts/auth_master_footer_view');?>
Also, duplicate the template header view and template footer view in templates/_parts changing the names accordingly to auth_master_header_view.php and auth_master_footer_view.php.
! YOU MIGHT CRY: “Why all this??? I only wanted to implement Ion Auth… Not all this templating stuff. But it is my opinion that you need to have a good start when working on a project. Some sort of good practice (“good practice” as I view it…).
Cool… We’re done.
Now let’s see if it all works. Inside the User.php we created a login() method. Let’s change it so that it will use the render() method we’ve defined in the MY_Controller.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class User extends MY_Controller { function __construct() { parent::__construct(); $this->load->library('ion_auth'); } public function index() { $this->load->view('welcome_message'); } public function login() { $this->data['message'] = 'here will be the login form'; $this->render('user/login_view'); } public function logout() { echo 'here we will do the logout'; } }
Now we need to create the view that will output that message. So we will create a login_view.php inside application/views/user directory. Why a user directory? It’s best to have views organised by the controllers names (in my opinion…). This way you will find them faster.
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <div class="container"> <?php echo $message;?> </div>
Now, if we visit the same page on our browser we will see that the header and footer was added to our page. Cool. Let’s work on our login() method now…
The login() method
The login method will use Ion Auth methods that will try to log the users and redirect them to the dashboard page.
As I said, we will use “username” as main identity column and the password.
We should first set our form validation rules. For this we will use the native form validation library.
$this->load->library('form_validation'); $this->form_validation->set_rules('username', 'Username', 'trim|required'); $this->form_validation->set_rules('password', 'Password', 'trim|required');
Once we’ve done this, we verify if the form passed validation. If it didn’t, we render the login view:
if ($this->form_validation->run() === FALSE) { $this->render('user/login_view'); }
If the validation was successful we will use the data coming from our form in order to log in the user by using the login() method of Ion Auth library:
else { $remember = (bool) $this->input->post('remember'); $username = $this->input->post('username'); $password = $this->input->post('password'); if ($this->ion_auth->login($username, $password, $remember)) { redirect('dashboard'); } else { $_SESSION['auth_message'] = $this->ion_auth->errors(); $this->session->mark_as_flash('auth_message'); redirect('user/login'); } }
Let’s see the User controller again:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class User extends MY_Controller { function __construct() { parent::__construct(); $this->load->library('ion_auth'); } public function index() { $this->load->view('welcome_message'); } public function login() { $this->data['title'] = "Login"; $this->load->library('form_validation'); $this->form_validation->set_rules('username', 'Username', 'trim|required'); $this->form_validation->set_rules('password', 'Password', 'required'); if ($this->form_validation->run() === FALSE) { $this->load->helper('form'); $this->render('user/login_view'); } else { $remember = (bool) $this->input->post('remember'); if ($this->ion_auth->login($this->input->post('username'), $this->input->post('password'), $remember)) { redirect('dashboard'); } else { $_SESSION['auth_message'] = $this->ion_auth->errors(); $this->session->mark_as_flash('auth_message'); redirect('user/login'); } } } public function logout() { echo 'here we will do the logout'; } }
Now let’s modify the login_view.php so that it will have the form. As you can see, inside the login() method we already loaded the native form helper before calling the render() method.
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <div class="container"> <h1>Login in</h1> <?php echo form_open(); echo form_label('Username:','username').'<br />'; echo form_error('username'); echo form_input('username').'<br />'; echo form_label('Password:', 'password').'<br />'; echo form_error('password'); echo form_password('password').'<br />'; echo form_checkbox('remember','1',FALSE).' Remember me<br />'; echo form_submit('submit','Log In'); echo form_close(); ?> </div>
As you can see… no css styling… I will leave this to you… But for now, let’s log in. WAIT!!! What username and password should we use to log in? Well… Ion Auth has a default username and password to get us started:
Username: administrator
Password: password
Keep in mind that you should change these credentials… on another episode of my series…
Now, if we log in with these credentials we should be taken to the dashboard. But what if we’ve tried to log in with wrong credentials? How would we know with no warning on our login form? If you look back to our login() method we created a session variable named ‘auth_message’ in case the login credetials were bad or some sort of error took place. So why not output this session variable just before the login form. Let’s see the login_view again:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <div class="container"> <?php echo isset($_SESSION['auth_message']) ? $_SESSION['auth_message'] : FALSE; ?> <h1>Login in</h1> <?php echo form_open(); echo form_label('Username:','username').'<br />'; echo form_error('username'); echo form_input('username').'<br />'; echo form_label('Password:', 'password').'<br />'; echo form_error('password'); echo form_password('password').'<br />'; echo form_checkbox('remember','1',FALSE).' Remember me<br />'; echo form_submit('submit','Log In'); echo form_close(); ?> </div>
Cool.
The logout() method
Let’s log out. How we do this? We change the logout() method of our User controller:
public function logout() { $this->ion_auth->logout(); redirect('user/login'); }
Yes… it’s that simple…
Now let’s add a link to the logout() method on all the pages that belong to the authenticated pages? That means we go to our templates/_parts/auth_master_header_view.php and add a link there.
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title><?php echo $page_title;?></title> <meta name="description" value="<?php echo $page_description;?>" /> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <?php echo $before_closing_head;?> </head> <body> <div class="container"><?php echo anchor('user/logout', 'Logout');?></div>
Now… we go to our index() method of our Dashboard controller and move the message in a view which will be called by the render() method.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Dashboard extends Auth_Controller { public function index() { $this->render('dashboard/index_view'); } }
And we create an index_view.php inside application/views/dashboard directory:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <div class="container">Hello from dashboard...</div>
And that’s it… In the next tutorial we will create a registration form.
THUMBS UP
Very Clear and easy to follow