Greetings,
This is just another informative post about one of the core features that Engine is hiding deep within; User permissions. This feature had a major revamp with the 1.1 code base and I’ve dedicated this blog post to go into more details about how the feature works.
The problem
As every other feature, each is designed to solve a problem. In this case its pretty obvious we want to solve the problem of user permissions, while also implementing a system thats easy to build on later without causing any issues with the current code base.
Most designs I’ve seen from friends were a simple boolean check, where:
- Many crowed permission fields in the user table like “perm_admin”, “perm_mod”, etc. that had 0 or 1 values
- A huge relational table that were linked to the user table about which permissions that user could access
(… and then of course the same for those with usergroups.)
Simple is not so hard
So thinking about it for a moment, its no brainer that we got to do with numbers and boolean values. This left me to a simple solution I had previous used in another personal project of mine, while this idea is a well used solution, it is still very unknown to many although its simplicity, so lets skip to it.
The solution is to use bitfields and bitmask, and manage them with bitwise operations. To understand this for the easy minded, lets take an example:
<?php /* Mask is equal to 15, and contains the bits from each of those 4 brackets */ $mask = 1 | 2 | 4 | 8; ?>
Each of these can be considered a permission field (bitfield), lets rewrite this example to be more verbose:
<?php const PERM_GUEST = 1; const PERM_BANNED = 2; const PERM_USER = 4; const PERM_ADMINISTRATOR = 8; /* Don't mind the names, this is just to show an example of them combined */ $mask = PERM_GUEST | PERM_BANNED | PERM_USER | PERM_ADMINISTRATOR; ?>
So to continue on that example, lets say a user is an administrator, since the administrator is an extension to the basic user permission, both most be present, so the bitmask would looks like this:
<?php /* $mask = 12; ( 4 | 8 ) */ $mask = PERM_USER | PERM_ADMINISTRATOR; >
This magic number that $mask have is the permission bitmask that the user and usergroup tables have, meaning its a simple integer field and not a huge list of yes and no.
So to get the terminology correct;
- PERM_GUEST, PERM_BANNED, PERM_USER, PERM_ADMINISTRATOR are each a bitfield.
- The collection of one bitfield or more makes it a bitmask.
- The | operator is called bitwise OR.
- The & operator is called bitwise AND.
Now that the terminology is at place, we can go to the last point on our agenda; the actual checking for the correct permissions. To achieve this we must use the bitwise AND operator, since we use the OR operator for creating the mask, we must use the AND operator to check if the mask actually contains the field or fields we desire.
<?php
/**
* This example takes into account that $user_permissions is populated with the value of the
* user currently authenticated.
*/
/* Is the user flagged for a ban? */
if($user_permissions & PERM_BANNED)
{
throw new Exception('You are banned from viewing this sites content');
}
/**
* We can also check multiple permissions at the same, while this example is irrelevant
* mainly because the user flag already exists, its a proof of concept
*/
if($user_permissions & (PERM_USER | PERM_ADMINISTRATOR))
{
/* Administrator options */
}
?>
As you can see, you can check for a single field or multiple in one by making a mask and checking that mask against the main one.
To understand the return values and why those conditions are true is quite simple;
- If the mask contains the bitfields you are comparing against, the value of the bitfields are returned, and since they are never 0, its evaluated as true.
- If there is no matches, the return value of the expression is 0, thats evaluated as false.
One last gem…
There is one last gem to using bitfields, that is you can have a master value for debugging this. -1 always contains all the bits, so if your bitfield is -1 all possible conditions will return true, but use this with great care in such implementations.
The tool
Engine 1.1 contains a designated tool to test for such permissions, and to see which failed and which succeed. It can be found in the tools menu, attached below is a screenshot of it in action:
I hope this post have been informative, although its more about the abstract concept rather than how its implemented in Engine which is more or less irrelevant to this simple and sleek design.
For the record; this system is also implemented in the 1.0 series, but its not as verbose as it is in 1.1.

