Last week, we covered the basic structure of a CodeIgniter application. Let’s now jump right into developing a simple todo list application using CodeIgniter. We will be keeping the actual functionality of the application itself simple here, as the goal here is to give a good overview on what it takes to build a CI application from scratch.
Okay, the first thing you have to do is to download and extract the latest build of CodeIgniter. Next, download the controllers, models and views that I have used in this sample todo list application. You should refer to these files as you read the tutorial. Here is the demo of the sample application (use “demo” as username and password).
Directory structure
All the files related to our application will be placed in the "system/application" folder:
As you can see, we have to place our controllers, views and models in their correspondng /controllers, /views and /models directories. Initially, we will have a sample controller (Welcome) in the /controllers directory, and its corresponding Welcome view in the /views directory. The model directory will be empty.
The /config directory consists of various files which will help us fine-tune the CI framework to our development environment. We will ignore the other directories in the /application directory for the time being.
Some basic configuration first
We need to modify some of the configuration files in the /config folder to set up the framework:
To remove this, we can optionally place a .htaccess file in your CI root folder with the following content:
CodeIgniter session class
Before we go further, let’s have a brief review of CodeIgniter’s sessions class, which will be using in this application to keep track of the user’s session. CI’s session class can handle user session data stored using either cookies or in a database. CodeIgniter’s session class does not utilize native PHP sessions. To make use of the session class in our application, we must either initialize it in a controller’s constructor, or we have to auto-load it so that it will run in the background, and will be available for us across the entire system. To load the session class manually in the controller’s constructor, we do that by calling:
Reading and writing data to the session class is a breeze! To write data to a user’s session, we simply do:
With that, out of the way, let’s get started. Our to-do-list application will have the following "features":
Given the rather simple nature of our application, it’s not too difficult to identify what database tables we will be needing upfront. We will need two tables:
Here is a breakdown of all the controllers, views and model we will be needing for this application. I will explain the purpose of each of them, as we go about tackling them.
The login controller
The login controller first checks whether the user is already logged in – in which case, we simply redirect him to the dashboard. This, we do by checking whether the "logged_in" field exists in the user’s session data. We are using CI’s session class for this:
On the other hand, if its is a login form submission, we first retrieve the username and password variable from the POST request. We then load the Users_model class, and use its validate() function to authenticate the user. If the user’s username and password match, his user_id field from the database is returned. Else, a -1 is returned. For a valid user, we initialise his session by:
The Dashboard
The welcome controller is the default controller for CodeIgniter. It will already be found in the /application/controllers directory, and this is the controller that will be called when you access our application’s URL directly without using any URL segments, as discussed in the previous article. Let us just make use of this controller for our application’s dashboard. Assuming the user has already logged in successfully, let’s build our application’s dashboard – the page the visitor first sees after logging in. In our case, it will be a page which will display a set of to-do items, and in addition, provide a way to enter a new to-do item or modify the done/not-done status of any existing item using AJAX. Here is the index() function of the welcome controller.
dashboard_view.php links to an external stylesheet (todoapp.css) and a JavaScript file (todoapp.js). The AJAX functionality is defined in the JavaScript file. In our application, we are using AJAX to add a new todo item to the list, and also update the done/not-done status of any of the todo items. The function addNewItem() in the JavaScript file is bound to the click event of the "Add" button.
The addNewItem() function, when fired, makes an AJAX POST request to the "add" controller which will handle the addition of a new todo item. The add controller will return the ID field of the newly added todo item in the database. If the operation is a success (if the ID returned in not -1), we simply append the new todo item (along with a checkbox) to the bottom of the existing items. We also clear the text in the textfield.
The updateItem() function is bound to the click event on each of the checkboxes. When fired, it checks whether the checkbox that the user clicked is selected or not, and it sends this information to the "update" controller.
The add controller
In all the controllers, we will have to first check if the user is logged in, before we carry out any action. For a valid user, we retrieve the text of the new todo item to be added (from the POST variable sent to the script) using:
What the update controller does is similar to the add controller and also fairly straight forward. It simply retrieves the POST variables sent to it (the ID of the item which is to be updated, and its updated status). The update controller then loads the Items_model and invokes the update_item() function to peform the update.
The logout controller
The logout controller destroys the session data of the user, and then redirects him to the login page once again.
Finally, let’s get to the user registration, which is handled by The Register controller. First off, I should mention here that for the sake of simplicity, I have implemented a very simple registration form, with absolutely no spam control!
The Register controller is similar to the Login controller in that – it again serves both the purposes of rendering the registration form, and as well as handling the form submission. The register_view simply asks the user to pick a username and password. The <form>’s action attribute points to the URL of the register controller.
When the form is submitted, the Register controller first checks to see that both the username and password fields are not empty. It then loads the "Users_model" which handles all database operations concerned with the "Users" table. We will invoke the is_valid_username() of the Users_model to see whether the username that the user has chosen already exists (the function returns a -1 if no such username is found on the system). If it a username is indeed found (in which case the function will return the ID of the user), we will initialise a $message variable with the text "That username already exists." and load the register view again, by passing the $message variable for rendering.
With that, we come to the end of this second part of CodeIgniter tutorial.
Okay, the first thing you have to do is to download and extract the latest build of CodeIgniter. Next, download the controllers, models and views that I have used in this sample todo list application. You should refer to these files as you read the tutorial. Here is the demo of the sample application (use “demo” as username and password).
Directory structure
All the files related to our application will be placed in the "system/application" folder:
As you can see, we have to place our controllers, views and models in their correspondng /controllers, /views and /models directories. Initially, we will have a sample controller (Welcome) in the /controllers directory, and its corresponding Welcome view in the /views directory. The model directory will be empty.
The /config directory consists of various files which will help us fine-tune the CI framework to our development environment. We will ignore the other directories in the /application directory for the time being.
Some basic configuration first
We need to modify some of the configuration files in the /config folder to set up the framework:
- database.php – this is where we will be filling up our database connectivity details. The file has ample comments to help you fill in all the necessary details correctly!
- config.php – we have to fill in the path to our CI root folder here in the variable: $config['base_url']
- autoload.php – this file allows us to autoload any libraries or helpers that CodeIgniter provides us so that they are available across the entire system. We will be using the session library and the url helper class, so initialise the $autoload['libraries'] and $autoload['helper'] variables to:
- $autoload['libraries'] = array(‘database’,'session’);
- $autoload['helper'] = array(‘url’);
To remove this, we can optionally place a .htaccess file in your CI root folder with the following content:
RewriteEngine on RewriteCond $1 !^(index\.php|images|css|scripts|robots\.txt) RewriteRule ^(.*)$ index.php/$1 [L]With the above rule in place, all requests other than those for index.php, images, css, scripts and robots.txt are treated as a request for your index.php file.
CodeIgniter session class
Before we go further, let’s have a brief review of CodeIgniter’s sessions class, which will be using in this application to keep track of the user’s session. CI’s session class can handle user session data stored using either cookies or in a database. CodeIgniter’s session class does not utilize native PHP sessions. To make use of the session class in our application, we must either initialize it in a controller’s constructor, or we have to auto-load it so that it will run in the background, and will be available for us across the entire system. To load the session class manually in the controller’s constructor, we do that by calling:
$this->load->library('session');To auto-load the session class, we have to open the file "application/config/autoload.php" and add the item to the "autoload" array as I have mentioned in configuration step above.
Reading and writing data to the session class is a breeze! To write data to a user’s session, we simply do:
$this->session->set_userdata('some_variable', 'some_value');And, to retrieve the data again, we just call:
$item = $this->session->userdata('item');Apart from that, CI’s session class by default, provides us with the following information:
- user’s unique Session ID
- user’s IP Address
- user’s User Agent data (the first 50 characters of the browser data string)
- user’s "last activity" time stamp
With that, out of the way, let’s get started. Our to-do-list application will have the following "features":
- a simple user sign up and login system
- session management using CI’s session class
- a single to-do list which allows multiple users to add and delete items using AJAX
Given the rather simple nature of our application, it’s not too difficult to identify what database tables we will be needing upfront. We will need two tables:
- users : stores the user id, username and the hashed password.
- items : stores the to-do list items and their attributes like item_id, user_id (ID of the user who created it)
CREATE TABLE IF NOT EXISTS `items` ( `item_id` bigint(20) NOT NULL auto_increment, `user_id` bigint(20) NOT NULL, `item_text` varchar(255) NOT NULL, `is_done` int(11) NOT NULL, PRIMARY KEY (`item_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `users` ( `user_id` bigint(20) NOT NULL auto_increment, `username` varchar(100) NOT NULL, `password` varchar(100) NOT NULL, PRIMARY KEY (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;Setting up the above tables in the database which you have mentioned in your database.php configuration file above.
Here is a breakdown of all the controllers, views and model we will be needing for this application. I will explain the purpose of each of them, as we go about tackling them.
The login controller
The login controller first checks whether the user is already logged in – in which case, we simply redirect him to the dashboard. This, we do by checking whether the "logged_in" field exists in the user’s session data. We are using CI’s session class for this:
if( $this->session->userdata('logged_in') ) // user already logged in { header("Location: " . base_url() . "index.php" ); die(); }The login controller serves two needs:
- render the login form initially for a user who wants to sign in to the system
- when the user submits the login form, authenticate the user and either redirect him to the dashboard or show an error message
if( $this->input->post('login') ) { // treat this as a login form submission } else { // render the login form }If it’s NOT a login form submission, we simply load the login_view defined in application/views/login_view.php. This file will render the login form.
On the other hand, if its is a login form submission, we first retrieve the username and password variable from the POST request. We then load the Users_model class, and use its validate() function to authenticate the user. If the user’s username and password match, his user_id field from the database is returned. Else, a -1 is returned. For a valid user, we initialise his session by:
$newdata = array( 'user_id' => $user_id, 'username' => $username, 'logged_in' => TRUE ); $this->session->set_userdata($newdata);We then redirect him to the dashboard. If the username and password provided do not match, we load the login_view by passing a variable ‘$message’ that contains the error to be displayed.
The Dashboard
The welcome controller is the default controller for CodeIgniter. It will already be found in the /application/controllers directory, and this is the controller that will be called when you access our application’s URL directly without using any URL segments, as discussed in the previous article. Let us just make use of this controller for our application’s dashboard. Assuming the user has already logged in successfully, let’s build our application’s dashboard – the page the visitor first sees after logging in. In our case, it will be a page which will display a set of to-do items, and in addition, provide a way to enter a new to-do item or modify the done/not-done status of any existing item using AJAX. Here is the index() function of the welcome controller.
function index() { if( !$this->session->userdata('logged_in') ) // user NOT logged in { header("Location: " . base_url() . "index.php/login" ); die(); } $this->load->model('items_model','items'); $data['all_items'] = $this->items->fetch_all_items
($this->session->userdata('user_id'));
$this->load->view('dashboard_view',$data); }The welcome controller will check whether the user is logged in (using the session data set earlier in the login controller). If the user is not logged in, or his session has expired, we will redirect him to the login page. The base_url() function belongs to the URL helper that we autoloaded in our configuration, and it returns the base URL of our application (including the "/" at the end of the URL). Otherwise, we will load the Items_model class which will be used to interact with the items table in the database. The fetch_all_items() function of the item_model class will fetch all the todo items of this particular logged in user from the "items" table. The only other thing to note here is that we are using the session class to retrieve the user id of the user that we have stored as session data when the user successfully logs in to the system.
function fetch_all_items($user_id) { // fetch the to-do items of the user
identified by $user_id:
$query = $this->db->query("SELECT * FROM items
WHERE user_id = $user_id"); return $query->result(); }
The index() function of the Welcome controller then loads the view "dashboard_view", defined in "dashboard_view.php" in the system/application/views directory. When the view is loaded, we are passing to it the todo items we fetched from the database using the Items_model class. The view then renders all the to-do items on the page.
dashboard_view.php links to an external stylesheet (todoapp.css) and a JavaScript file (todoapp.js). The AJAX functionality is defined in the JavaScript file. In our application, we are using AJAX to add a new todo item to the list, and also update the done/not-done status of any of the todo items. The function addNewItem() in the JavaScript file is bound to the click event of the "Add" button.
The addNewItem() function, when fired, makes an AJAX POST request to the "add" controller which will handle the addition of a new todo item. The add controller will return the ID field of the newly added todo item in the database. If the operation is a success (if the ID returned in not -1), we simply append the new todo item (along with a checkbox) to the bottom of the existing items. We also clear the text in the textfield.
The updateItem() function is bound to the click event on each of the checkboxes. When fired, it checks whether the checkbox that the user clicked is selected or not, and it sends this information to the "update" controller.
The add controller
In all the controllers, we will have to first check if the user is logged in, before we carry out any action. For a valid user, we retrieve the text of the new todo item to be added (from the POST variable sent to the script) using:
$this->input->post('item_text',TRUE)The second parameter is set ‘TRUE’ to indicate that the input must be filtered to negate XSS (cross site scripting) attempts. XSS is a major problem faced by many web applications, and as a golden rule, any input which might potentially get rendered on the front end must be passed through an XSS filter that escapes/strips out the dangerous elements. As an added precaution we also check whether the todo item’s text is not empty, and if all is clear, we load the "Items_model" class once again, and call the add_item() function to add the todo item to the database. The add_item() function uses another handy function that CI provides, to escape the data by adding single quotes around the data:
$item_text = $this->db->escape($item_text);The update controller
What the update controller does is similar to the add controller and also fairly straight forward. It simply retrieves the POST variables sent to it (the ID of the item which is to be updated, and its updated status). The update controller then loads the Items_model and invokes the update_item() function to peform the update.
The logout controller
The logout controller destroys the session data of the user, and then redirects him to the login page once again.
$this->session->sess_destroy(); header("Location: " . base_url() . "index.php/login" );User registration
Finally, let’s get to the user registration, which is handled by The Register controller. First off, I should mention here that for the sake of simplicity, I have implemented a very simple registration form, with absolutely no spam control!
The Register controller is similar to the Login controller in that – it again serves both the purposes of rendering the registration form, and as well as handling the form submission. The register_view simply asks the user to pick a username and password. The <form>’s action attribute points to the URL of the register controller.
When the form is submitted, the Register controller first checks to see that both the username and password fields are not empty. It then loads the "Users_model" which handles all database operations concerned with the "Users" table. We will invoke the is_valid_username() of the Users_model to see whether the username that the user has chosen already exists (the function returns a -1 if no such username is found on the system). If it a username is indeed found (in which case the function will return the ID of the user), we will initialise a $message variable with the text "That username already exists." and load the register view again, by passing the $message variable for rendering.
if( $this->users->is_valid_username($this->db->escape($username))
!= -1 )
{
// username already exists
$data['message'] = "That username already exists."; } ... $this->load->view('register_view', $data);
If the user has chosen a non-existing username, then we go ahead and add the user to the database by calling the Users_model’s add_user() function, by passing the username and his hashed password. We are simply using a plain SHA1 hash here to store the password (which is again considered not secure enough without salting, but enough for our simple application). Once the user is added to the MySQL database, we use the nifty "mysql_insert_id()" PHP function to retrieve the auto increment ID field of the user row just added to the "users" table. After a successful account creation, we initialise the user’s session and redirect him to the dashboard, so the user can start using the application right away.
With that, we come to the end of this second part of CodeIgniter tutorial.
No comments:
Post a Comment