Subscribe to RSS Subscribe to Comments

Matt Stone, that’s me

Techno Trance Mix Uploaded

After a request for some music from a good friend of mine I’ve started work on getting some of my old dj mixes uploaded for your listening pleasure.

The first one is a mix I recorded several years ago now and went down well with everyone who nabbed a free cd from me.  Usually I get tired of my own mixes pretty quickly but after a couple of years of not listening to this one it’s grown on me again :)   So, without further ado, here’s the link http://www.mattstone.me/audio/03062005.mp3 and for anyone who’s interested the tracklisting is as follows…

Artist Title Label
Mellow Trax Feat. Shaft Sway EDM
Miss Loony Explain(DJ Tatana Mix) Sirup
Nick Sentience Freedom Nukleuz
Chrome Ritmo Del Mundo Taach!
Cloudburst The Mission(Club Mix) Drizzly
Groovelikers Groovelike(Snuggle Duggle Mix) Drop Out
Tony Walker Fields of Joy(Flutlicht Mix) Drizzly
Muzz & Diggs World of Tomorrow(MD Re-edit) Subliminal Heights
Adelphoi A Better Tomorrrow Ascendant Heights
Helikopter Der Rotor(Manover Mix) Edel
DJ Session One meets Manuel Oetl Trip to Africa(Club Mix) Blutonium
D-Devils Sex & Drugs & House(Stormtraxx Mix) Byte
Sergeant Sam ??????? Storm Trance
Kaylab pt2 Here We Go(Jam X & De Leon Mix) ????

Using the Zend Framework ACL Library in Codeigniter

To kick my blog off good and proper I thought a tutorial on implementing the Zend Framework ACL library into a Code Igniter application would be a nice start.

In this post I will explain how to build simple access control functionality for your Code Igniter application using the Zend Framework ACL library. To follow this tutorial you will need a working installation of Code Igniter and a database. You will also need to download the Zend Framework.

Code Igniter and Access Control Lists

A lot of Code Igniter users have complained that the framework doesn’t come bundled with an access control component unlike other heavyweight frameworks such as Symfony and CakePHP. Personally I don’t see this as a major issue as the developers behind Code Igniter have deliberately kept it lean with unnecessary libraries being left out in favour of a solid and very usable core and not every web app needs access control.

In my current job access control was an essential requirement and, being the sole person responsible for choosing code igniter over other frameworks, it’s down to me to implement some form of access control into our app.

I started by looking at rolling my own but decided that instead of reinventing the wheel it would be far better to go with a tried and trusted solution hence my reason for opting for the Zend Framework ACL implementation.

Zend ACL

The Zend ACL implementation provides a flexible approach to Access Control Lists with a simple querying interface supplying either true or false. It’s up to the developer to decide how to implement their permissions but I’ll give an example based on the application (a CMS) I’m currently developing.

Getting Started

To start with I’ll link to the blog post that got me started… A very good primer for getting your ACL up and running using the Zend Framework and a database can be found at Jani’s blog it helped me no end and formed the basis for this write up. Now on to the nitty gritty…

Download the Zend framework and unzip it to your code igniter install in /system/libraries. You can leave the whole framework there if you want but if it’s just the ACL stuff you need you can remove everything except Acl.php, Exception.php and the Acl folder.

After that create a file called Acl.php in /system/application/libraries, open it up in your favourite editor and pop this code in it…

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require_once BASEPATH .'libraries/Zend/Acl.php';
class Acl extends Zend_Acl {
 
	function __construct() {
		$CI = &get_instance();
		$this->acl = new Zend_Acl();
 
		$CI->db->order_by('ParentId', 'ASC'); //Get the roles
		$query = $CI->db->get('user_roles');
		$roles = $query->result();
 
		$CI->db->order_by('parentId', 'ASC'); //Get the resources
		$query = $CI->db->get('user_resources');
		$resources = $query->result();
 
		$query = $CI->db->get('user_permissions'); //Get the permissions
		$permissions = $query->result();
 
		foreach ($roles as $roles) { //Add the roles to the ACL
			$role = new Zend_Acl_Role($roles->id);
			$roles->parentId != null ?
				$this->acl->addRole($role,$roles->parentId): 
				$this->acl->addRole($role);
		}
 
		foreach($resources as $resources) { //Add the resources to the ACL
			$resource = new Zend_Acl_Resource($resources->id);
			$resources->parentId != null ?
				$this->acl->add($resource, $resources->parentId):
				$this->acl->add($resource);
		}
 
		foreach($permissions as $perms) { //Add the permissions to the ACL
			$perms->read == '1' ? 
				$this->acl->allow($perms->role, $perms->resource, 'read') : 
				$this->acl->deny($perms->role, $perms->resource, 'read');
			$perms->write == '1' ? 
				$this->acl->allow($perms->role, $perms->resource, 'write') : 
				$this->acl->deny($perms->role, $perms->resource, 'write');
			$perms->modify == '1' ? 
				$this->acl->allow($perms->role, $perms->resource, 'modify') : 
				$this->acl->deny($perms->role, $perms->resource, 'modify');
			$perms->publish == '1' ? 
				$this->acl->allow($perms->role, $perms->resource, 'publish') : 
				$this->acl->deny($perms->role, $perms->resource, 'publish');
			$perms->delete == '1' ? 
				$this->acl->allow($perms->role, $perms->resource, 'delete') : 
				$this->acl->deny($perms->role, $perms->resource, 'delete');
		}
		$this->acl->allow('3'); //Change this to whatever id your adminstrators group is
	}
	/*
	 * Methods to query the ACL.
	 */
 
	function can_read($role, $resource) {
		return $this->acl->isAllowed($role, $resource, 'read')? TRUE : FALSE;
	}
	function can_write($role, $resource) {
		return $this->acl->isAllowed($role, $resource, 'write')? TRUE : FALSE;
	}
	function can_modify($role, $resource) {
		return $this->acl->isAllowed($role, $resource, 'modify')? TRUE : FALSE;
	}
	function can_delete($role, $resource) {
		return $this->acl->isAllowed($role, $resource, 'delete')? TRUE : FALSE;
	}
        function can_publish($role, $resource) {
		return $this->acl->isAllowed($role, $resource, 'publish')? TRUE : FALSE;
	}
}

IMPORTANT! The final line in the constructor allows all permissions for the role with an ID of 3. This is purely for demonstration purposes. I’m assuming you’ll create an admin role in your database before deploying your app so make sure this ID corresponds with your admin role.

The Database Tables

Next we need to create the database tables we’ll be using for the Acl. For that we only need 3 tables, user_permissions, user_resources and user_roles. The sql for those tables is as follows…

CREATE TABLE `user_resources` (
       `id` INT NOT NULL AUTO_INCREMENT
     , `name` VARCHAR(255)
     , `description` VARCHAR(255)
     , `parentId` INT DEFAULT NULL
     , PRIMARY KEY (`id`)
);
 
CREATE TABLE `user_roles` (
       `id` INT NOT NULL AUTO_INCREMENT
     , `name` VARCHAR(255) NOT NULL
     , `description` VARCHAR(255)
     , `parentId` INT DEFAULT NULL
     , PRIMARY KEY (`id`)
);
 
CREATE TABLE `user_permissions` (
       `id` INT NOT NULL AUTO_INCREMENT
     , `role` INT
     , `resource` INT
     , `read` BOOLEAN DEFAULT FALSE
     , `write` BOOLEAN DEFAULT FALSE
     , `modify` BOOLEAN DEFAULT FALSE
     , `delete` BOOLEAN DEFAULT FALSE
     , `publish` BOOLEAN DEFAULT FALSE
     , `description` VARCHAR(255)
     , PRIMARY KEY (`id`)
);

The user_resources table holds the data for the resources we want to protect through the ACL. Typically this will be admin controllers for any area of your site and perhaps restricted areas of your site such as user profiles or forums. Both the description and parentId fields are optional, the description is there purely for an admin backend to the ACL, the parentId allows you to inherit permissions from a resource, for example you could have separate CMS and media library controllers and you would like the media library to inherit permissions from the CMS so for the media library you would insert the id of the CMS resource into the parent field for the media library.

The user_roles table works in the same way as the resources table. Roles can inherit from other roles allowing you to build permissions with a minimal number of groups. For example you could have a CMS users role which has all permissions except for publish and delete, you could then create a CMS editors role which inherits from the CMS users role but adds extra permissions for deleting and publishing content.

The final table, user_permisssions, is what builds the permissions in the acl. If needs be you can add as many boolean columns for whatever permissions your application requires, just remember to add a method in your ACL library for querying that permission! The description field is, like the other tables, optional but for the purposes of an admin backend you’ll probably want to use it!

We can now start by populating our tables…

INSERT INTO `user_resources` (`id`, `name`, `description`, `parentId`) VALUES
(1, 'test', 'Acl Test Controller', NULLL)
 
INSERT INTO `user_roles` (`id`, `name`, `description`, `parentId`) VALUES
(1, 'test', 'Acl Test Role', NULLL)
 
INSERT INTO `user_permissions` (`id` ,`role` ,`resource` ,`read` ,`write` ,`modify` ,`delete` ,`publish`)
VALUES (NULL , '1', '1', '1', '1', '0', '0', '0');

Testing the ACL

We’re now ready to test out the ACL. Create a controller test.php in /system/application/controllers with the following code.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 class Test extends Controller {
 function  Test() {
  parent::Controller()
  $this->load->library('Acl');
  define('ROLE', '1');
  define('RESOURCE', '1');
 }
 function index() {
  if (!$this->acl->can_read(ROLE, RESOURCE)) {
   die("You do not have permissions to read this resource");
  }
  echo "You have permission to read this resource!";
 }
 function write() {
  if (!$this->acl->can_write(ROLE, RESOURCE)) {
   die("You do not have permissions to write to this resource");
  }
  echo "You have permission to write to this resource!";
 }
 function modify() {
  if (!$this->acl->can_modify(ROLE, RESOURCE)) {
   die("You do not have permissions to modify this resource");
  }
  echo "You have permission to modify this resource!";
 }
 function delete() {
  if (!$this->acl->can_delete(ROLE, RESOURCE)) {
   die("You do not have permissions to delete this resource");
  }
  echo "You have permission to delete this resource!";
 }
 function publish() {
  if (!$this->acl->can_publish(ROLE, RESOURCE)) {
   die("You do not have permissions to publish this resource");
  }
  echo "You have permission to publish this resource!";
 }
}

For the purposes of this article I’m going to assume your working on your local machine, so browse to http://localhost/test. You should see the message “You have permission to read this resource”. Next try http://localhost/test/delete. You should see the message “You do not have permission to delete this resource”. Now go and try it on all the methods in your test controller.

Congratulations! You’ve successfully got Code Igniter and Zend ACL to play nicely together.

Note: If you get error messages about required files not being found in the include path you may have to modify the include paths in your Zend framework files. Open them up and, wherever you find an include or require, modify it to…

BASEPATH.'/libraries/REST OF THE FILE PATH';

Summary

While the above article explains how to get access control working in code igniter it doesn’t provide a model for obtaining roles and resources, the above example having the role and resource id hardcoded into the controller. This is an exercise I feel that is best left to the developer. Personally I use the excellent modular extensions for organising my application. I then have a separate module model which has a method get_resource_id which allows me to define the resource.

The users id is held in their session and I have a users model which, again, has to method to define their role from their session.

It’s also worth noting that if you try and check the ACL without either the role or resource being valid you’ll get an exception error so whichever way you decide to implement this it’s best to write some basic checks before querying the ACL.

The End

Ok, I hope some people have found this useful, let the comments commence!

Thank you for listening.

Based on FluidityTheme Redesigned by Kaushal Sheth Sponsored by Send Flowers