Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

September 02 2013

06:30

Ionize CMS: Multilingual Developers Dreams Come True


  

Moving on with our series of CMS reviews, today we will be focusing on another developer-friendly Content Management System: Ionize CMS. Ionize CMS is a flexible open source CMS, that uses PhpStorm and CodeIgniter. Managed by Studio Partikule of France, it has its own module engine and can be used to power a wide plethora of websites. Also, Ionize CMS is equipped with the very liberal MIT license.

August 27 2013

01:28

Building a CodeIgniter Web Application From Scratch – Part 1

In this series we’re going to build a web billboard application from scratch, we’re going to use CodeIgniter to handle the back-end service and BackboneJS for the web client. In the first two parts of the series we’ll create the back-end service and then the client application in the last two.


Application Description

The application we are creating will be a simple billboard, where users can register, post tasks, and offer a reward for its completion. Other users can see the existing tasks, assign the task to themselves, and get the offered reward.

The tasks will have basic data like a title, description and reward (as required parameters) and an optional due date and notes. The user profile will simply consist of the user’s name, email and website. So let’s get started.


Database Setup

First off, for the app data we’re going to use MongoDB as the database server. MongoDB is a document oriented database and the leading NoSQL database out there. It’s really scalable and fast, which makes it great to manage huge amounts of data.

MongoDB is a document oriented database and the leading NoSQL database.

In order to use MongoDB in this application, I’m going to use a MongoDB CodeIgniter driver that I wrote some time ago, it’s just a wrapper of the MongoDB PHP driver to mimic the framework’s SQL ActiveRecord. You can find the source files for this driver in my public repository. For this driver to work properly, make sure that you have the PHP’s MongoDB driver installed, if you don’t, follow these steps to get it working.

Please note that explaining the drivers in CodeIgniter and such is out of the scope of this tutorial, refer to the documentation if you have any doubts. You just need to move the "mongo_db.php" in the "config" folder to the "config" folder of your application and the "Mongo_db" folder in the "libraries" folder to the "libraries" folder in your application.

Database Configuration

The only file we need to edit at this point is the "mongo_db.php" file under the "config" folder, since my mongo installation has all the default parameters, I’m just going to edit line 40 and give it the name of the database that I want to use:

$config['mongo_db'] = 'billboard';

That’s it for the database, one of the many advantages of MongoDB is that the documents have no predefined structure, so it works without us needing to set anything up before using it, our database doesn’t even have to exist, MongoDB will create it on the fly when we need it.


Global Configuration

Other than your regular configuration options, that should include the base_url and the index_page if any, we need to set the string and date helpers to autoload. I’m not going to walk you through this, since we have much more to cover, when in doubt refer to the documentation.

Other than the helpers, we need to set up the encryption class since we’re going to use it for our app.


URL Handling

This is going to be a RESTful service and we need a way to take the requests coming to the server and handle them accordingly. We could use an existing library (which is great by the way) but for the purposes of this demonstration, I’m going to create the functionality I need using CodeIgniter’s core features.

Handling RESTful Requests

In particular, we’re going to use the ability to extend the core classes. We will start with the Controller, for the main part of this extension we’re using the "_remap" method in the base controller so all the controllers of our app can use it. Start by creating a MY_Controller.php file inside the "core" folder in the "application" folder, we create this just like any other CodeIgniter controller, as follows:

<?php
if( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

class MY_Controller extends CI_Controller {

}

Now in this controller we’re going to use the CodeIgniter _remap method to preprocess every request made to the server. Inside the class we just created, add the following method:

public function _remap( $param ) {
    $request = $_SERVER['REQUEST_METHOD'];

    switch( strtoupper( $request ) ) {
        case 'GET':
            $method = 'read';
            break;
        case 'POST':
            $method = 'save';
            break;
        case 'PUT':
            $method = 'update';
            break;
        case 'DELETE':
            $method = 'remove';
            break;
        case 'OPTIONS':
            $method = '_options';
            break;
    }

    $this->$method( $id );
}

A couple of things to note here, first off, there are some REST verbs that we are ignoring (like PATCH), since I’m demonstrating building a REST app, I don’t want to add things that may make this more complex than it needs to be. Secondly, we’re not taking into account the case where a controller doesn’t implement a particular method, which is very likely that this could happen. Now, we could add a default method to handle such requests, but so that we don’t add too much complexity, let’s leave it like this. Third, we’re receiving a param variable in the method declaration, let’s address that, and then I’ll explain the OPTIONS request. Above the switch statement, add the following code:

if ( preg_match( "/^(?=.*[a-zA-Z])(?=.*[0-9])/", $param ) ) {
    $id = $param;
} else {
    $id = null;
}

This regular expression matches any string consisting of uppercase and lowercase letters and any numbers. This is used to check if a MongoDB _id string is being given as a parameter, again, this is not the safest way nor the most thorough check, but for the sake of simplicity, we’ll keep it as is.

OPTIONS Request

Since we’re building a web service and a client application as separate parts, it makes sense that both are going to be hosted on different domains, so we will enable CORS in the back-end and this means, among other things, that our app will respond properly to OPTIONS requests.

When a web app created with BackboneJS (and some other frameworks) tries to make an asynchronous request to a remote server, it sends an OPTIONS request before sending the actual request it’s supposed to send. Among other things, the client tells the server from where it is sending the request, what type of request it is about to send, and the content that it’s expecting. After that, it is up to the server to send the client a response where it acknowledges the request or rejects it.

Since our back-end service, no matter which controller is called, is going to receive this OPTIONS request, it makes sense to implement the method to respond to it in our base controller. Add the following method below (or above) the _remap method in our controller.

private function _options() {
    $this->output->set_header( 'Access-Control-Allow-Origin: *' );
    $this->output->set_header( "Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS" );
    $this->output->set_header( 'Access-Control-Allow-Headers: content-type' );
    $this->output->set_content_type( 'application/json' );
    $this->output->set_output( "*" );
}

Ideally, we would only allow some domains to make requests to us, we would check the request_headers header to see if we accept it and we would check for the expected content type, by the client to see if we support it, but again, this is a not-so-complex app and we are skipping these edge cases.


Managing Output

To finish our base controller, let’s create a method that every controller will use to send its results back to the client. In the base controller class, add the following method:

protected function _format_output( $output = null ) {
    $this->output->set_header( 'Access-Control-Allow-Origin: *' );

    if( isset( $output->status ) && $output->status == 'error' ) {
        $this->output->set_status_header( 409, $output->desc );
    }
    $this->_parse_data( $output );

    $this->output->set_content_type( 'application/json' );
    $this->output->set_output( json_encode( $output ) );
}

Again, in order for BackboneJS to process the server response it has to know that its host is accepted by the server, hence the Allow-Origin header, then, if the result is a faulty one, we set a status header indicating this. This status will become more clear when we create the back-end models. Next we use the parse_data helper, which will be a private method (that we will write in a moment) but let me skip that for the time being, then we set the content type as JSON and finally we encode the response as a JSON object. Again, here we could (and should) support other output formats (like XML).

Now let’s create the parse_data helper method (and I’ll explain it afterwards), add the following code to the base controller:

private function _parse_data( &$data ) {
    if ( ! is_array( $data ) && ! is_object( $data ) )
        return $data;

    foreach ( $data as $key => $value ) {
        if ( is_object( $value ) || is_array( $value ) ) {
            if( is_object( $data ) ) {
                $data->{$key} = $this->_parse_data( $value );
            } else {
                $data[ $key ] = $this->_parse_data( $value );
            }
        }

        if ( isset( $value->sec ) ) {
            if( is_object( $data ) ) {
                $data->{$key} = date( 'd.m.Y', $value->sec );
            } else {
                $data[ $key ] = date( 'd.m.Y', $value->sec );
            }
        }

        if ( is_object( $value ) && isset( $value->{'$id'} ) ) {
            if( is_object( $data ) ) {
                $data->{$key} = $value->__toString();
            } else {
                $data[ $key ] = $value->__toString();
            }
        }
    }

    return $data;
}

First off, note that we only parse the data for arrays and objects, and we’re doing it recursively. This pre-parsing has to do with the fact that MongoDB uses dates and IDs as objects, but our clients don’t need this information. Now for the case of IDs, we just need its string value, hence the toString method call, then the value has an ‘$id’ property. Afterwards we are converting the dates to a day.month.year format, this is being done for convenience in the design of the client application, again, not the most flexible approach but it works for this example.


Handling Input

Since we’re sending JSON back to the client application, it is only logical that we accept data in JSON format as well. CodeIgniter doesn’t support this by default like Laravel does, as a matter of fact, CodeIgniter doesn’t even support put and delete params. This is mainly because the framework is not intended for a RESTful service, however the effort that it takes to adapt it is minimal compared to the benefits, at least from my point of view.

So we will start by supporting the JSON data that BackboneJS sends. Create a new file inside the "core" folder, this time it is going to be named "MY_Input.php" and it will have the following basic structure:

<?php
if( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

class MY_Input extends CI_Input {

}

Now every time we use $this->input in our application we’ll be referring to this class, we will create some new methods and override a few existing ones. First off, we are going to add the support for JSON data, add the following method to the new class.

public function json() {
    if ( !self::$request_params ) {
        $payload    = file_get_contents( 'php://input' );

        if ( is_array( $payload ) ) {
            self::$request_params   = $payload;
        } else if ( ( substr( $payload, 0, 1 ) == "{" ) && ( substr( $payload, ( strlen( $payload ) - 1 ), 1 ) == "}" ) ) {
            self::$request_params   = json_decode( $payload );
        } else {
            parse_str( $payload, self::$request_params );
        }
    }

    return (object) self::$request_params;
}

$request_params is a static variable used to store the request string/data sent by the client. It is static in order to make it object independent so that we can access it from any controller at any given time. The data is obtained from the php://input stream rather than the $_POST global. This is done in order to obtain the data sent in via PUT and DELETE requests as well. Finally, the obtained payload is inspected to check if it’s an array, a JSON encoded object, or a query string, and it’s processed accordingly. The result is then returned as an object.

For this method to work, we need to create the static $request_params variable, add its declaration to the top of the class.

private static $request_params  = null;

Handling Regular Requests

Next, we need to override the post method of the regular input class to use the new JSON payload instead of the $_POST global, add the following method to the new Input class.

public function post( $index = NULL, $xss_clean = FALSE ) {
    $request_vars   = ( array ) $this->json();
    if ( $index === NULL && !empty( $request_vars ) ) {
        $post       = array();
        foreach( array_keys( $request_vars ) as $key ) {
            $post[$key]  = $this->_fetch_from_array( $request_vars, $key, $xss_clean );
        }
        return $post;
    }
    return $this->_fetch_from_array( $request_vars, $index, $xss_clean );
}

This is almost the same as the post method from the original CI_Input class, with the difference being that it uses our new JSON method instead of the $_POST global to retrieve the post data. Now let’s do the same for the the PUT method.

public function put( $index = NULL, $xss_clean = FALSE ) {
    $request_vars   = ( array ) $this->json();
    if ( $index === NULL && !empty( $request_vars ) ) {
        $put = array();
        foreach( array_keys( $request_vars ) as $key ) {
            $put[$key]   = $this->_fetch_from_array( $request_vars, $key, $xss_clean );
        }
        return $put;
    }
    return $this->_fetch_from_array( $request_vars, $index, $xss_clean );
}

And then we also need the DELETE method:

public function delete( $index = NULL, $xss_clean = FALSE ) {
    $request_vars   = ( array ) $this->json();
    if ( $index === NULL && !empty( $request_vars ) ) {
        $delete = array();
        foreach( array_keys( $request_vars ) as $key ) {
            $delete[$key]   = $this->_fetch_from_array( $request_vars, $key, $xss_clean );
        }
        return $delete;
    }
    return $this->_fetch_from_array( $request_vars, $index, $xss_clean );
}

Now technically, there’s really no need for these additional methods, since the post method can handle the params in the PUT and DELETE requests, but semantically it’s better (in my opinion).

This is all we need for our custom Input class. Again we’re ignoring edge cases here, like multipart requests, even though it’s not very hard to handle those and still maintain the functionality obtained here, but, for the sake of simplicity we’ll keep it just the way it is.


Base Model

To end the extension of the core classes, let’s create a base model that every model in the app will extend upon, this is just to avoid repetition of common tasks for every model. Like any other core class extension, here’s our barebones base model:

<?php
if( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

class MY_Model extends CI_Model {

}

This base model will only serve the purpose of setting and retrieving errors. Add the following method to set a model error:

protected function _set_error( $desc, $data = null ) {
    $this->_error           = new stdClass();
    $this->_error->status   = 'error';
    $this->_error->desc     = $desc;
    if ( isset( $data ) ) {
        $this->_error->data = $data;
    }
}

As you can see, this method uses an instance variable $error, so let’s add its declaration to the top of our base model class.

protected $_error;

Finally, to keep it structured, let’s create the getter method for this property.

public function get_error() {
    return $this->_error;
}

Handling Sessions

Session Controller

For the last part of this tutorial, we will create the controller and model to handle user sessions.

The controller for our session is going to respond to any POST request made to our Session resource, since the session can’t be retrieved after creation, nor updated directly, this controller will only respond to POST and DELETE requests. Please note that sending any other request to the resource will result in a server error, we’re not dealing with edge cases here but this could be easily avoided by checking if the method that’s called exists in our MY_Controller file and setting a default method name if the resource doesn’t support the request.

Below you’ll find the structure for our Session controller:

<?php
if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

class Session extends MY_Controller {

    public function __construct() {}

    public function save() {}

    public function remove( $id = null ) {}
}

Note that this controller is extending the MY_Controller class instead of the regular CI_Controller class, we do this in order to use the _remap method and other functionality that we created earlier. OK, so now let’s start with the constructor.

public function __construct() {
    parent::__construct();

    $this->load->model( 'session_model', 'model' );
}

This simple constructor just calls its parent constructor (as every controller in CodeIgniter must do) and then loads the controller’s model. The code for the save method is as follows.

public function save() {
    $result = $this->model->create();
    if ( !$result ) {
        $result = $this->model->get_error();
    }
    $this->_format_output( $result );
}

And then the code for the remove method:

public function remove( $id = null ) {
    $result = $this->model->destroy( $id );
    if ( !$result ) {
        $result = $this->model->get_error();
    }
    $this->_format_output( $result );
}

Both methods simply delegate the task at hand to the model, which handles the actual data manipulation. In a real world application, the necessary data validation and session checking would be done in the controller, and the common tasks such as session checking should be implemented in the base controller.

Session Model

Now let’s move on to the session model. Here is its basic structure:

<?php
if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

class Session_Model extends MY_Model {

    public function __construct() {}

    public function create() {}

    public function destroy( $id ) {}
}

Like the controller, this model extends the MY_Model class instead of the regular CI_Model class, this is being done in order to use the common methods that we’ve created earlier. Again, let’s start with the constructor.

public function __construct() {
    $this->load->driver( 'mongo_db' );
}

In this case, we just load the Mongo_db driver, that we discussed earlier. Now we’ll continue with the method in charge of destroying the session.

public function destroy( $id ) {
    $filters    = array( '_id' => $this->mongo_db->gen_id( $id ) );

    $query     = $this->mongo_db->get_where( 'sessions', $filters );
    if ( $query->num_rows() == 0 ) {
        $this->_set_error( 'INVALID_CREDENTIALS' );
        return false;
    }

    $this->mongo_db->remove( 'sessions', $filters );
    return 'SESSION_TERMINATED';
}

In this method we check if there’s a session for the given session_id, and if so we attempt to remove it, sending a success message if everything goes OK, or setting an error and returning false if something goes wrong. Note that when using the session_id we use the special method $this->mongo_db->gen_id, this is because like I mentioned earlier, IDs in MongoDB are objects, so we use the id string to create it.

Finally, let’s write the create method which will wrap up part one of this tutorial series.

public function create() {
    $query      = $this->mongo_db->get_where( 'users', array( 'email' => $this->input->post( 'email' ) ) );
    if ( $query->num_rows() != 1 ) {
        $this->_set_error( 'INVALID_CREDENTIALS' );
        return false;
    }

    $this->load->library( 'encrypt' );
    $user   = $query->row();
    $salt   = $this->encrypt->decode( $user->salt );
    if ( $user->pass != sha1( $this->input->post( 'pass' ) . $salt ) ) {
        $this->_set_error( 'INVALID_CREDENTIALS' );
        return false;
    }

    $this->mongo_db->remove( 'sessions', array( 'user_id' => $user->_id->__toString() ) );

    $session    = array(
        'timestamp'     => now(),
        'user_id'       => $user->_id->__toString(),
        'persistent'    => $this->input->post( 'persistent' )
    );

    if ( !$this->mongo_db->insert( 'sessions', $session ) ) {
        $this->_set_error( 'ERROR_REGISTERING_SESSION' );
        return false;
    }

    $result                 = new stdClass();
    $result->id             = $this->mongo_db->insert_id();
    $result->user_id        = $user->_id->__toString();

    return $result;
}

First of all, we check that there’s a user associated with the given email. Then we decode the user’s associated salt (which I’ll explain in the second part of this series when we cover user registration) and check that the given password matches the user’s stored password.

We then remove any previous session associated with the user and create a new session object. If we were checking the session thoroughly, we would add things like the user_agent, ip_address, last_activity field and so on to this object. Finally, we send back to the client the session and user IDs for the new session.


Conclusion

This has been a rather long tutorial, we covered a lot of topics, and we have even more to cover yet. Hopefully by now you have a better understanding of RESTful or stateless services and how to create such a service with CodeIgniter, and possibly, you may have also picked up some new ideas that you can give to the framework’s core functionality.

In the next part we will finish the back-end service and in parts three and four we’ll cover the BackboneJS client application. If you have any doubts/suggestions or anything to say, please do so in the comments section below.

Sponsored post
feedback2020-admin
20:51

April 17 2012

13:16

Advanced CodeIgniter Profiling With XHProf

There are a number of ways to profile and monitor the performance of PHP code in a development environment, but once it’s been let loose on a production server its extremely difficult to know what’s going on when your app is getting accessed by your users.

In March 2009, Facebook released XHProf, a function level profiler that allows you to identify bottlenecks in your application. And it runs on a production server with little overhead.

XHProf will provide you with a hierarchical profile of the functions your application calls, allowing you to follow the chain of events that lead up to resource intensive code running. You’ll be able to see exactly how much wall time (the actual time elapsed), CPU time and memory your application uses.

This tutorial will help you get XHProf installed on your server, and integrated with your CodeIgniter application via hooks so that you can start profiling your application, in a production environment, straight away. Everything you see here was written for Ubuntu 10.04 – the latest LTS release at the time of writing.


Installation

Installation of XHProf can be done via PECL – that said, I’ve never been able to get the PECL version installed on Ubuntu easily so its easier to install from source. Start off by downloading the latest revision from the XHProf GitHub account.

  	wget https://github.com/facebook/xhprof/tarball/master -O xhprof.tar.gz

Extract the tarball and switch into the extracted folder – this will change depending on the latest revision available from GitHub.

	tar -xvf xhprof.tar.gz
	cd facebook-xhprof-bc8ef04/extension

Then install as normal.

	phpize
	./configure
	make
	sudo make install

Finally, we need to tell PHP to load the extension. Create a config file for it – I do this for cleanliness but you can always drop it at the end of your main php.ini.

	sudo nano /etc/php5/conf.d/xhprof.ini

And paste in the following:

	extension=xhprof.so
	xhprof.output_dir="/var/tmp/xhprof"

This tells XHProf to use the directory at /var/tmp/xhprof to save its run data.

You can check whether XHProf is installed correctly by entering php -m at the command line and checking that the module is available. Remember to restart Apache so that it gets picked up in your PHP web applications as well.

If you want to render the callgraph images you’ll also need the graphviz package. This can be obtained from apt.

	sudo apt-get install graphviz

Integration With CodeIgniter

XHProf can be used on an ad-hoc basis to evaluate small pieces of code, but it’s at its most useful when you let it profile the full page. First of all, you’ll need to move the XHProf code into your web applications root so that it has access to the appropriate classes.

	sudo mv ~/facebook-xhprof-bc8ef04  /var/www/xhprof

CodeIgniter has an excellent mechanism for injecting custom code into the execution of a page called ‘Hooks’. This is what we’ll use to integrate XHProf with your application. Enable hooks in your application/config/config.php file.

	$config['enable_hooks'] = true;

Then specify your hooks in application/config/hooks.php

	$hook['pre_controller'] = array(
	  'class'  => 'XHProf',
	  'function' => 'XHProf_Start',
	  'filename' => 'xhprof.php',
	  'filepath' => 'hooks',
	  'params' => array()
	);

	$hook['post_controller'] = array(
		'class'  => 'XHProf',
		'function' => 'XHProf_End',
		'filename' => 'xhprof.php',
		'filepath' => 'hooks',
		'params' => array()
	);

Then create the hook that will load XHProf into your application at application/hooks/xhprof.php. This class will provide the necessary minimum to get XHProf collecting data from your application.

	class XHProf {

		private $XHProfPath = 'xhprof/';
		private $applicationName = 'my_application';
		private $sampleSize = 1;
		private static $enabled = false;

		public function XHProf_Start() {
			if (mt_rand(1, $this->sampleSize) == 1) {
				include_once $this->XHProfPath . 'xhprof_lib/utils/xhprof_lib.php';
				include_once $this->XHProfPath . 'xhprof_lib/utils/xhprof_runs.php';
				xhprof_enable(XHPROF_FLAGS_NO_BUILTINS);

				self::$enabled = true;
			}
		}

		public function XHProf_End() {
			if (self::$enabled) {
				$XHProfData = xhprof_disable();

				$XHProfRuns = new XHProfRuns_Default();
				$XHProfRuns->save_run($XHProfData, $this->applicationName);
			}
		}

	}

There’s a few thing to point out in this code sample.

  • The $XHProfPath variable should point to the directory you installed XHProf in. In our example, we put it in the root of the web application, but you might be storing it somewhere central and symlinking it to multiple applications.
  • The $applicationName variable lets you specify the name of the application using XHProf. This could be especially important in an environment where you’re running multiple applications on the same server.
  • The $sampleSize variable lets you specify a factor for how often XHProf profiles a run. In a production environment where you’re receiving thousands of hits, it’s probably not worth storing every single run. You can increase this variable to get a random sample of runs. Changing it to 10, for example, will give you a report from one in every 10 visits to your application.

The xhprof_enable() function can accept any combination of 3 constants.

  • XHPROF_FLAGS_NO_BUILTINS – skip all internal php functions. Adding this means you’ll only see time spent in functions that you have written (or are part of CodeIgniter)
  • XHPROF_FLAGS_CPU – add additional CPU profiling information
  • XHPROF_FLAGS_MEMORY – add additional memory profiling information

Combine them using +. eg. xhprof_enable(XHPROF_FLAGS_NO_BUILTINS + XHPROF_FLAGS_MEMORY);

After running through your application a couple of times, point your browser at the XHProf application directory http://localhost/xhprof/xhprof_html/index.php – adjusting for the address of your development server – and you’ll see a list of your last application runs with the newest at the top. Select one of the runs to see it’s profiling information.


Evaluating the Results

Storing all this profiling information is all very well and good but knowing how to evaluate it is the key to optimising your application.

The ‘Overall Summary’ is a good place to start – it’ll show you:

  • Total inclusive wall time – how long (in microseconds) it took for you page to be generated
  • Total memory use – the total memory used by this run of your application
  • Total peak memory use – the maximum amount of memory that was used by your application
  • Number of function calls – the number of functions that were called by your application
Run summary

These number should give you an overall base to start from and provide headline numbers to compare against when you start optimisation.

Below the summary is the detailed run report The bottlenecks in your application should be fairly obvious – they’re the function calls at the top of the report.

Wall report

The most resource intensive things you’re likely to come across will be those that make calls to external services or your database. By default, the results are sorted by ‘inclusive wall time’. This shows the functions that took the longest to run by the cumulative total of them and the functions they call. Ordering by ‘exclusive wall time’ allows you to see the specific functions that are using the most amount of resource.

Clicking a function allows you to drill down into more detail about that function and the functions it called. From there, it’ll be easier to see exactly what your long running function was doing and spot any issues.

When debugging your CodeIgniter application, one of the best places to start is the controller being called for your page – Welcome::index in the example. From there you can easily see the breakdown of where the controller spent most of it’s time.

Controller summary

Callgraph

XHProf can generate a call graph view that provides a visual clue to the main path of your application. The main bottlenecks are highlighted in red to show where most your resources are being spent.

Callgraph

Comparing Runs

XHProf provides a mechanism for comparing multiple runs – this will allow you to make a number of optimisations and then see how they’ve affected your application.

http://localhost/xhprof/xhprof_html/index.php?run1=run_id_1>&run2=run_id_2&source=applicationName

Note: run_id_1 and run_id_2 should be the ids from some of your previous runs and applicationName should be the name you specified when setting up the hook earlier.

This will provide the same information you see in a regular report but provide percentage statistics on any changes since the first run, allowing you to easily see if your optimisations are moving your performance in the right direction.

Aggregating Runs

Sometimes a single run might not be enough to evaluate exactly what’s going on. Pages my work slightly differently depending on the query string or user input or there might be differences in caching mechanisms.

Aggregating a number of runs allows you to combine a number of runs and receive an average of the resources consumed.

http://localhost/xhprof/xhprof_html/index.php?run=run_id,run_id,run_id&source=applicationName

Note: run_id should be the ids from some of your previous runs and applicationName should be the name you specified when setting up the hook earlier.


Summary

You should now have XHProf up and running in your CodeIgniter application and be able to see exactly where your code is spending most of it’s time. Optimisation can be a difficult task. Sometimes it’s not as simple as reimplementing a function, or adding a layer of caching. Thinking about why you’re doing something and what the exact effect that is having on your application is just as important.

So let me know if you have any questions in the comments below. Thank you so much for reading!


March 26 2012

18:11

AJAX User Table Management in CodeIgniter: New on Premium

Learn how to use CodeIgniter and the jQuery library to create a slick, AJAX-utilizing management page for a typical “Users” table, and discover some of the awesome features of jQuery UI.

This Tuts+ Premium exclusive tutorial will guide you through the process of creating a slick, AJAX-utilizing management page for a typical “Users” table in a MySQL database. We will cover a range of topics, in both CodeIgniter and jQuery, including creating and using Models, Controllers and Views, the Form Validation class, and jQuery UI.

preview
preview

Tuts+ Premium

The recently re-launched Tuts+ Premium is a service that provides top-tier training in a variety of creative fields. Whether you prefer books, visual training, or in depth tutorials, we have you covered. While we unfortunately can’t afford to provide the service for free, it’s only $19 a month – less than you’d spend on dinner.

I hope you’ll consider checking it out! In addition to learning a huge variety of new skills, it’s also a fantastic way to say thank you to Nettuts+.


September 22 2011

18:47

Build Ajax Data Grids with CodeIgniter and jQuery

In this lesson, we will create a CodeIgniter library that allows us to generate data grids automatically for managing any database table. I’ll explain each step required to create this class; so you’ll likely learn some new OOP techniques/concepts in the process!

As a bonus, we’ll proceed to write some jQuery code that will enable a user to update the data grid’s content without having to wait for a page refresh.


Please Note…

This tutorial assumes that you have a modest understanding of the CodeIgniter and jQuery frameworks.

What is a Data Grid?

A datagrid is a table that displays the contents of a database or table along with sorting controls.

A datagrid is a table that displays the contents of a database or table along with sorting controls. In this tutorial, we will be tasked with providing this functionality, but also saving the user from waiting for the page to refresh each time an operation is performed. Thanks to jQuery, this will be a fairly simple task!

What about the users who don’t have Javascript enabled? Don’t worry, we’ll compensate for them as well!


Step 1: Build a Data Grid Generator Class

We want to build a tool that will enable us to create datagrids dynamically for any database table that we have. This means the code is not tied up to any specific table structure, and, thus, is independent on the data itself. All the coder (the developer who uses our class) must know is the name of the table to be transformed into a grid and the primary key for that table. Here is the preface of the class that we will be developing for the most part of this tutorial:

<?php
class Datagrid{
	private $hide_pk_col = true;
	private $hide_cols = array();
	private $tbl_name = '';
	private $pk_col	= '';
	private $headings = array();
	private $tbl_fields = array();
}
?>

The Datagrid Class could well be added to the application/library folder, but we are going to add it as a helper to the CodeIgniter framework. Why? Because loading libraries doesn’t allow us to pass arguments to the class’ constructor, thus loading it as a helper will solve the problem. This point will make more sense for you when we have finished writing the constructor.

The Class’ Constructor Method

public function __construct($tbl_name, $pk_col = 'id'){
	$this->CI =&amp; get_instance();
	$this->CI->load->database();
	$this->tbl_fields = $this->CI->db->list_fields($tbl_name);
	if(!in_array($pk_col,$this->tbl_fields)){
		throw new Exception(&quot;Primary key column '$pk_col' not found in table '$tbl_name'&quot;);
	}
	$this->tbl_name = $tbl_name;
	$this->pk_col = $pk_col;
	$this->CI->load->library('table');

}

We have much going on already; but don’t worry, as I’ll explain everything for you in the next paragraph.

The constructor takes two arguments: the first one being the name of the table in your database that you wish to display as a datagrid to the user; the second param is the name of the column serving as the primary key for that table (more on that later). Inside the constructor’s body, we instantiate the CodeIgniter Object, the Database Object and the HTML Table class/library. All of these will be needed throughout a Datagrid object’s lifetime and are already built into the CI framework. Notice that we also check if the primary key really exists in the given table, and, in case it does not, we throw an exception reporting the error. Now the $this->tbl_fields member variable will be available for later use, so we don’t have to fetch the database again.

“We can use the command, $CI->db->list_fields($tbl_name) to fetch the names of all fields that a table has. However, for better performance, I recommend caching the results.”

Method for Customizing Table Headings

public function setHeadings(array $headings){
	$this->headings = array_merge($this->headings, $headings);
}

This permits you to customize the headings of your data grid table – that is, with it, you can overwrite the original column names for certain table fields. It takes an associative array, like this: regdate => “Registration Date”. Instead of just the technical “Regdate” as the column heading for that type of data, we have a more human-readable title in its place. The code responsible for applying the headings will be revealed shortly.

Method for Ignoring/Hiding Table Fields

public function ignoreFields(array $fields){
	foreach($fields as $f){
		if($f!=$this->pk_col)
			$this->hide_cols[] = $f;
	}
}

ignoreFields receives an array containing the fields to be ignored when fetching data from the database. This is useful when we have tables with lots of fields, but we only want to hide a couple of them. This method is smart enough to track an attempt to ignore the primary key field and then skip that. This is so because the primary key cannot be ignored for technical reasons (you will see why shortly). Still, if you want to hide the primary key column from appearing in the UI, you can use the hidePkCol method:

public function hidePkCol($bool){
	$this->hide_pk_col = (bool)$bool;
}

This method receives a boolean value to indicate if we want to hide the primary key column so it won’t show up in the data grid. Sometimes, it’s an ugly idea to display the pkey data, which is usually a numerical code without any meaning to the user.

Next instance method:

private function _selectFields(){
	foreach($this->tbl_fields as $field){
		if(!in_array($field,$this->hide_cols)){
			$this->CI->db->select($field);
			// hide pk column heading?
			if($field==$this->pk_col &amp;&amp; $this->hide_pk_col) continue;
				$headings[]= isset($this->headings[$field]) ? $this->headings[$field] : ucfirst($field);
		}
	}
	if(!empty($headings)){
		// prepend a checkbox for toggling
		array_unshift($headings,&quot;<input type='checkbox' class='check_toggler'>&quot;);
		$this->CI->table->set_heading($headings);
	}

}

Here we have a helper method; that’s why it has the “private” modifier and is prefixed with an underline character (code convention). It will be used by the generate() method – explained shortly – in order to have the appropriate table fields selected and also the appropriate headings set to the table (generator) object. Notice the following line:

$headings[]= isset($this->headings[$field]) ? $this->headings[$field] : ucfirst($field);

This is where we apply the customized headers or resort to the default ones if none is given. If the pk column is supposed to be hidden from display, then it’s heading will be skipped. Also notice the following line:

array_unshift($headings,&quot;<input type='checkbox' class='dg_check_toggler'>&quot;);

The above command instructs the program to prepend a “Master” checkbox as the first heading of the table. That checkbox is different from other checkboxes in the grid in that it allows a user to check or uncheck all checkboxes in just one go. This toggling functionality will be implemented in a few moments with a simple jQuery code snippet.

Method to Generate/Render the Datagrid

Now comes the thing that does the real work for us:

public function generate(){
	$this->_selectFields();
	$rows = $this->CI->db
			->from($this->tbl_name)
			->get()
			->result_array();
	foreach($rows as &amp;$row){
		$id = $row[$this->pk_col];

		// prepend a checkbox to enable selection of items/rows
		array_unshift($row, &quot;<input class='dg_check_item' type='checkbox' name='dg_item[]' value='$id' />&quot;);

		// hide pk column cell?
		if($this->hide_pk_col){
			unset($row[$this->pk_col]);
		}
	}

	return $this->CI->table->generate($rows);
}

The generate method, as its name suggests, is responsible for generating the data grid itself. You should call this method only after you have configured the object according to your needs. The first thing it does is call the $this->_selectFields() method to perform the actions we explained earlier. Now it has to fetch all rows from the database and then loop through them, adding checkboxes to the beginning of each row:

// prepend a checkbox to enable selection of items/rows
array_unshift($row, &quot;<input class='dg_check_item' type='checkbox' name='dg_item[]' value='$id' />&quot;);

Inside the foreach loop on the generate method, if the $this->hide_pk_col flag is set to true, then we must unset the primary key entry in the $row array so it won’t show up as a column when the $this->CI->table object processes all rows and generates the final html output. At this point, it is okay to remove the primary key, if necessary, because we no longer need that information. A

But what does the user do with the selected/checked rows? To answer this, I have prepared a few more methods. The first one enables us to create “action buttons” without having to know any technical details about how the grid system works internally:

Method for Adding Buttons to a Data Grid Form

public static function createButton($action_name, $label){
	return &quot;<input type='submit' class='$action_name' name='dg_action[$action_name]' value='$label' />&quot;;
}

Simply pass the name of the action as the first argument and a second argument to indicate the label for the generated button. A class attribute is automatically generated for that button so we can play around with it more easily when we are working with it in our JavaScript. But, how do we know if a certain action button has been pressed by the user? The answer can be found in the next method:

public static function getPostAction(){
// get name of submitted action (if any)
	if(isset($_POST['dg_action'])){
		return key($_POST['dg_action']);
	}
}

Yep! Another static method that helps us when we are dealing with forms. If any data grid has been submitted, this method will return the name of the action (or “operation”) associated with that submit event. In addition, another handy tool for processing our datagrid forms is…

public static function getPostItems(){
	if(!empty($_POST['dg_item'])){
		return $_POST['dg_item'];
	}
	return array();
}

… which returns an array containing the selected ids so you can track which rows have been selected on the grid and then perform some action with them. As an example of what can be done with a selection of row ids, I have prepared another method – this one being an instance method, and not a static one, because it makes use of the object’s instance resources in order to do its business:

public function deletePostSelection(){
// remove selected items from the db
	if(!empty($_POST['dg_item']))
		return $this->CI->db
			->from($this->tbl_name)
			->where_in($this->pk_col,$_POST['dg_item'])
			->delete();
}

If at least one checkbox was checked, the deletePostSelection() method will generate and execute an SQL statement like the following (suppose $tbl_name='my_table' and $pk_col='id'):

DELETE FROM my_table WHERE id IN (1,5,7,3,etc...)

…which will effectively remove the selected rows from the persistent layer. There could be more operations you could add to a data grid, but that will depend on the specifics of your project. As a tip, you could extend this class to, say, InboxDatagrid, so, beyond the deletePostSelection method, it could include extra operations, such as moveSelectedMessagesTo($place), etc…

Putting everything together

Now, if you have followed this tutorial step by step, you should have ended up with something similar to the following:

class Datagrid{

	private $hide_pk_col = true;
	private $hide_cols = array();
	private $tbl_name = '';
	private $pk_col	= '';
	private $headings = array();
	private $tbl_fields = array();

	function __construct($tbl_name, $pk_col = 'id'){
		$this->CI =&amp; get_instance();
		$this->CI->load->database();
		$this->tbl_fields = $this->CI->db->list_fields($tbl_name);
		if(!in_array($pk_col,$this->tbl_fields)){
			throw new Exception(&quot;Primary key column '$pk_col' not found in table '$tbl_name'&quot;);
		}
		$this->tbl_name = $tbl_name;
		$this->pk_col = $pk_col;
		$this->CI->load->library('table');

	}

	public function setHeadings(array $headings){
		$this->headings = array_merge($this->headings, $headings);
	}

	public function hidePkCol($bool){
		$this->hide_pk_col = (bool)$bool;
	}

	public function ignoreFields(array $fields){
		foreach($fields as $f){
			if($f!=$this->pk_col)
				$this->hide_cols[] = $f;
		}
	}

	private function _selectFields(){
		foreach($this->tbl_fields as $field){
			if(!in_array($field,$this->hide_cols)){
				$this->CI->db->select($field);
				// hide pk column heading?
				if($field==$this->pk_col &amp;&amp; $this->hide_pk_col) continue;
				$headings[]= isset($this->headings[$field]) ? $this->headings[$field] : ucfirst($field);
			}
		}
		if(!empty($headings)){
			// prepend a checkbox for toggling
			array_unshift($headings,&quot;<input type='checkbox' class='dg_check_toggler'>&quot;);
			$this->CI->table->set_heading($headings);
		}

	}

	public function generate(){
		$this->_selectFields();
		$rows = $this->CI->db
				->from($this->tbl_name)
				->get()
				->result_array();
		foreach($rows as &amp;$row){
			$id = $row[$this->pk_col];

			// prepend a checkbox to enable selection of items
			array_unshift($row, &quot;<input class='dg_check_item' type='checkbox' name='dg_item[]' value='$id' />&quot;);

			// hide pk column?
			if($this->hide_pk_col){
				unset($row[$this->pk_col]);
			}
		}

		return $this->CI->table->generate($rows);
	}

	public static function createButton($action_name, $label){
		return &quot;<input type='submit' class='$action_name' name='dg_action[$action_name]' value='$label' />&quot;;
	}

	public static function getPostAction(){
	// get name of submitted action (if any)
		if(isset($_POST['dg_action'])){
			return key($_POST['dg_action']);
		}
	}

	public static function getPostItems(){
		if(!empty($_POST['dg_item'])){
			return $_POST['dg_item'];
		}
		return array();
	}

	public function deletePostSelection(){
	// remove selected items from the db
		if(!empty($_POST['dg_item']))
			return $this->CI->db
				->from($this->tbl_name)
				->where_in($this->pk_col,$_POST['dg_item'])
				->delete();
	}

}

Notice: Don’t forget to save this file as datagrid_helper.php, and place it in “application/helper/”


Step 2: Testing the Datagrid Helper Class with a CodeIgniter Controller

We’ll now create a simple test controller and load the Datagrid class as a helper in its constructor. But before that, we should define a dummy database table and populate it with some sample data.

Execute the following SQL to create the database and the user table:

CREATE DATABASE `dg_test`;
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(80) NOT NULL,
  `password` varchar(32) NOT NULL,
  `email` varchar(255) NOT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

Next, let’s add some users to it:

INSERT INTO `users` (`id`, `username`, `password`, `email`) VALUES
(1, 'david', '12345', 'david@domain.com'),
(2, 'maria', '464y3y', 'maria@domain.com'),
(3, 'alejandro', 'a42352fawet', 'alejandro@domain.com'),
(4, 'emma', 'f22a3455b2', 'emma@domain.com');

Now, save the following code as “test.php,” and add it to the “application/controllers” folder:

<?php
class Test extends CI_Controller{

	function __construct(){
		parent::__construct();
		$this->load->helper(array('datagrid','url'));
		$this->Datagrid = new Datagrid('users','id');
	}

	function index(){
		$this->load->helper('form');
		$this->load->library('session');

		$this->Datagrid->hidePkCol(true);
		$this->Datagrid->setHeadings(array('email'=>'E-mail'));
		$this->Datagrid->ignoreFields(array('password'));

		if($error = $this->session->flashdata('form_error')){
			echo &quot;<font color=red>$error</font>&quot;;
		}
		echo form_open('test/proc');
		echo $this->Datagrid->generate();
		echo Datagrid::createButton('delete','Delete');
		echo form_close();
	}

	function proc($request_type = ''){
		$this->load->helper('url');
		if($action = Datagrid::getPostAction()){
			$error = &quot;&quot;;
			switch($action){
				case 'delete' :
					if(!$this->Datagrid->deletePostSelection()){
						$error = 'Items could not be deleted';
					}
				break;
			}
			if($request_type!='ajax'){
				$this->load->library('session');
				$this->session->set_flashdata('form_error',$error);
				redirect('test/index');
			} else {
				echo json_encode(array('error' => $error));
			}
		} else {
			die(&quot;Bad Request&quot;);
		}
	}

}
?>

An instance of this class is created and passed as a reference to the $this->Datagrid member. Notice that we will be fetching data from a table called “users” whose primary key is the “id” column; then, on the index method we take the following steps: configure the Datagrid object, render it inside a form with a delete button added to it and see if everything works as expected:

Question: What happens when the form is sent?

Answer: The “Test::proc()” method takes care of processing the form and choosing the right operation to apply against the ids that were selected by the form’s sender. It also takes care of AJAX requests, so it will echo a JSON object back to the client. This AJAX-aware feature will come in handy when jQuery comes into action, which is right now!

“It’s always a smart idea to create web applications which compensates for when JavaScript/AJAX is unavailable. This way, some users will have a richer and faster experience, while those without JavaScript enabled will still be able to use the application normally.”


Step 3: Implementing Ajax (jQuery to the Rescue!)

When the user clicks the button (or any other action button), we would like, perhaps, to prevent the page from reloading and having to generate everything again; this could make the user of our application fall asleep! Circumventing this problem will not be a difficult task if we stick to the jQuery library. Since this is not a “beginners” tutorial, I will not go through all the details related to how to get the library, how to include it on the page, etc. You’re expected to know these steps on your own.

Create a folder, named “js“, add the jQuery library within, and create a view file, named users.php. Open this new file, and add:

<html>
<head>
	<title>Users Management</title>
	<script src=&quot;<?php echo base_url(); ?>js/jquery-1.6.3.min.js&quot;></script>
	<script src=&quot;<?php echo base_url(); ?>js/datagrid.js&quot;></script>
</head>
<body>
<?php
		$this->Datagrid->hidePkCol(true);
		if($error = $this->session->flashdata('form_error')){
			echo &quot;<font color=red>$error</font>&quot;;
		}
		echo form_open('test/proc',array('class'=>'dg_form'));
		echo $this->Datagrid->generate();
		echo Datagrid::createButton('delete','Delete');
		echo form_close();
?>
</body>
</html>

Did you realize that we have moved the code away from Test::index and into the new view script? This means we must change the Test::index() method accordingly:

function index(){
	$this->load->helper('form');
	$this->load->library('session');
	$this->load->view('users');
}

That’s better. If you want to add some styling to the grid, you could use the following CSS (or make a better layout on your own):

	.dg_form table{
		border:1px solid silver;
	}

	.dg_form th{
		background-color:gray;
		font-family:&quot;Courier New&quot;, Courier, mono;
		font-size:12px;
	}

	.dg_form td{
		background-color:gainsboro;
		font-size:12px;
	}

	.dg_form input[type=submit]{
		margin-top:2px;
	}

Now, please, create a “datagrid.js” file, put it on the “js” directory, and start with this code:

$(function(){
	// cool stuff here...
})

Inside this closure, we will write code that will be tasked with controlling certain submit events once the page has completely loaded. The first thing we need to do is track when a user clicks a submit button on the data grid form, and then send that data to be processed on the server.

 	$('.dg_form :submit').click(function(e){
		e.preventDefault();
		var $form = $(this).parents('form');
		var action_name = $(this).attr('class').replace(&quot;dg_action_&quot;,&quot;&quot;);
		var action_control = $('<input type=&quot;hidden&quot; name=&quot;dg_action['+action_name+']&quot; value=1 />');

		$form.append(action_control);

		var post_data = $form.serialize();
		action_control.remove();

		var script = $form.attr('action')+'/ajax';
		$.post(script, post_data, function(resp){
			if(resp.error){
				alert(resp.error);
			} else {
				switch(action_name){
					case 'delete' :
						// remove deleted rows from the grid
						$form.find('.dg_check_item:checked').parents('tr').remove();
					break;
					case 'anotherAction' :
						// do something else...
					break;
				}
			}
		}, 'json')
	})

Alternatively, we could have started with something like: $('.dg_form').submit(function(e){...}). However, since I want to track which button has been pressed and extract the name of the chosen action based on it, I prefer binding an event handler to the submit button itself and then go my way up the hierarchy of nodes to find the form that the pressed button belongs to:

// finds the form
var $form = $(this).parents('form');
// extracts the name of the action
var action_name = $(this).attr('class').replace(&quot;dg_action_&quot;,&quot;&quot;);

Next, we add a hidden input element inside the form element to indicate which action is being sent:

// create the hidden input
var action_control = $('<input type=&quot;hidden&quot; name=&quot;dg_action['+action_name+']&quot; value=1 />');
// add to the form
$form.append(action_control);

This is necessary because function doesn’t consider the submit button to be a valid form entry. So we must have that hack in place when serializing the form data.

action_control.remove();

“Don’t forget: the function ignores the submit button, dismissing it as just another piece of markup junk!”

Sending Form Data to the Server

Next, we proceed to get the action attribute from the form element and append the string “/ajax” to that url, so the method will know that this is, in fact, an AJAX request. Following that, we use the jQuery.post function to send the data to be processed by the appropriate controller, server-side, and then intercept the response event with a registered callback/closure:

...
	var script = $form.attr('action')+'/ajax';
	$.post(script, post_data, function(resp){
		if(resp.error){
			alert(resp.error);
		} else {
			switch(action_name){
				case 'delete' :
					// remove deleted rows from the grid
					$form.find('.dg_check_item:checked').parents('tr').remove();
				break;
				case 'anotherAction' :
					// do something else...
				break;
			}
		}
	},'json')

Notice that we are asking the response to be encoded as “json” since we are passing that string as the fourth argument of the $.post function. The contents of the callback dealing with the server response should be rather simple to grasp; it determines if there is an error, and, if so, alerts it. Otherwise, it will indicate that the action was successfully processed (in this case, if it is a “” action, we remove the rows related to the ids that were selected by the user).


Step 4: Check All or Nothing!

The only thing that is missing now is the toggle functionality that I promised earlier. We must register a callback function for when the “Master” checkbox – which has a class attribute set to “dg_check_toggler” – is clicked. Add the following code snippet after the previous one:

	$('.dg_check_toggler').click(function(){
		var checkboxes = $(this).parents('table').find('.dg_check_item');
		if($(this).is(':checked')){
			checkboxes.attr('checked','true');
		} else {
			checkboxes.removeAttr('checked');
		}
	})

When the “toggler” checkbox is clicked, if it goes to a “checked” state, then all rows from the pertaining data grid will be checked simultaneously; otherwise everything will be unchecked.


Final Thoughts

We haven’t reached the tip of the iceberg when it comes to data grids for more complex content management systems. Other features which might prove to be useful are:

  • Sorting the data grid by column names
  • Pagination links for browsing the data grid
  • Edit/Modify links for updating a single row’s data
  • Search mechanism to filter results

Thanks for reading. If you’d like a follow-up tutorial, let me know in the comments!


September 08 2011

15:10

How to Upload Files with CodeIgniter and AJAX

Uploading files asnychronously can be a pain at the best of times, but when coupled with CodeIgniter, it can be a particularly frustrating experience. I finally found a way that not only works consistently, but keeps to the MVC pattern. Read on to find out how!


Preface

In this tutorial, we’ll be using the PHP framework CodeIgniter, the JavaScript framework jQuery, and the script AjaxFileUpload.

It’s assumed you have a working knowledge of CodeIgniter and jQuery, but no prior knowledge of AjaxFileUpload is necessary. It is also assumed that you already have an install of CodeIgniter already set up.

For the sake of brevity, the loading in of certain libraries/models/helpers has been omitted. These can be found in the source code supplied, and is pretty standard stuff.

You’ll also need a database, and a table, called files. The SQL to create said table is:

CREATE TABLE `files` (
  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `filename` varchar(255) NOT NULL,
  `title` varchar(100) NOT NULL
);

By the end of the tutorial, your file structure should look similar to this (omitting unchaged folders/files):

public_html/
– application/
—- controllers/
—— upload.php
—- models/
—— files_model.php
—- views/
—— upload.php
—— files.php
– css/
—- style.css
– files/
– js/
—- AjaxFileUpload.js
—- site.js


Step 1 - Creating the Form

Set up the Controller

First, we need to create our upload form. Create a new Controller, called upload, and in the index method, render the view upload.

Your controller should look like this:

class Upload extends CI_Controller
{
	public function __construct()
	{
		parent::__construct();
		$this->load->model('files_model');
		$this->load->database();
		$this->load->helper('url');
	}

	public function index()
	{
		$this->load->view('upload');
	}
}

We are also loading in the files model, so we can use it in our methods. A better alternative may be to autoload it in your actual project.

Create the Form

Create your view, upload.php. This view will contain our upload form.

<!doctype html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
	<script src="<?php echo base_url()?>js/site.js"></script>
	<script src="<?php echo base_url()?>js/ajaxfileupload.js"></script>
	<link href="<?php echo base_url()?>css/style.css" rel="stylesheet" />
</head>
<body>
	<h1>Upload File</h1>
	<form method="post" action="" id="upload_file">
		<label for="title">Title</label>
		<input type="text" name="title" id="title" value="" />

		<label for="userfile">File</label>
		<input type="file" name="userfile" id="userfile" size="20" />

		<input type="submit" name="submit" id="submit" />
	</form>
	<h2>Files</h2>
	<div id="files"></div>
</body>
</html>

Don’t forget to place ajaxfileupload.js in js/.

As you can see, we are loading in our scripts at the top; jQuery, AjaxFileUpload, and our own js file. This will house our custom JavaScript.

Then, we are simply creating a standard HTML form. The empty #files div is where our list of uploaded files will be.

Some Simple CSS

Just so it doesn’t look quite so bad, lets add some basic CSS to our file style.css in css/.

h1, h2 { font-family: Arial, sans-serif; font-size: 25px; }
h2 { font-size: 20px; }

label { font-family: Verdana, sans-serif; font-size: 12px; display: block; }
input { padding: 3px 5px; width: 250px; margin: 0 0 10px; }
input[type="file"] { padding-left: 0; }
input[type="submit"] { width: auto; }

#files { font-family: Verdana, sans-serif; font-size: 11px; }
#files strong { font-size: 13px; }
#files a { float: right; margin: 0 0 5px 10px; }
#files ul {	list-style: none; padding-left: 0; }
#files li { width: 280px; font-size: 12px; padding: 5px 0; border-bottom: 1px solid #CCC; }

Step 2 - The Javascript

Create and open site.js in js/. Place the following code:

$(function() {
	$('#upload_file').submit(function(e) {
		e.preventDefault();
		$.ajaxFileUpload({
			url 			:'./upload/upload_file/',
			secureuri		:false,
			fileElementId	:'userfile',
			dataType		: 'json',
			data			: {
				'title'				: $('#title').val()
			},
			success	: function (data, status)
			{
				if(data.status != 'error')
				{
					$('#files').html('<p>Reloading files...</p>');
					refresh_files();
					$('#title').val('');
				}
				alert(data.msg);
			}
		});
		return false;
	});
});

The JavaScript hijacks the form submit and AjaxFileUpload takes over. In the background, it creates an iframe and submits the data via that.

We’re passing across the title value in the data parameter of the AJAX call. If you had any more fields in the form, you’d pass them here.

We then check our return (which will be in JSON). If no error occured, we refresh the file list (see below), clear the title field. Regardless, we alert the response message.


Step 3 - Uploading the File

The Controller

Now on to uploading the file. The URL we are uploading to is /upload/upload_file/, so create a new method in the upload controller, and place the following code in it.

public function upload_file()
{
	$status = "";
	$msg = "";
	$file_element_name = 'userfile';

	if (empty($_POST['title']))
	{
		$status = "error";
		$msg = "Please enter a title";
	}

	if ($status != "error")
	{
		$config['upload_path'] = './files/';
		$config['allowed_types'] = 'gif|jpg|png|doc|txt';
		$config['max_size']	= 1024 * 8;
		$config['encrypt_name'] = TRUE;

		$this->load->library('upload', $config);

		if (!$this->upload->do_upload($file_element_name))
		{
			$status = 'error';
			$msg = $this->upload->display_errors('', '');
		}
		else
		{
			$data = $this->upload->data();
			$file_id = $this->files_model->insert_file($data['file_name'], $_POST['title']);
			if($file_id)
			{
				$status = "success";
				$msg = "File successfully uploaded";
			}
			else
			{
				unlink($data['full_path']);
				$status = "error";
				$msg = "Something went wrong when saving the file, please try again.";
			}
		}
		@unlink($_FILES[$file_element_name]);
	}
	echo json_encode(array('status' => $status, 'msg' => $msg));
}

This code loads in the CodeIgniter upload library with a custom config. For a full reference of it, check out the CodeIgniter docs.

We do a simple check to determine if the title is empty or not. If it isn’t, we load in the CodeIgniter upload library. This library handles a lot of our file validation for us.

Next, we attempt to upload the file. if successful, we save the title and the filename (passed in via the returned data array).

Remember to delete the temp file off the server, and echo out the JSON so we know what happened.

The Model

In keeping with the MVC pattern, our DB interaction will be handled by a model.

Create files_model.php, and add the following code:

class Files_Model extends CI_Model {

	public function insert_file($filename, $title)
	{
		$data = array(
			'filename'		=> $filename,
			'title'			=> $title
		);
		$this->db->insert('files', $data);
		return $this->db->insert_id();
	}

}

Files Folder

We should also create the folder our files will be uploaded to. Create new file in your web root called files, making sure it is writable by the server.


Step 4 - The File List

Upon a successful upload, we need to refresh the files list to display the change.

The JavaScript

Open site.js and add the following code to the bottom of the file, below everything else.

function refresh_files()
{
	$.get('./upload/files/')
	.success(function (data){
		$('#files').html(data);
	});
}

This simply calls a url and inserts the returned data into a div with an id of files.

We need to call this function on the page load to initially show the file list. Add this in the document ready function at the top of the file:

refresh_files();

The Controller

The URL we are calling to get the file list is /upload/files/, so create a new method called files, and place in the following code:

public function files()
{
	$files = $this->files_model->get_files();
	$this->load->view('files', array('files' => $files));
}

Quite a small method, we use our model to load in the currently saved files and pass it off to a view.

The Model

Our model handles the retrieval of the file list. Open up files_model.php, and add in the get_files() function.

public function get_files()
{
	return $this->db->select()
			->from('files')
			->get()
			->result();
}

Quite simple really: select all the files stored in the database.

The View

We need to create a view to display the list of files. Create a new file, called files.php, and paste in the following code:

<?php
if (isset($files) && count($files))
{
	?>
		<ul>
			<?php
			foreach ($files as $file)
			{
				?>
				<li class="image_wrap">
					<a href="#" class="delete_file_link" data-file_id="<?php echo $file->id?>">Delete</a>
					<strong><?php echo $file->title?></strong>
					<br />
					<?php echo $file->filename?>
				</li>
				<?php
			}
			?>
		</ul>
	</form>
	<?php
}
else
{
	?>
	<p>No Files Uploaded</p>
	<?php
}
?>

This loops through the files and displays the title and filename of each. We also display a delete link, which include a data attribute of the file ID.


Deleting the File

To round off the tutorial, we’ll add in the functionality to delete the file, also using AJAX.

The JavaScript

Add the following in the document ready function:

$('.delete_file_link').live('click', function(e) {
	e.preventDefault();
	if (confirm('Are you sure you want to delete this file?'))
	{
		var link = $(this);
		$.ajax({
			url			: './upload/delete_file/' + link.data('file_id'),
			dataType	: 'json',
			success		: function (data)
			{
				files = $(#files);
				if (data.status === "success")
				{
					link.parents('li').fadeOut('fast', function() {
						$(this).remove();
						if (files.find('li').length == 0)
						{
							files.html('<p>No Files Uploaded</p>');
						}
					});
				}
				else
				{
					alert(data.msg);
				}
			}
		});
	}
});

It’s always a good idea to get a user confirmation when deleting information.

When a delete link is clicked, we display a confirm box asking if the user is sure. If they are, we make a call to /upload/delete_file, and if successful, we fade it from the list.

The Controller

Like above, the url we are calling is /upload/delete_file/, so create the method delete_file, and add the following code:

public function delete_file($file_id)
{
	if ($this->files_model->delete_file($file_id))
	{
		$status = 'success';
		$msg = 'File successfully deleted';
	}
	else
	{
		$status = 'error';
		$msg = 'Something went wrong when deleteing the file, please try again';
	}
	echo json_encode(array('status' => $status, 'msg' => $msg));
}

Again, we let the model do the heavy lifting, echoing out the output.

The Model

We’re now at the final piece of the puzzle: our last two methods.

public function delete_file($file_id)
{
	$file = $this->get_file($file_id);
	if (!$this->db->where('id', $file_id)->delete('files'))
	{
		return FALSE;
	}
	unlink('./files/' . $file->filename);
	return TRUE;
}

public function get_file($file_id)
{
	return $this->db->select()
			->from('files')
			->where('id', $file_id)
			->get()
			->row();
}

Because we only pass the ID, we need to get the filename, so we create a new method to load the file. Once loaded, we delete the record and remove the file from the server.

That’s it, tutorial complete! If you run it, you should be able to upload a file, see it appear, and then delete it; all without leaving the page.


Final Thoughts

Obviously, the views can do with some prettying up, but this tutorial should have given you enough to be able to integrate this into your site.

There are a few shortcomings to this method, however:

  • You can only upload one file at a time, but this can rectified easily by using a service like Uploadify.
  • There is no progress bar built into the script.
  • We could reduce the SQL calls by updating the files div upon file upload, instead of fully replacing them.

Thanks for reading!


June 24 2011

14:42

Integrating Two-Factor Authentication with CodeIgniter

Advertise here

With the recent string of high profile break-ins (hacks) at Sony and other companies, it’s time you took a second look at the security of your website. Two-factor authentication is a step in the right direction to securing your website from attackers. In this tutorial, we’ll take a look at implementing this in our CodeIgniter application.


What is Two-Factor Authentication?

Two-factor authentication requires users to use something they know, such as a username and password, and something they have, like a phone, to log in.

Lately, companies like Google and Facebook have been rolling out two-factor authentication for their users. Other services, like MailChimp, are using alternate forms of two-factor authentication to help thwart attackers. But still, what specifically is two-factor authentication?

Two-factor authentication is a way of proving your identity based on your username and password as well as a physical device that you can carry with you.

Duo supports push notifications
Duo’s mobile application supports push notifications for authentication!

This makes it much harder for crooks to steal your identity, since they will need access to your phone or hardware token – not just your login credentials.

Lucky for you, Duo Security offers a free two-factor service ideal for anybody looking to protect their website.

Not only is Duo free, but it’s full of features. They let you authenticate in a variety of ways, including:

  • Phonecall authentication
  • SMS-based tokens
  • Mobile app token generator
  • Push-based authentication
  • Hardware tokens available for purchase

Step 1: Setup

Setup CodeIgniter

If you haven’t worked with CodeIgniter before, I highly recommend that you check out theCodeIgniter From Scratch series first.

This tutorial will build on the Easy Authentication with CodeIgniter tutorial. This tutorial will be much easier for you to understand if you complete the previous tutorial before continuing. We will be using the files from that tutorial as our starting point.

Please verify that your config/autoload.php has the following helpers being loaded.

$autoload['helper'] = array('url', 'form');

Create an Account

Head over to Duo Security, and sign up for an account.

They offer a free plan for open source projects, and for sites with less than 10 Duo users (A Duo user is someone who will be using the two-factor authentication to log in).

Create an Integration

After registering, you need to log in to Duo and create an integration. Once logged in, click on integrations on the side panel to pull up the integrations page. From there, click the “New Integration” button.

Make sure the integration you create is a Web SDK integration. This will allow you to use their PHP API with CodeIgniter.

The integration name is only used on Duo’s website. This is just a way for you to identify your integration. Duo has a getting started guide that explains how to set up an integration.

Download the Web SDK

In addition to setting up an integration, you’ll need to download the Web SDK.

There are two pieces of the SDK that we’ll need: A PHP file (duo_web.php) and a JavaScript file. Please note that the JavaScript has a jQuery dependency and the bundled JavaScript comes with jQuery.

We will be using the bundled JavaScript, but note that if you aren’t, jQuery must be loaded before the JavaScript provided by Duo. For more information on the Web SDK and how it works, view the documentation at http://www.duosecurity.com/docs/duoweb


Step 2: Modifications for Security

After finishing the Easy Authentication with CodeIgniter tutorial, you should have a basic login system in place.

Better Hashing

As a first step, we’ll add a strong hashing function to the database. Openwall has a nice PHP hashing library that implements bcrypt. The latest version of phpass is 0.3 at the time of this article.

Go ahead and download phpass from their website: http://openwall.com/phpass/. After downloading and unarchiving the folder, you’ll need to place that in your libraries folder.

We’ll now need to make our own library file as an interface to phpass. Create a new library file, named password.php. Our library will have two functions:

  • a hash function to rehash the old passwords
  • a check_password function to compare hashes with plaintext passwords.
require_once('phpass-0.3/PasswordHash.php');

class Password {

  var $hasher;

  function __construct()
  {
    // 8 is the hash strength.  A larger value can be used for extra security.
    // TRUE makes the passwords portable.  FALSE is much more secure.
    $this->hasher = new PasswordHash(8, TRUE);
  }

 function hash($pass)
 {
    return $this->hasher->HashPassword($pass);
 }

 function check_password($pass, $hash){
    return $this->hasher->CheckPassword($pass, $hash);
 }
}

The require_once() statement ensures that we’ll be able to use the PasswordHash class from phpass.

PasswordHash takes two arguments in its constructor:

  • a number indicating hash strength
  • a boolean as to whether or not the passwords should be portable.

In this case, we’re going to make our passwords portable.

This essentially means that the hash isn’t as strong, but if we ever need to switch servers or move the database, we can make a copy. If we don’t use a portable hashing scheme, we run the risk of having all of our users create new passwords if the database is moved.

Note: Even though we’re implementing a stronger hashing function, you should still require users to have a strong password.

Altering the Admin Model

   public function verify_user($email, $password)
   {
      $q = $this
            ->db
            ->where('email_address', $email)
            ->limit(1)
            ->get('users');

      if ( $q->num_rows > 0 ) {
         $result = $q->row();
         $this->load->library('password');

         //Make sure the hashes match.
         if($this->password->check_password($password, $result->password)){
          return $result;
         }
      }
      return false;
   }

Previously, we were selecting the user by the email address and the hashed password. Now we’re pulling the user from the database based on the email address. This means we have to validate the password before we can return the user.

After we’ve pulled the user from the database, we’ll load the password library we just created and verify that the entered password matches the hashed password.

If the two passwords match, we proceed to return the user, otherwise, we return false.

Be sure to use the password library to hash a new password for yourself. The passwords in your database will be invalid now!

Altering the Users Table

We’re going to add a basic permission field to the database. This permission will determine whether or not the user will log in with two-factor authentication.

We need to add a column to the users table for two-factor permissions. You can do this via phpMyAdmin, or by running the following SQL.

ALTER TABLE users ADD two_factor_permission BOOLEAN NOT NULL;

A value of 1 in the permission column will make the user use two-factor authentication.

The SQL will add a boolean column to the users table. We’ll use this to require users to use two-factor authentication, or to bypass it.

If you did this right, you should see a new column in your users table. You’ll then need to update a current record, or insert a new record that sets two_factor_permission to true (1).

If this column is set to false (0), the user will be able to bypass two-factor authentication. This is ideal for users who don’t need the same level of security as an administrator.


Step 3: Using the Permission Setting

We’ll need a way to bypass secondary authentication, as well as a way to insert a secondary authentication step to the login process.

Bypassing Secondary Authentication

First off, we’ll need a way to bypass secondary authentication. This means that we’ll need to inspect the user in the admin controller.

    if ( $res !== FALSE ) {
        $_SESSION['username'] = $res->email_address;
        if ( $res->two_factor_permission ) {
          $this->_second_auth($res->email_address);
          return;
        }
        else {
          $_SESSION['logged_in'] = TRUE;
          redirect('welcome');
        }
    }

This checks to see if the user should be logged in with our two-factor system.

If the user should be using two-factor authentication, we want them to go to the secondary authentication page without logging them in.

Instead of redirecting the user, we can call the _second_auth() function and have that load the page. The “return” statement avoids loading the login form.

We’ve created a new session variable logged_in which we will use to verify that the user has been logged in. This means we need to make some changes to the redirects.

Fixing the Redirects

There are two redirects that need to be changed: the first is in the index function of the admin controller.

if ( isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === TRUE ) {
  redirect('welcome');
}

The other is in the welcome controller. We need to make sure that the user isn’t logged in before redirecting.

if ( !isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== TRUE ) {
  redirect('admin');
}

Inserting Secondary Authentication

Now we need to handle the secondary authentication.

In the admin/index function, we call _second_auth(), so let’s write a basic function.

  public function _second_auth ($username)
  {
    echo "Welcome $username, you are looking at a secondary authentication page.";
  }

Step 4: Constructing the View

Traditional authentication systems treat logins as a single step process.

User enters username and password, then is logged in.

Duo gives us a bit of JavaScript and HTML to inject between the two steps. This means we’ll need to create a view with the required code.

User enters username and password, then is prompted for phone verification, then is logged in.

Let’s create a new view, called second_auth.php in the views folder. We’ll need to insert the the iframe and JavaScript provided by Duo to make it work.

You should create a page with the basic HTML structure. The following can be placed in the body:

        <iframe id="duo_iframe" width="100%" height="500" frameborder="0"></iframe>
        <script type="text/javascript" src="/path/to/Duo-Web-v1.js" ></script>

In a typical setup, you would keep all your JavaScript in a resource folder. Here, we’ve put a resources folder in the root of our site, with a ‘js‘ sub-folder that contains the Web SDK JavaScript file.

Our src will look like:

src="<? echo base_url(); ?>resources/js/Duo-Web-v1.js"

We also need to add this second bit of JavaScript.


We’ll generate this data from the controller shortly.

Inserting a Form

If you followed the previous tutorial, you should have configured CodeIgniter to protect against CSRF.

Because the JavaScript will post data to our controller, CodeIgniter will be looking for the CSRF token. If we don’t have this token, we’ll get an error.

The JavaScript we’re using will submit a form with the id “duo_form“. All we need to do is create it.

echo form_open('admin', array('id'=> "duo_form"));
echo form_close();

By using the form class, CodeIgniter will automatically inject the token. When the form gets posted, CodeIgniter will find the token and let us continue.


Step 5: Preparing the Data

Back in the admin controller, we need to generate some data in our _second_auth() function.

The host is the API URL that you were provided with when you signed up with Duo. This URL should look something like api-xxxxxxxx.duosecurity.com (where ‘xxxxxxxx’ is a unique string tied to your Duo account).

$data['host'] = "api-xxxxxxxx.duosecurity.com";

Remember to replace the host with your specific URL. The above URL will not work.

The post action is the URL that will be handling the response once the user has attempted to authenticate with Duo.

We’ll create another function in the admin controller to handle the post-back. For now, we’ll name the function process_second_auth().

  $data['post_action'] = base_URL() . "admin/process_second_auth";

Loading the PHP Web SDK

Make sure you rename ‘duo_web.php’ to ‘duo.php’ to avoid CodeIgniter errors.

If you haven’t downloaded the latest copy of duo_web.php, you can get it from Duo’s Web SDK GitHub page.

Because the Web SDK comes as a PHP class, we can rename it to “duo.php” and place it in our “application/libraries” folder.

After you’ve placed the file into the libraries folder, we can load it in our controller.

  public function _second_auth($username)
  {
    $this->load->library('duo');

    $data['host'] = "api-xxxxxxxx.duosecurity.com";
    $data['post_action'] = base_URL() . "admin/process_second_auth";

    echo "Welcome $username, you are looking at a secondary authentication page.";
  }

Generating the Signed Request

To understand how to generate sig_request, you must understand what we’re generating.

The $akey variable needs to be at least 40 characters long, otherwise the Duo library will return an error!

The Duo Web SDK creates two signed tokens, one with the secret key they give you, another with an application key that you make up.

sig_request is a combination of the two tokens.

By creating your own application key you will have a second layer of security. An attacker will need both the secret key from Duo and your personal application key to spoof a token.

Now we’ll generate the ‘sig_request’. Duo will provide you with an integration key and secret key when you create an integration.

Make sure to replace the below text with the integration key and secret key given to you. You need to make up your own secret key. It needs to be at least 40 characters long, and should be as random as possible.

public function _second_auth($username)
{
  $this->load->library('duo');

  // Duo Integration Key
  $ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY";

  // Duo Secret Key
  $skey = "REPLACE WITH YOU DUO SECRET KEY";

  // Personal Application Key
  $akey = "CREATE AN APPLICATION KEY";

  $data['host'] = "api-xxxxxxxx.duosecurity.com";
  $data['post_action'] = base_URL() . "admin/process_second_auth";
  $data['sig_request'] = $this->duo->signRequest($ikey, $skey, $akey, $username);

  echo "Welcome $username, you are looking at a secondary authentication page.";
}

Duo’s signRequest() will generate the tokens and return them as a string to pass to sig_request.

Now we need to load the data into the view we created earlier.

public function _second_auth($username)
{
  $this->load->library('duo');

  // Duo Integration Key
  $ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY";

  // Duo Secret Key
  $skey = "REPLACE WITH YOUR DUO SECRET KEY";

  // Personal Application Key
  $akey = "CREATE AN APPLICATION KEY";

  $data['host'] = "api-xxxxxxxx.duosecurity.com";
  $data['post_action'] = base_URL() . "admin/process_second_auth";
  $data['sig_request'] = $this->duo->signRequest($ikey, $skey, $akey, $username);

  $this->load->view('second_auth', $data);
}

If you attempt to login now, you should see this page:

Duo Enrollment Page

This is the enrollment form. You can enroll your cell phone here, but we don’t have anything to process the secondary authentication so it won’t log you in.

If you don’t see anything at all, view the page source for error messages. Any errors with the data will be displayed in the <script> tag.

If it says, “Access Denied”, make sure that you have entered the integration and secret key from Duo Security’s website.


Step 6: Processing Secondary Authentication

We’ve set up our post action to be admin/process_second_auth, so we need to create a process_second_auth() function.

public function process_second_auth()
{
  if ( isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === TRUE ) {
    redirect('welcome');
  }
}

Since this function will have its own URL, we need to redirect logged in users.

We have to load the Duo library again to validate the data.

$this->load->library('duo');

// Same keys used in _second_auth()
$ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY";
$skey = "REPLACE WITH YOUR DUO SECRET KEY";
$akey = "REPLACE WITH YOUR APPLICATION KEY";

We’ll be needing the same $ikey, $skey and $akey from the _second_auth() function to validate the posted data.

The JavaScript posts back a sig_response from the Duo servers.

$sig_response = $this->input->post('sig_response');
$username = $this->duo->verifyResponse($ikey, $skey, $akey, $sig_response);

Once we’ve pulled sig_response from the posted data, we’ll run it through the verifyResponse() function. This will return NULL if the tokens don’t match, or a username if they are valid.

if ( $username ) {
  $_SESSION['logged_in'] = TRUE;
  redirect('welcome');
}
else{
  redirect('admin');
}

Lastly, we’ll verify that a username was returned, and finish logging them in by setting the value of $_SESSION['logged_in'] to true.

All together the function should look like this:

public function process_second_auth()
{
  if ( isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === TRUE ) {
    redirect('welcome');
  }

  $this->load->library('duo');

  // Same keys used in _second_auth()
  $ikey = "REPLACE WITH DUO'S INTEGRATION KEY";
  $skey = "REPLACE WITH DUO'S SECRET KEY";
  $akey = "REPLACE WITH YOUR APPLICATION KEY";

  $sig_response = $this->input->post('sig_response');
  $username = $this->duo->verifyResponse($ikey, $skey, $akey, $sig_response);

  if ( $username ) {
    $_SESSION['logged_in'] = TRUE;
    redirect('welcome');
  }
  else{
    redirect('admin');
  }
}

Now you should be able to login with two-factor authentication, go ahead and try it out!


Conclusion

Hopefully you’ve set up your own two-factor authentication system for CodeIgniter!

What else could you do? There is plenty to do in terms of security, but the largest improvement would be tracking user actions.

A good security system isn’t only secure: it will help you identify where a vulnerability came from. You should keep track of login attempts, and other actions to make identifying attackers easier.

Thanks for reading! If you’re having trouble, leave a post in the comments.

June 03 2011

16:07

Quick Tip: Integrate Compass into an Existing CodeIgniter Project

Advertise here

I was recently asked about how to use Compass in an existing CodeIgniter project. It seems that the emailer was under the impression that Compass was made for Ruby and Rails. But that’s not the case at all!

Note that Ruby will need to be installed on your system in order for Compass to work correctly. It’s installed by default on a Mac. Otherwise, the easiest way to install the latest version of Ruby is with RVM. Refer here for detailed instructions.

Choose 720p for optimal viewing.
Subscribe to our YouTube and Blip.tv channels to watch more screencasts.

Let us walk you through the process of getting started with Sass and Compass from scratch.

May 26 2011

22:55

Easy Authentication with CodeIgniter

Advertise here

In this in depth “screencast of the week,” I’ll take you through the process of building an authentication system with CodeIgniter. Need to restrict access to certain parts of your website to only those who’ve logged in? This tutorial will teach you how!


You’ll Learn About:

  • The form helper
  • The form validation library
  • Sessions
  • CodeIgniter best practices
  • Authentication
  • Active record
  • Working with MySQL databases

Part 1

Press the HD button for a clearer picture.
Subscribe to our YouTube and Blip.tv channels to watch more screencasts.

Part 2

Press the HD button for a clearer picture.
Subscribe to our YouTube and Blip.tv channels to watch more screencasts.

April 21 2011

14:55

Protect a CodeIgniter Application Against CSRF


In today’s tutorial, we will learn how to painlessly protect your CodeIgniter (pre 2.0) application against Cross-Site Request Forgery attacks. The library we’ll be creating today will automate all of the protection mechanisms, making your site stronger and more secure.


Step 1 - Understanding the Attack Vector

Cross-Site Request Forgery attacks are based on unprotected forms on your sites.

An attacker could create a bogus form on his site – for example a search form. This form could have hidden inputs that contain malicious data. Now the form isn’t actually sent to the attacker’s site to perform the search; in reality, the form points to your site! Since your website will trust that the form is genuine, it goes through and executes the requested (and perhaps malicious) actions.

Imagine that a user is logged into your site, and is redirected to the attacker’s site for some reason (phishing, XSS, you name it). The attacker’s form could point to your account deletion form on your site. If the user performs a “search” on the attackers site, his account will then be deleted without him knowing!

There are numerous ways to prevent these sorts of attacks.

  • Check the HTTP Referer header and see if it belongs to your site. The problem with this method is that not all browsers submit this header (I personally had this problem once with IE7); it could be forged anyway.
  • Another method (the one we will use), is to include a random string (a “token”) on each form, and store that token on the user’s session. On each POST request, compare the submitted token to the one on store, and, if they differ, deny the request. Your site still needs to be protected against XSS though, because if it’s not, this method becomes useless.

Step 2 - Planning

We’ll need to do three things for each request:

  • If the request is a POST request, validate that the submitted token.
  • Generate a token in case there isn’t one.
  • Inject the token into all forms. This makes the method seamless and painless, since no modification is needed on your views.

To do this automatically, we’ll use CodeIgniter hooks. Hooks allow us to execute all actions on different parts of the request. We’ll need three:

  • post_controller_constructor – To check the submitted token, we’ll need a post_controller_constructor hook. Hooking this action before this event doesn’t give us access to CodeIgniter’s instance correctly.
  • Generate the Token – To generate the token, we’ll use the same hook as before. This allows us to have access to it in case we needed to print it manually in our views.
  • display_override – To inject the token automatically in our views, we’ll need to use the display_override hook. This is a tricky hook though, since, as its name implies, it overrides the display of the views. We need to output the content ourselves if we use this hook (check the CodeIgniter documentation for more info).

Step 3 - Token Generation

Let’s get started. We’ll go step by step in order to explain everything as thoroughly as possible. We’ll create the method that generates the token first, so we can test everything correctly afterwards. Create a file in your system/application/hooks folder called “csrf.php“, and paste the following code:

<?php
/**
 * CSRF Protection Class
 */
class CSRF_Protection
{
  /**
   * Holds CI instance
   *
   * @var CI instance
   */
  private $CI;

  /**
   * Name used to store token on session
   *
   * @var string
   */
  private static $token_name = 'li_token';

  /**
   * Stores the token
   *
   * @var string
   */
  private static $token;

  // -----------------------------------------------------------------------------------

  public function __construct()
  {
    $this->CI =& get_instance();
  }
}

Hopefully, what we’ve added above should look rather basic to you. We’re creating a class, called CSRF_Protection, an instance variable to hold the CodeIgniter instance, two static variables to hold the name of the parameter that will store the token, and one to store the token itself for easy access throughout the class. Within the class constructor (__construct), we simply retrieve the CodeIgniter instance, and store it in our corresponding instance variable.

Note: The “name of the parameter” is the name of the field that holds the token. So on the forms, it’s the name of the hidden input.

After the class constructor, paste the following code:

/**
 * Generates a CSRF token and stores it on session. Only one token per session is generated.
 * This must be tied to a post-controller hook, and before the hook
 * that calls the inject_tokens method().
 *
 * @return void
 * @author Ian Murray
 */
public function generate_token()
{
  // Load session library if not loaded
  $this->CI->load->library('session');

  if ($this->CI->session->userdata(self::$token_name) === FALSE)
  {
    // Generate a token and store it on session, since old one appears to have expired.
    self::$token = md5(uniqid() . microtime() . rand());

    $this->CI->session->set_userdata(self::$token_name, self::$token);
  }
  else
  {
    // Set it to local variable for easy access
    self::$token = $this->CI->session->userdata(self::$token_name);
  }
}

Step by step:

  • We load the session library, in case it’s not being loaded automatically. We need this to store the token.
  • We determine if the token was already generated. If the userdata method returns FALSE, then the token is not yet present.
  • We generate a token and store it in the class variable for easy access. The token could be almost anything really. I used those three functions to ensure that it’s very random.
  • We then store it in the session variable with the name configured previously.
  • If the token was already present, we don’t generate it and instead store it in the class variable for easy access.

Step 4 - Token Validation

We need to ensure that the token was submitted, and is valid in case the request is a POST request. Go ahead and paste the following code into your csrf.php file:

/**
 * Validates a submitted token when POST request is made.
 *
 * @return void
 * @author Ian Murray
 */
public function validate_tokens()
{
  // Is this a post request?
  if ($_SERVER['REQUEST_METHOD'] == 'POST')
  {
    // Is the token field set and valid?
    $posted_token = $this->CI->input->post(self::$token_name);
    if ($posted_token === FALSE || $posted_token != $this->CI->session->userdata(self::$token_name))
    {
      // Invalid request, send error 400.
      show_error('Request was invalid. Tokens did not match.', 400);
    }
  }
}
  • Above, we validate the request, but only if it’s a POST request, which means that a form was, in fact, submitted. We check this by taking a look at the REQUEST_METHOD within the $_SERVER super global.
  • Check if the token was actually posted. If the output of $this->CI->input->post(self::$token_name) is FALSE, then the token was never posted.
  • If the token wasn’t posted or if it’s not equal to the one we generated, then deny the request with a “Bad Request” error.

Step 5 - Inject Tokens into the Views

This is the fun part! We need to inject the tokens in all forms. To make life easier for ourselves, we are going to place two meta tags within our <head> (Rails-like). That way, we can include the token in AJAX requests as well.

Append the following code to your csrf.php file:

/**
 * This injects hidden tags on all POST forms with the csrf token.
 * Also injects meta headers in <head> of output (if exists) for easy access
 * from JS frameworks.
 *
 * @return void
 * @author Ian Murray
 */
public function inject_tokens()
{
  $output = $this->CI->output->get_output();

  // Inject into form
  $output = preg_replace('/(<(form|FORM)[^>]*(method|METHOD)="(post|POST)"[^>]*>)/',
                         '$0<input type="hidden" name="' . self::$token_name . '" value="' . self::$token . '">',
                         $output);

  // Inject into <head>
  $output = preg_replace('/(<\/head>)/',
                         '<meta name="csrf-name" content="' . self::$token_name . '">' . "\n" . '<meta name="csrf-token" content="' . self::$token . '">' . "\n" . '$0',
                         $output);

  $this->CI->output->_display($output);
}
  • Since this is a display_override hook, we need to retrieve the generated output from CodeIgniter. We do this by using the $this->CI->output->get_output() method.
  • To inject the tags in our forms, we’ll use regular expressions. The expression ensures that we inject a hidden input tag (which contains our generated token) only into forms with a method of type POST.
  • We also need to inject our meta tags into the header (if present). This is simple, since the closing head tag should only be present once per file.
  • Lastly, since we’re using the display_override hook, the default method to display your view will not be called. This method includes all sorts of things, which we should not – just for the purposes of injecting some code. Calling it ourselves solves this.

Step 6 - Hooks

Last, but not least, we need to create the hooks themselves – so our methods get called. Paste the following code into your system/application/config/hooks.php file:

//
// CSRF Protection hooks, don't touch these unless you know what you're
// doing.
//
// THE ORDER OF THESE HOOKS IS EXTREMELY IMPORTANT!!
//

// THIS HAS TO GO FIRST IN THE post_controller_constructor HOOK LIST.
$hook['post_controller_constructor'][] = array( // Mind the "[]", this is not the only post_controller_constructor hook
  'class'    => 'CSRF_Protection',
  'function' => 'validate_tokens',
  'filename' => 'csrf.php',
  'filepath' => 'hooks'
);

// Generates the token (MUST HAPPEN AFTER THE VALIDATION HAS BEEN MADE, BUT BEFORE THE CONTROLLER
// IS EXECUTED, OTHERWISE USER HAS NO ACCESS TO A VALID TOKEN FOR CUSTOM FORMS).
$hook['post_controller_constructor'][] = array( // Mind the "[]", this is not the only post_controller_constructor hook
  'class'    => 'CSRF_Protection',
  'function' => 'generate_token',
  'filename' => 'csrf.php',
  'filepath' => 'hooks'
);

// This injects tokens on all forms
$hook['display_override'] = array(
  'class'    => 'CSRF_Protection',
  'function' => 'inject_tokens',
  'filename' => 'csrf.php',
  'filepath' => 'hooks'
);
  • The first hook calls the validate_tokens method. This is not the only post_controller_constructor hook, so we need to add those brackets (“[]“). Refer to the documentation on CodeIgniter hooks for more info.
  • The second hook, which is also a post_controller_constructor, generates the token in case it hasn’t been generated yet.
  • The third one is the display override. This hook will inject our tokens into the form and the header.

Wrapping Up

With minimal effort, we’ve built quite a nice library for ourselves.

You can use this library in any project, and it will automagically protect your site against CSRF.

If you’d like to contribute to this little project, please leave a comment below, or fork the project on GitHub. Alternatively, as of CodeIgniter v2.0, protection against CSRF attacks is now built into the framework!

February 11 2011

05:33

CodeIgniter from Scratch: Search Results without Query Strings


In this episode of CodeIgniter from Scratch, we will implement search features, and display the results pages without the use of query strings. You can use these methods to keep your URL’s clean, and continue using the uri segments convention of the CodeIgniter framework.

Press the HD button for a clearer picture.

Subscribe to our YouTube page to watch all of the video tutorials!

November 17 2010

14:00

Basecamp Style Subdomains With CodeIgniter


CodeIgniter is a simple and lightweight PHP framework used to create powerful web applications. Today, we are going to do something nifty: we’ll combine user names and subdomains to make for a more cohesive user experience.

If you’re a bit confused, this feature allows your users to access their accounts by typing in a custom url, which maps to their user name, such as harbinger.yourapp.com.


Overview

In this tutorial, we are going to be creating both a front-end view and a back-end application view, similar to the configuration used in Basecamp, where visiting basecamphq.com shows the homepage, but visiting a subdomain displays the login page.

We will be using the fictional address nettutsapp.com, and will create a sample “dashboard” page; however, you could incorporate this into an existing project with relative ease.

basecamp-comapre

Before you begin, make sure that you have a web server with PHP installed. You also need to download CodeIgniter; in the example, I am using CodeIgniter 2.0, but the code should work on 1.7.2. So let’s get started!


Step 1: DNS Configuration

First, we need to configure our DNS settings to make all subdomains resolve to a single address. If you are working on a live server, then you will have to change your DNS settings with the company who handles your DNS. This is most commonly your web host or domain registrar.

To cover each configuration in this tutorial would take too much time. Instead, ask your host for some help to set up wildcard subdomains. You might expect to add something like the line below to your DNS configuration.

*.nettutsappapp.com.      IN  A    91.32.913.343

Instead, if you are working on a local server, adding a wildcard subdomain to the hosts file is quite tricky. What I prefer to do is add single entries for testing purposes. These can be deleted after you have finished. For our domain, we need to add four entries as follows:

  • 127.0.0.1     nettutsapp.com
  • 127.0.0.1     user1.nettutsapp.com
  • 127.0.0.1     user2.nettutsapp.com
  • 127.0.0.1     user3.nettutsapp.com

Mac Hosts Configuration

To do this on a Mac, open Terminal and type sudo nano /etc/hosts. Use the arrow keys to move to the bottom of the document, and add the entries to the bottom of the file. Once done, press Ctrl+X and Y to confirm the save.

dns-terminal1

Windows Hosts Configuration

If you are using Windows, browse to the directory C:\Program Files\system32\drivers\etc and open the hosts file in Notepad, or your preferred text editor. Add four entries, shown above, and save the file.

If you’ve made DNS changes to a live server, it will take a while before you notice any effect. If you made changes to your hosts file, the changes will be immediate.


Step 2: Apache Configuration

The aim here is to set up two Virtual Hosts in the Apache Configuration,:one serves the front end page (Basecamp Homepage), and the other serves the page seen when accessed via a subdomain (Dashboard Page).

To add new entries, you need to open the httpd.conf file, which can be found in the Apache installation directory. It’s often found in the bin/apache/conf folder. However, depending on your server configuration, the location may vary.

Once opened, you need to add the two entries, shown below. Be sure to change the DocumentRoot to a location of your choice, which you have created.

Note: Remember the wildcard and the different directory path on the second VirtualHost.

WAMP Users: I recommend reading this post, which describes how to set up VirtualHosts. You may also encounter permission problems; so I recommend placing your VirtualHost directories inside the www directory.

	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsappfront"
		ServerName nettutsapp.com
		ServerAlias nettutsapp.com

		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsappfront">
			Options -Indexes
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>

	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsapp"
		ServerName nettutsapp.com
		ServerAlias *.nettutsapp.com

		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsapp">
			Options -Indexes
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>

Once you have saved the file, you need to restart Apache for the changes to take effect.

Make sure that you have created the directories you specified in the httpd.conf file before starting the server.


Step 4: Testing Our Server Configuration

Before we test the configuration, place a basic html page in each of the directories you created earlier. Maybe add a single line of text to each, so you can differentiate them. I have copied an example for you to use.

<!DOCTYPE html>
<html lang="">
<head>
	<meta charset="utf-8">
	<title>NetTuts App Front</title>
</head>
<body>
	NetTutsApp Front
</body>
</html>

Next, open your favorite browser, and first check the address nettutsapp.com. If everything works, you should be looking at the page you placed in the ‘nettutsappfront‘ directory.

Next, check a subdomain, eg. user1.nettutsapp.com; this should show you the other page you created in the directory.

config-success

You can go on to check the other subdomains you specified in the hosts file, which should all show the page saved within our directory.

Step 5: CodeIgniter Installation

This tutorial assumes that you know how to install CodeIgniter. If not, you should take a look at this video tutorial by Jeffrey Way, which explains the process in detail.

Place the CodeIgniter files into our directory after deleting the html page we created before. If you are using CodeIgniter 1.7.2, you may want to take the application folder out of the system folder.

nettutsapp-ci

Test the installation by browsing to the URL user1.nettutsapp.com, and you should see the CodeIgniter Welcome Page.

nettutsapp-ci-welcome

Step 6: Setting up CodeIgniter

Set up CodeIgniter as you normally would, as described in this tutorial. You may want to remove the index.php from the URL, autoload some libraries or helpers, etc. For the purposes of this tutorial, we need to autoload the database library and the url helper. Open the autoload.php file in the config directory, and add the relevant entries.

We also need to change the default controller to one which we will be making, called dashboard. This value can be changed within the /config/routes.php file.

Base_url

For the user subdomains, we need to make the base_url variable dynamic, as the application will be receiving requests from a number of potential subdomains.

The easiest way to do this is by using the HTTP_HOST variable. Open the config.php file, and find the variable $config['base_url'], and replace it with the following code:

if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on"){$ssl_set = "s";} else{$ssl_set = "";}
$config['base_url'] = 'http'.$ssl_set.'://'.$_SERVER['HTTP_HOST'];

This code allows for HTTPS connections, however, if you never plan on using HTTPS, you can simplify it to base_url = $_SERVER['HTTP_HOST'].

Database Settings

Before we go ahead and add the database settings into our CodeIgniter application, we need to create both the database and a sample table.

This example application uses one database and one table. This table will hold all the subdomains currently assigned, and some basic information about them. If you’ve decided to use this code in your own application, you’ll have to generally assign multiple users to a single subdomain, however that database schema is beyond the scope of this tutorial.

The table is named nt_subdomains, within the database ntapp, and has four fields:

  • subdomain_id(primary, auto_increment)
  • subdomain_name
  • user_fname
  • user_sname

I have also populated the table with two records, which match the subdomains we’ve added to our hosts file:

php-my-admin

Now we can open the database config, file found in /application/config/database.php, and edit the following values so that they match your personal configuration settings.

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root'; //MAMP default
$db['default']['password'] = 'root'; //MAMP default
$db['default']['database'] = 'ntapp';

And we’re done setting up our CodeIgniter installation. Let’s start using the subdomains in our application.


Step 7: Creating Our Controllers and Views

For this application, we are going to create two controllers. The first is an error controller, which displays an error if the subdomain has not been registered for use in the application. The other controller is our main dashboard controller, which is what the user sees if the subdomain has been added to our database.

Error Controller

Let’s go ahead and create our error controller. First, create a new file in the /application/controllers directory, and call it error.php.
Note: The name of the file is important

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Add the code above to our new error.php file. The index function loads a view called ‘error‘, which we will be creating later.

Dashboard Controller

Now we need to create the main dashboard controller, which will be loaded when a user enters one of the subdomains. The controller will then check whether the subdomain has been registered, and will redirect as necessary. We’ll add this code later, but first, we need to create the basic controller.

Create a new file within the controllers directory, and name it dashboard.php. Within this file, we need to create the controller and load the dashboard view. Copy the code below and save the file.

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('dashboard');
	}
}

Error View

The error page will be displayed when a user tries to access a subdomain, which has not been registered for use by the application. For the purposes of the tutorial, simply create a basic page, displaying the message Subdomain Not Registered. Add the code below to a new file called error.php and save it within the application/views folder.

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Dashboard View

initial-dashboard

For the time being, we will only be creating a basic dashboard page. You can use the same structure as the error view, and just change it to read Nettuts Dashboard, or something along those lines. Save the page as dashboard.php, within the application/views folder.

Test the two views by visiting the URLs:

  • user1.nettutsapp.com/index.php/error
  • user1.nettutsapp.com/index.php/dashboard

Working? Let’s move on.


Step 8: Extending Our Dashboard Controller (Part 1)

The next step is to extract the subdomain name in our controller so we can use it in a database query.

We are going to insert our subdomain checking code into the construct function within the dashboard controller. (Underneath the parent::Controller()). This means that the subdomain will be checked when any of the functions within the dashboard controller are accessed.

The easiest way to extract the subdomain name is to use the PHP explode function, and set the delimiter to ‘.’. As we only need the first part, we can split it into two parts, and then assign the first part (the subdomain name) to a variable.

To test this, we can echo the variable out in the controller itself. See the code below:

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();

		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2); //creates the various parts
		$subdomain_name = $subdomain_arr[0]; //assigns the first part
		echo $subdomain_name; // for testing only
	}

}

Access your subdomain URLs, and you should see the correct subdomain echoed on your page, as below.
Note: You can delete the echo statement now.

subdomain-parse1

Now that we have access to the subdomain name in our controller, we can check to see if it has been added the table we created earlier.

We will be using CodeIgniter’s ActiveRecord Class to build our queries, which will check the table for the accessed subdomain. If it is present, then the user will be able to access the dashboard page. If, on the other hand, the subdomain has not been entered, then they are denied access, and are then redirected to the error page we created earlier.

For this tutorial, we won’t be using models as it makes the tutorial much easier to follow. CodeIgniter is quite flexible in that it doesn’t force you to use them.

First, we need to assemble the query as show below. This code will only work in PHP5, as it uses method chaining; however, you can change it to your liking.

// adds on from rest of construct //
$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
$query = $this->db->get();

We can use the CodeIgniter function row() to check whether that subdomain exists in the table. If it doesn’t, then we need to use the redirect function to redirect our users to the error controller. The next part of the code is below:

// adds on from previous code //
if($query->num_rows() < 1)
		{
		redirect ('error');
		}

Let’s test this by accessing user1.nettutsapp.com, which should direct you to the dashboard page. Now, try user3.nettutsapp.com, which should redirect you to the error page as it was not entered into the table.

subdomain-comapre1

Step 9: Extending Our Dashboard Controller (Part 2)

Now we can use the information in the table to display specific information for each subdomain.

We’ll add to the index function in our dashboard controller. First, copy the subdomain name code and the database query we used before.

function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

	}

We are using CodeIgniter’s row() function to retrieve the result of the query. The row function returns a single result row, which means we don’t need to use a foreach loop; it’s unnecessary.

// adds on from rest of index function //
$subdomain_info = $query->row();

Then, assign the user_fname and user_sname column values to the array, $data, which is then passed to the view.

$data['fname'] = $subdomain_info->user_fname;
$data['sname'] = $subdomain_info->user_sname;
$this->load->view('dashboard', $data);

We can use these values within our view by using the variables $fname and $sname. Open the dashboard view and edit it to read:

	<p>Welcome to your dashboard
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>

And we’re done! Let’s test it.


Step 10: Testing

Try all of the URLs, and hopefully, if everything went according to plan, the results should be as follows:

  • nettutsapp.com → Front End Page
  • user1.nettutsapp.com → Dashboard (John Doe)
  • user2.nettutsapp.com → Dashboard (Steve Smith)
  • user3.nettutsapp.com → Error Page
finalresult

Controller and View Code

Here’s the complete cote used for our controllers and views:

Dashboard Controller

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();

		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

		if($query->num_rows() < 1)
		{
		redirect ('error');
		}

	}

	function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

		$subdomain_info = $query->row();
		$data['fname'] = $subdomain_info->user_fname;
		$data['sname'] = $subdomain_info->user_sname;
		$this->load->view('dashboard', $data);
	}
}

Error Controller

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Dashboard View

<html>
<head>
	<title>Dashboard : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Dashboard</h1>

	<p>Welcome to your dashboard
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>

</body>
</html>

Error View

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Conclusion

Of course, this tutorial describes only one way of obtaining this nifty functionality. I’m sure there are many more; so feel free to chime in with your thoughts and opinions in the comments section below.

November 10 2010

01:02

How to Create a Config Variables Loader in CodeIgniter: New Premium Tutorial


If you’ve been using CodeIgniter or another MVC framework for any length of time, you’ve probably started to realize the advantage of abstracting data and logic from presentation. But efficiency is not without its drawbacks, and, in the case of CodeIgniter, one of these drawbacks is the need to constantly bounce variables out of your controllers so that they are available within your views.

In this tutorial, I’ll show you a really cool way to eliminate this hassle. Become a Premium member to gain access to this tutorial, as well as hundreds of other tutorial, screencasts, and freebies from the Tuts+ network.

We’re going to build a config loader that automatically loads all of your important site variables and makes them available globally. Even more cool, your site variables will be stored in a separate config file that you can append or edit whenever you like. Not only will this save you a lot of time (and errors!), but it will help you develop a killer workflow that you can build on for all your projects. Lets get started!


Join Net Premium

Screencasts and Bonus Tutorials

For those unfamiliar, the family of Tuts+ sites runs a premium membership service. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies from Nettuts+, Psdtuts+, Aetuts+, Audiotuts+, Vectortuts+, and CgTuts+. For the price of a pizza, you’ll learn from some of the best minds in the business. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

October 27 2010

16:54

Turbocharge your ExpressionEngine 2 Education


ExpressionEngine, as a platform and a community, has seen a lot of growth recently. While there are some nice roundups out there about EE resources I thought it was time for a more relevant and up-to-date article to hit the streets. If you’re getting started, this set of resources will get you moving in the right direction. After all, I’ve walked this path myself thus far.


My Perspective

Before diving into the resources I should provide a bit of context to my approach to learning EE. I first looked at the software a few years ago and totally didn’t get it. I was already using the PHP framework CodeIgniter, made by the same company, and I saw no need to use EE if I could just build a CMS to do exactly what I needed. Regardless, I wanted to download and test out the software.

Straight out of the gate, I didn’t get it.

I was used to either WordPress or writing my own logic. ExpressionEngine installed with a bunch of “modules” and a few “custom fields” in which I could insert my data. I took a look at the official documentation and didn’t really understand how or why it was a powerful tool. After about 5-10 days of kicking the tires I just put it aside.

Fast Forward

Jump ahead two months, and I find myself back to testing out ExpressionEngine. This time, it was due to finding a series of tutorials on building a church website in EE. After reading the articles, I started to learn how EE was setup “out of the box” and where I could take it. Since reading those tutorials I haven’t put EE down and would consider myself an EE evangelist these days.

During my EE journey, I’ve discovered quite a few excellent resources and taken note of a few community leaders. Let’s dive in and see how they can help you learn ExpressionEngine 2.


(Possibly) Changing Mindsets

When I first dove into EE, I, as mentioned above, simply didn’t “get it.” Coming from WordPress, I was accustomed to working with a Title, Body and some extremely basic Custom Fields. I’d worked a lot with WP’s Categories, Tags, and Widgets, and was used to 1-click installs of templates and auto-updating software. EE is quite different…but I love almost every difference.

I won’t venture into explaining how things work in EE, but there are some great articles to check out. Firstly, I’d suggest reading “Switching Mindsets: From WordPress to ExpressionEngine,” by Mindy Wagner at Viget Labs. Her story is similar to mine in particular. Next I’d say, check out WordPress vs. ExpressionEngine: Apples and Oranges? by Marcus Neto. He talks about how the two handle content differently and provides excellent examples.

Okay, now that you’re eager to debate why one piece of software is “better” than the other, let’s change the topic slightly.


Community Websites

This year EllisLab, makers of ExpressionEngine and CodeIgniter, did something awesome. They welcomed some EE fan sites into the EllisLab family by making them “official community partners.” The sites collectively supply the EE community with the latest EE community news, short tips on using EE, a gallery of great EE-powered sites, articles on projects, the official repository of add-ons & more. Take a look at the community sites here:

And some great un-official community EE sites:


Official & Un-official Support

What I really love about the forums is the unofficial support.

EllisLab offers official support from their dedicated staff for any license holder of ExpressionEngine. If you’re having a problem with your site and can’t figure out what’s gone awry, they are good at helping figure things out. They provide this support, via their forums at ExpressionEngine.com. Official support is quite nice for software like this.

What I really love about the forums is the unofficial support. The community of EE users is awesome and I’ve learned a lot from other developers via the official EE Forums. I’ve been a fan of forums since my moderating days at Flashkit; so I naturally jumped into learning about EE there.


Train-ee

I can’t help but give Train-EE a section of its own here. If you’ll remember from this article’s introduction, I turned away from EE rather quickly, at first. It wasn’t until I read through a tutorial series on Building a Church Site that I really started to understand how to use EE.

Long time EE user Michael Boyink created Train-ee when he saw a void in the EE learning process. Since creating Train-ee, Mike has written two EE books, published numerous online text and video tutorials and created the only to-date classroom training course for EE. Mike is also working with EllisLab to make the process of learning EE more seamless and formalized.

In short, Train-ee is an excellent learning resource for ExpressionEngine. Start with some of the free stuff, but definitely purchase some of the commercial goods. The small amount you spend on training is probably nothing compared to the time you’ll save slaving through EE without it.


Other Free and Paid Learning

Train-ee, of course, isn’t the only place in town for learning EE. Here are a few more ways to learn EE both on and off the web.

Online Learning

I personally got a lot out of the EE Screencasts series by Ryan Irelan. He’s also working with other developers on premium tutorials that go beyond the basics. Keep your eyes on his site for additional videos down the road.

Speaking of Ryan, he has his hands in a lot of EE resources. He also runs official community partner site EE Insider where you can get all the latest EE news and quick tips. They do a great job of keeping the community informed. EE Insider also hosts a weekly ExpressionEngine chat most Wednesdays. It is an open chat where you can come and ask questions and give ideas.

Ryan also co-hosts the EE Podcast with Lea Alcantara. This is a weekly podcast where Ryan and Lea and the occasional guest dive deeper and discuss topics like “E-Commerce and ExpressionEngine” and “SEO, Search Engine Optimization, ExpressionEngine“. The EE Podcast is definitely a great way to stay informed on EE techniques.

If you’re looking to extend what EE can do out of the box, then the place to go is Devot:ee created by Ryan Masuga. They provide a catalog of nearly all public EE add-ons to date and even offer simple software support and commercial sales to developers who might not want to host that on their own. Devot:ee is the first place I go when looking to extend EE. If the add-on exists, they probably know about it.

Offline Learning

There are numerous opportunities to learn EE live and in person. For starters, there is the EECI conference, which just saw its 3rd occurrence (photo courtesy of Nate Croft, FortySeven Media). It’s the largest gathering of EE nerds that I’m aware of. The speakers are top notch, and it’s a big heap of fun. The next iteration is in New York in October of 2011.

Aside from the big EECI, there are other conference opportunities out there. Just last week, there was EE Camp in Denver, Colorado. This week, there is the online ExpressionEngine conference EngineSummit 2. Numerous cities also have meetups for ExpressionEngine, which are great ways to share and learn in a small, informal atmosphere.

A slightly different approach to in-person learning is hiring a professional consultant. It’s a service typically used by companies with in-house teams working with EE. For example my company, Focus Lab, LLC, often does private training and consulting on EE topics. If you find yourself in need of a private instructor, the ExpressionEngine community certainly has those resources available.

Buy a Book

The last place I want to touch on offline learning is published books. There are a few to choose from and it would be silly not to mention them. The aforementioned Michael Boyink and Ryan Irelan both have published books on ExpressionEngine 2. There is also a book by Leonard Murphey, which is published by Packt Publishing. Certainly consider checking them out if you’re a book reader.


Dive in to the Community

EllisLab, themselves, have said their favorite feature of EE is the community. I have to agree! They have two full time staff members dedicated to the community; so that should tell you a little about them. Getting involved in the EE community is easy. For me, it began on the official EE forums. From there, I started tweeting a lot about EE and then publishing some of my add-ons publically on GitHub. Here are a few places you can look out for EE’rs.


Who to Follow

Since you’re ready to dive into ExpressionEngine 2, I thought it’d be nice to share some developer names with you. You know, the guys who are consistently doing awesome work and sharing ideas with others. This is by no means meant to be a complete list, but here are a few developers to keep your eyes on:


Link Roundup

To preserve your precious mouse index finger’s strength today I’ve provided you with a roundup of the primary links here:

I’ve overloaded you with resources. Now go forth and learn ExpressionEngine!


Already a Seasoned EE Pro?

If you’re already a seasoned Expression Engine pro, did you know that Envato’s rapidly growing marketplace for code, CodeCanyon, very recently launched a new ExpressionEngine extensions category? We’ve launched with a handful of seed extensions, however, we’re actively seeking new authors and contributions.

There’s no better time to join, as we’ve recently increased our author rates, once again, to 50-70% of every sale. With countless authors making four+ figures in income every month, now is the perfect time to jump in. If you have any questions, leave a comment in this thread, and I (Jeffrey) will get back to you ASAP.

Premium EE Extensions on CodeCanyon

  • Mapper: Display Google Maps on your site with ease.
  • Widgets: Widgets is a ExpressionEngine 2.1 module that allows even your least experienced client or to manage chunks of intelligent content on there site without needing to learn loads of tags, HTML or call you in to help.
  • Multi-Language Support: This extension provides the foundation for multi-language support in your website.

October 22 2010

00:37

How to Create a Layout Manager with CodeIgniter: New Premium Tutorial


This Premium video, and companion article will teach you how to create a simple, yet powerful library to handle layouts in the popular CodeIgniter framework. The library you’ll create will allow you to maximize your efficiency, save time and code, modularize your views and even your Javascript and CSS files.

The basic functionality of this library will be very simple. We’ll take the contents of a view, render them with the appropriate data, then take the rendered content and assign it to a variable. Now, we’ll render the layout itself, and replace a part of the layout with the contents of this variable. Simple, but powerful enough.

The idea is to mimic the calls to $this->load->view(). When we call this method, we pass the name (and location) of our view, and then an array of data that will be accessible from the view. Here’s an example:

function method($url_param)
{
  $this->load->view('controller_views/method_view', array('url_param' => $url_param));
}

The above code will take the file system/application/views/controller_views/method_view.php, pass it the url_param variable, and then send it to the browser. Here’s where we come in. We will not send the content to the browser yet. Instead, we’ll send it to the layout, then to the browser. But how do we do that?

…Become a Premium member to follow along with this screencast/article and find out!


Join Net Premium

NETTUTS+ Screencasts and Bonus Tutorials

For those unfamiliar, the family of Tuts+ sites runs a premium membership service. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies from Nettuts+, Psdtuts+, Aetuts+, Audiotuts+, Vectortuts+, and CgTuts+ For the price of a pizza, you’ll learn from some of the best minds in the business. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

September 15 2010

21:14

How to Sell Digital Goods with CodeIgniter: New Premium Tutorial


In today’s tutorial, you’ll learn how to create a small web app to sell digital items (eg. eBooks) securely and accept payments from PayPal. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

How to Sell Digital Goods with CodeIgniter: New Premium Tutorial

Join Net Premium

NETTUTS+ Screencasts and Bonus Tutorials

For those unfamiliar, the family of Tuts+ sites runs a premium membership service. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies from Nettuts+, Psdtuts+, Aetuts+, Audiotuts+, Vectortuts+, and CgTuts+ For the price of a pizza, you’ll learn from some of the best minds in the business. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.


Other Awesome Premium Tuts you may Like

September 07 2010

14:14

CodeIgniter from Scratch: Displaying & Sorting Tabular Data


In today’s video tutorial, we are going to use CodeIgniter to pull information from a database and display it in a sortable table structure. This is a quite common task, especially inside admin areas, for displaying database records. We’ll be utilizing a few different utilities, such as the active records library and pagination.


Catch Up


Day 16: Displaying & Sorting Tabular Data

Day 16: Displaying & Sorting Tabular Data

Thanks for watching! Any questions/thoughts?

August 09 2010

16:52

Who Needs University? The Best Nettuts+ Screencast Training Courses


Education is expensive…very expensive! But, luckily, 95% of the tutorials and courses on Nettuts+ are free! And, should you require more training, a Tuts+ premium subscription is extremely cheap, at only $9 per month. Whether you’re hoping to learn jQuery, WordPress, CSS, Tumblr, PHP, CodeIgniter, or JavaScript, we’ve got you covered! Further, if screencasts are your thing, you’re particularly in luck, thanks to our in depth video courses, listed below!


1. Diving Into PHP

Diving Into PHP

Just as with the “jQuery for Absolute Beginners” series, you’ll start from scratch and slowly work your way up to some more advanced PHP topics; this is another incredible series that first aired on the ThemeForest Blog.

The Complete Series


2. Magento for Designers

Magento for Designers

Magento is a stunningly powerful e-commerce platform. In celebration of ThemeForest’s new Magento category, this mini-series will you teach how to get started with the platform: you’ll get to know the terminologies and learn how to set up a store and all related aspects of it; finally you’ll learn how to customize it to make it your very own.

The Complete Series


3. JavaScript from Null

JavaScript from Null (Premium)

Thanks to the wide adoption of libraries like jQuery and Mootools, JavaScript’s popularity has skyrocketed in the last few years. However, in the process, an interesting thing occurred: many newer developers are learning these libraries without taking the time to actually learn about raw JavaScript techniques. What percentage of jQuery users don’t know how to fade out an element with only raw JS? My guess is that it’s much higher than many would think.

If you want to truly understand the library you’re working with, and improve your skill-set, it’s vital that you learn the fundamentals of raw JavaScript. And this series will teach you what you need to know!

The Complete Series


4. Tumblr Theme Design – Start to Finish (Premium)

Tumblr Theme Design – Start to Finish (Premium)

Tumblr’s popularity over the last year has increased exponentially. The reason why is quite simple: Tumblr is flexible, powerful, and, most importantly, a pleasure to work with. Unfortunately, there aren’t many training resources available for the platform yet. In this video series, we’ll go through the process of taking a Tumblr theme, designed in Photoshop, and converting it into a fully working theme – in just a few hours.

The Complete Series

If you’re not already a Nettuts+ Premium member, you’ll want to sign up to get this course. You can view an introduction to it here.

  • Chapter 1: Intro
  • Chapter 2: Slicing the Design
  • Chapter 3: Creating the Markup and Adding the Tumblr Template Tags
  • Chapter 4: Adding the CSS
  • Chapter 5: Configuration Options
  • Chapter 6: @Font-Face and Custom Fonts
  • Chapter 7: Slide-out Panel – HTML and CSS
  • Chapter 8: Slide-out Panel – jQuery

5. CodeIgniter from Scratch

CodeIgniter from Scratch

After numerous requests, we launched a new screencast series on Nettuts+ that will focus exclusively on the CodeIgniter PHP framework. Over the course of 15 videos (so far!), you’ll learn how to use this framework.

The Complete Series


6. Regular Expressions for Dummies

If there’s one topic that most people agree is difficult to get into, it’s regular expressions. But fear not: you’ll get comfortable using this sometimes-confusing technology with these five screencasts.

The Complete Series

You can see the whole series here, and this is what you’ll get:


7. CSS: Noob to Ninja (Premium)

This exclusive premium video series will take you from a state of absolute CSS “noobness,” all the way up to ninja-status, capable of taking advantage of the latest CSS3 techniques. The series begins with the basics: the syntax, properties, etc. However, each new video expands upon the previous, as you work your way up and improve your skills.

The Complete Series

This series is for Premium members, but if you aren’t familiar with CSS, there’s no better way to learn! Get it here!

  • Part 1: Preparation
  • Part 2: CSS Properties
  • Part 3: Typography
  • Part 4: Floats
  • Part 5: Positioning
  • Part 6: Semantics, List Items, and Menus
  • Part 7: CSS Organizational Techniques
  • Part 8: Rounded Corners, Box Shadows, and Text Shadows
  • Part 9: CSS3 Gradients
  • Part 10: Custom Fonts with @font-face
  • Part 11: Taking Advantage of CSS Frameworks
  • Part 12: Extending CSS with LESS

8. jQuery for Absolute Beginners

jQuery for Absolute Beginners

So, everywhere you look, you see “jQuery this” and “jQuery that.” For the last year or so, this library has been the darling of the JavaScript world. But do you feel that you just can’t seem to learn the dang thing? Do you hate how the existing tutorials assume that you know WAY more than you actually do? If this rings true for you, I can help: check out the jQuery for absolute beginners series that first showed on the old ThemeForest Blog, and has since joined the Nettuts’ arsenal.

The Complete Series


9. WordPress for Designers

If you want to get into the WordPress community, we’ve got a great way to start: the WordPress for Designers series, from the old Themeforest Blog. You’ll learn everything from installing the platform to slicing a PSD file and turning it into a complete theme.

The Complete Series


10. The Ultimate Guide to Creating a Design and Converting it to HTML and CSS

The Ultimate Guide to Creating a Design and Converting it to HTML and CSS

This was a multi-part series across the Tuts+ sites, which demonstrated how to build a beautiful home page for a fictional business. We learned how to create the wireframe on Vectortuts+; we added color, textures, and effects on Psdtuts+; and we took our completed PSD, and converted it into a nicely coded HTML and CSS website.

The Complete Series


You’ll be a Pro in No Time!

Well, now you’re well on your way to becoming a well-trained web developer. What’s your favorite tutorial here on Nettuts+? Let us know in the comments!

If you enjoyed these screencasts over the last year or so, and would like to give back to Nettuts+, please do consider signing up for a Premium Tuts+ subscription. In addition to helping us out, you’ll gain access to source files, extra advanced tutorials and video series, and freebies…from all of the Tuts+ sites!

August 05 2010

20:31

CodeIgniter from Scratch: Profiling, Benchmarking & Hooks


In this 15th episode of the series, we are going to learn about three subjects: Profiling, Benchmarking and Hooks. You can use these tools to analyze your CodeIgniter applications performance, and figure out what part of the code you need to optimize. We are also going to make even further improvements to the Profiler library to suit our needs.


Catch Up


Day 15: Profiling, Benchmarking & Hooks

Premium Members: Download this Video ( Must be logged in)
Day 15

Thanks for watching! Any questions/thoughts?

June 30 2010

14:44

CodeIgniter from Scratch: Security


In this fourteenth episode of the series, our subject is ‘Security.’ We will go over topics such as: password encryption, message encoding/decoding, XSS filtering, output filtering, sql injection, session security, private controller methods and more.


Catch Up


Day 14: Security


Thanks for watching! Any questions/thoughts?

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...