Open SourceCreating a Custom ACL in PHP

Creating a Custom ACL in PHP

An ACL (access control list) is a list that controls object permissions, determining which user can execute a certain task. It can be further extended to contain not only users, but also user groups. This is an important aspect of PHP security and is used in virtually all medium- and large-sized applications.

So, what are the advantages of an ACL model? The first advantage is security. Using this model will make your application more secure and less vulnerable to exploits. When securing any program, it is good to give to the user only the privileges he/she needs. That means that, for example, you should not give super administrator privileges to someone who will only manage website content. The ACL security model allows you to do just that. The second advantage is the easiness of user management. You can divide users into groups, while each group has certain access permissions. Also, you can easily add new user groups, delete the old ones or change group permissions.

Let’s see how an ACL model works in practice. I will explain how to implement an access control list in PHP and MySQL. First, we have to create tables and their relations for users, user groups and their permissions:

CREATE TABLE users (
 userid INT(10) NOT NULL AUTO_INCREMENT,
 group_id INT(10) NOT NULL,
 username VARCHAR(255) NOT NULL UNIQUE,
 password VARCHAR(255) NOT NULL,
 reg_date INT(10),
 PRIMARY KEY(userid)
);

CREATE TABLE usergroups (
group_id INT(10) NOT NULL AUTO_INCREMENT,
group_name VARCHAR(100) NOT NULL,
PRIMARY KEY(group_id)
);

CREATE TABLE user_permissions (
pid INT(10) NOT NULL AUTO_INCREMENT,
permission_name VARCHAR(100) NOT NULL,
permission_type INT(1),
userid INT(10) NOT NULL,
PRIMARY KEY (pid)
);

CREATE TABLE group_permissions (
pid INT(10) NOT NULL AUTO_INCREMENT,
permission_name VARCHAR(100) NOT NULL,
permission_type INT(1),
group_id INT(10) NOT NULL,
PRIMARY KEY (pid)
);

The permissions tables are the most important here, as they represent a relationship between objects (users) and actions in the application. Have in mind that there are ACL security models with group permissions only. But I wanted to create a very flexible ACL, so I created both types of permissions. Now that we have the basis of this model, we need to program the dynamic part of it in PHP.

Object-oriented ACL in PHP

Before I write the code, let’s mention some tips on creating a PHP object-oriented ACL. Object-oriented programming (OOP) allows you to write code more efficiently, re-using it as much as possible, while offering much better organization for the application. Regarding the ACL OOP, create your ACL as a PHP class. Use a plug-in system, or have a page which you would include in every PHP page. Also, create a class that will handle form inputs and execute ACL code upon submit. The same should be done for all AJAX requests.

So, let’s create the ACL class:

<?php
Class Acl {

private $db;

//initialize the database object here
function __construct() {
$this->db = new db;
}

function check($permission,$userid,$group_id) {

//we check the user permissions first

}

}
?>

This is the class layout. The database object is initialized upon initializing the ACL class, as we have to check permissions in the database. The function check() will check the permissions and return true if the user is allowed to execute that action, or error if not allowed. Note that user permissions will be checked first, because they override group permissions. If there is no specific user permission, then we continue with checking group permissions. Also, $db is the database object, and you can use any database management class for this purpose. Look at the PHP code that checks user and group permissions:

<?php
Class Acl {

private $db;
private $user_empty = false;

//initialize the database object here
function __construct() {
$this->db = new db;
}

function check($permission,$userid,$group_id) {

//we check the user permissions first
If(!$this->user_permissions($permission,$userid)) {
return false;
}

if(!$this->group_permissions($permission,$group_id) & $this->IsUserEmpty()) {
return false;
}

return true;

}

function user_permissions($permission,$userid) {
$this->db->q(“SELECT COUNT(*) AS count FROM user_permissions WHERE permission_name=’$permission’ AND userid=’$userid’ “);

$f = $this->db->f();

If($f[‘count’]>0) {
$this->db->q(“SELECT * FROM user_permissions WHERE permission_name=’$permission’ AND userid=’$userid’ “);

$f = $this->db->f();

If($f[‘permission_type’]==0) {
return false;
}

return true;

}
$this->setUserEmpty(‘true’);

return true;

}
function group_permissions($permission,$group_id) {
$this->db->q(“SELECT COUNT(*) AS count FROM group_permissions WHERE permission_name=’$permission’ AND group_id=’$group_id’ “);

$f = $this->db->f();

if($f[‘count’]>0) {
$this->db->q(“SELECT * FROM group_permissions WHERE permission_name=’$permission’ AND group_id=’$group_id’ “);

$f = $this->db->f();

If($f[‘permission_type’]==0) {
return false;
}

return true;

}

return true;

}

function setUserEmpty($val) {
$this->userEmpty = $val;
}

function isUserEmpty() {
return $this->userEmpty;
}

}
?>

PHP ACL: Permissions and Performance

Permission names are created by you — that means that you can use any name as a permission name. However, I suggest you check some permissions automatically and assign them some generic names, such as view_[page_name] for checking page access permissions, or form_[form_name] for checking if a certain users has permissions to submit a form.

Permission types are introduced in this version of PHP ACL, where “0” means “deny” and “1” means “allow.” This feature is very useful if you have to manage exceptions, e.g., you need to allow a whole user group to execute an action, but you want to deny access to that action for a few group members.

After creating the PHP class, you need to create an object of that class in another PHP file. It should be done the following way:

<?php
$acl = new Acl();
If(!$acl->check(view_admin_dashboard,1,1)) {
// user doesn't have permission to execute the following action
//do something here
}
?>

Consider your website’s performance when implementing an ACL. Using access control list checks increases the number of queries per request by 4. Although there is MySQL query cache, it is recommended that you create your own caching system. It can be as simple as storing the query results into a file and fetching them from a txt file for a certain period of time, or more complex, such as CodeIgniter’s SQL caching system, which can store cache for unlimited period of time, but delete it when a certain action is executed (e.g., clear cache when a new user is registered).

In conclusion, implement the ACL model, as it is would significantly increase your website security.

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories