I'm working on a personal CMS and I've got a problem. I wanted to define access levels such as CAN_DELETE_THREAD, CAN_EDIT_MESSAGE or CAN_CREATE_THREAD as binary flags, but I don't know how a function 'has_flag' would work. For example, if I took a user from the db and wanted to check if he can edit messages, how would I go around doing that?
Thanks!
You could create a permissions
database table, and a permissions_users
table that joins permissions to users, and then check on a per-page basis if the logged-in user can view that page.
Imagine you have a User
model, and a permission with an ID of 1:
if ($user->hasPermission(1)) {
// show form or whatever
}
else {
throw new ForbiddenException();
}
Your hasPermission()
method could be as simple as:
<?php
class User extends Model {
public function hasPermission($permission_id) {
$sql = "SELECT COUNT(*) FROM `permissions_users` WHERE `user_id` = :user_id AND `permission_id` = :permission_id";
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':user_id', $this->id, PDO::PARAM_INT);
$stmt->bindParam(':permission_id', $permission_id, PDO::PARAM_INT);
return ($this->pdo->fetchColumn() > 0); // returns true if at least 1 result
}
}
Obviously you'll need to adjust this to fit your application.
Do you need per-user or per-role access settings?
per-role would be way more scalable, especially if your system will be open for many users.
At first, I'd define actions that a user can do, grouped by some category ("Thread" with [Add, Edit, Delete, Flag, Archive, Whatever]), then you could create a list to define for each role and each action if it is allowed or denied.
You could decrease the amount of needed specifications in that table if you define a default value (everything is allowed if not denied or vice versa).
A bit more details would be needed for further help ;)
You can do that in several ways. You might store an integer property associated with the user, then define the flags as integer powers of 2:
define('CAN_CREATE_THREAD', 0x0010);
define('CAN_DELETE_THREAD', 0x0020);
then to your hasFlag($flag)
could be something like
return ($this->BinaryFlags & $flag);
Otherwise you can store all the flags in the database:
CREATE TABLE flags
(
id integer not null primary key auto_increment,
name varchar(32)
);
CREATE TABLE has_flag
(
user_id integer,
flag_id integer
);
and your hasFlag function is a query to the database.
Role-level access is the same, except that you do not store flags associating them to an user, but rather associate an user to a role (so you have a table like (user_id, role_id)
), and then associate the flags to the role as shown above.
The advantage is that you can define a person as "Section XYZ Administrator" without having to remember and set all permissions one by one; the disadvantage is that you can't have intermediate states (say, a semi-administrator that can edit but not create) unless you create the role first.