Revolves

Innovation

Revolves header image 2

Using Zend Acl With CodeIgniter

December 18th, 2008 · 6 Comments · PHP, Programming

You’ll need to scroll horizontally to see the source codes. Best is to copy them and paste in your text editor
I was just taking a look at the CodeIgniter forum, and found that many people require some sort of an Acl component to make their lives easier. Of course, Zend framework has an excellent tried and tested Acl component. Also, the framework’s loose coupoling allows to just use a small part of it.

Seeing this, I tried implementing Zend’s Acl component into a default CI installation. Now, this is a very dirty work, I’ve just thrown stuffs here and there. But you’ll at least get an idea on how to use it. The major code goes into a CI library, which initializes the Acl object, roles, resources and rules for them.

Lets begin with the directory structure,

I created a new directory called Custom inside the application directory. And here’s how the folder structure looks inside of Custom,

Custom
-Zend
–Acl
–Acl.php
–Exception.php (You’ll need this file too)

If you download the Zend framework, those are the only files you’ll need. Remember, you’ll need to have a folder called Zend, since this is how Zend refers to them in all of its includes. I apppend the Custom directory into PHP’s include path, since putting the Zend directory directly into the include path throws errors. That’s the reason I have the Custom folder in the first place. You’ll see all the include path stuff ahead, so don’t start worrying about them now.

Lets go to the library part. Now, lemme tell you beforehand that I’ve made no effort to organize code. My objective was to make the Acl component work in a convenient way. So pardon the bad coding practice if any ;) .

In the libraries folder within your application folder, created a new library file named Zacl.php (I know I’m not creative). This is it’s contents.

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

class Zacl
{
    function __construct()
    {
        session_start();
        //Append Zend's folder in PHP's include path
        set_include_path(get_include_path() . PATH_SEPARATOR . BASEPATH . "application/Custom");

        //Load the Acl class
        require_once 'Zend/Acl.php';
        require_once 'Zend/Acl/Role.php';
        require_once 'Zend/Acl/Resource.php';

        //Create a new Acl object
        $this->acl = new Zend_Acl();

        /**
         * Add roles and resources. Check Zend's documentation for excellent
         * information on all these.
         * http://framework.zend.com/manual/en/zend.acl.html
         */
        $this->acl->addRole(new Zend_Acl_Role('guest'));
        $this->acl->addRole(new Zend_Acl_Role('users'),array('guest'));

        /**
         * Add some resources
         */
        $this->acl->add(new Zend_Acl_Resource('users_login'));
        $this->acl->add(new Zend_Acl_Resource('users_profile'));

        /**
         * Set rules for Acl
         */
        $this->acl->deny(); //Deny everything, so as to follow a whitelist approach.
        $this->acl->allow('guest','users_login');
        $this->acl->allow('users','users_profile');
    }

    function check_acl($resource)
    {
        if (!$this->acl->has($resource))
        {
            return 1;
        }

        if (isset($_SESSION['user_id']))
        {
            $role = 'users';
        }
        else
        {
            $role = 'guest';
        }

        return $this->acl->isAllowed($role,$resource);
    }

}

Now, I have a constructor, which sets up everything. First of all, don’t be scared by the session_start() stuff, I just included it for a simple login/logout mechanism you’ll see later, to check if everythings fine. Even though I’ve commented the source code, I’ll just give a gist of what I’m doing.

1. Loading all required classes for Zend Acl.
2. Adding Roles.
3. Adding Resources (I elaborate on this below)
4. Set access rules

If you see, the ‘users’ role is actually a child of ‘guest’ role, thus inheriting properties from it. You’ll need to check Zend’s manual to know about the syntax and stuff, since its explained quite well.

Now, both role and resource names are arbitrary. You can set them as whatever you want. I’ve used a small convention for resource part. I’ve named resources as “controller_action”. This is because, I can easily get controller and action name from the URI, and can easily query Acl from any controller.

In the next part, I simply set the access rules (quite self explanatory). I have a function called check_acl(), which takes a parameter named $resource. This is passed by the controller to the function, using the convention I told you about above. Zend throws an exception if a given resource couldn’t be found. Thus, if a resource is not in the Acl, I return 1, saying that its allowed to be accessed.

If the user has a session variable user_id, it means he’s logged in, thus I set his role to ‘users’. Else, his role is ‘guest’.

Now, to the controller path. I created a controller called Users, having this,

<?php

class Users extends Controller
{
    function __construct()
    {
        parent::__construct();
        $this->load->library('zacl');

        $resource = $this->uri->segment(1) . '_' . $this->uri->segment(2);
        if (!$this->zacl->check_acl($resource))
        {
            $this->load->helper('url');
            redirect('/users/login');
        }
    }

    function login()
    {
        echo "The login page";
    }

    function profile()
    {
        echo "The restricted profile page<br />";
        echo "Your user id: " . $_SESSION['user_id'];
    }

    function setsess()
    {
        $_SESSION['user_id'] = 1;
    }

    function remsess()
    {
        unset($_SESSION['user_id']);
    }
}

In the constructor, I load the Acl library, and pass the controller_action to check_acl() function. If the output is 1, user is allowed, else he isn’t. If he isn’t, I redirect him to login page.

The login() and profile() functions are simply dummy functions, to check if Acl is working properly. If you look at the library, you’ll find that guest cannot access profile, while only a user can. The setsess() and remsess() functions are to set and remove user session to simulate logging in and logging out.

Well, I guess that’s it. I know I went a bit fast, but I really got tired typing this much. Anyways, if you have any sort of doubts, or if my code has some errors, please point out by commenting below! I’ve tested the above code in WAMP.

Similar Posts:

Liked The Post? Share And Enjoy!
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Sphinn
  • Mixx
  • Diigo
  • BlinkList
  • Reddit
  • Blogosphere News
  • IndianPad
  • RSS

Tags: ·

6 Comments so far ↓

  • New Fresh PHP Tutorials | Pocko.org

    [...] 9. Using Zend Acl With CodeIgniter [...]

  • Alexwebmaster

    Hello webmaster
    I would like to share with you a link to your site
    write me here preonrelt@mail.ru

  • Matt

    Hi, so I read through most of your article. I’m trying to determine if Zend is has the best ACL to incorporate into CodeIgniter. My first assumption is yes. But I wanted to ask you a few questions about the Zacl library you created.

    It looks like it would be better to leave out lines 20-39 and put those lines in the constructor of your controller. That way if you have multiple controllers which you need to restrict access to you won’t end up controlling your entire sites access through Zacl. Actually, it may be wise to define access rights in a model or helper and that can then be called when a constructor is initialized.

  • admin

    Yes, you’re right. They should go into a constructor like you said. Actually, at the time when I wrote this, I saw many questions about getting Zacl to work with CI in the CI forums. So I gave this elementary example as a reply to it.

    Once understood, people can adapt the concept to their own OOP practices.

  • truffo

    Thanks a lot, it’s very usefull. If you agree i think a make a french translations for the people who don’t understand english.

  • admin

    @truffo

    It’d be great if you could translate it into French, since it would reach a wider audience. You have my permission for that. I would just require you to attribute the original source (this page). :)

    Also, please do post the link to the translation when it’s done. I’ll add it to this page so that people more comfortable with French can go to the translated page.

Leave a Comment