1

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!

argoneus
  • 1,097
  • 2
  • 13
  • 24
  • Please search for binary flags here on SO and on google. You should find plenty of stuff. – hakre Sep 28 '12 at 12:54
  • Well, thing is, PHP doesn't have enums, so it'd be a little complicated... (or not?) – argoneus Sep 28 '12 at 12:56
  • Read what I wrote in response to this question...http://stackoverflow.com/questions/5708239/when-is-it-better-to-store-flags-as-a-bitmask-rather-than-using-an-associative-t/5708369#5708369 – Neville Kuyt Sep 28 '12 at 12:57

3 Answers3

1

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 ;)

Pharao2k
  • 685
  • 4
  • 24
  • Per role seems better, but then can I do something like `if user access > moderator` which would work for moderator, administrator and owner? – argoneus Sep 28 '12 at 13:11
  • you mean a hierarchy of roles, as in higher roles inherit the rights of parent roles? (= moderator role has all rights of user role, admin role has all rights of moderator role...) .. sure that would be possible – Pharao2k Sep 28 '12 at 13:29
  • could you give me some basic pointers / link me to something that's worked for you? : – argoneus Sep 28 '12 at 13:38
1

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.

Martin Bean
  • 38,379
  • 25
  • 128
  • 201
  • Good choice, but I would suggest to load the permission level at start in a session to avoid database requests on each single line, that needs to be checked. – Peon Sep 28 '12 at 13:05
  • Yeah. It was just a simple example. I'd normally load the permissions on logging a user in and storing that information in a session as you suggest. – Martin Bean Sep 28 '12 at 14:06
0

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.

LSerni
  • 55,617
  • 10
  • 65
  • 107