位掩码
位掩码的最初问题是它们违背了数据建模的惯例(以another answer here 表示,进一步阅读here 和here)。一个 4 字节的有符号整数可能只包含 31 不同的值(以整数表示为 2 147 483 648),并且很难用它们进行计算。在讨论这个话题之前,Stack Overflow 上有各种各样的问题,我曾经用它来了解 bistmasks 的工作原理。
测试还表明,使用位掩码很难。理解位运算符需要一种感觉,并且迁移基本上是不可能的。 (不可能我的意思是,起初,实现位掩码似乎是 good 要做的事情,但毕竟它需要 太多 花费与它可以带来的收益相比。)以一个基本的类似门户的网站...我的意思是不。以 Stack Overflow 为例,它有多少独特的特权。实际上,我曾尝试进行计数,但在复杂性中迷失了自己,但我们需要的数量非常接近,如果还没有超过 31 个唯一值的上述障碍的话。更改位掩码含义的项目更新很可能导致长期需要重新计算,并且如果遇到数据库错误,则更容易出错。
虽然我没有准确、精确的时序数据,但使用位掩码感觉比 ACL 慢。比较数据库大小,内存和存储空间更大,我们利用关系数据库和索引功能的机会更少。对于网站上的用户权限,如果我们有其他可能使用的方法,位掩码是不行。
位掩码做工作的系统有很多种,即MaNGOS(我最初是从这里提出这个想法的),item_template 和其他各种模板表定义了使用位掩码的flags。但底线是,在这些表中,值不可能永远改变,计算是只读,与用户任意获取和失去权限的网站相反。
示例代码
define('U_NIL', 0);
define('U_EXEC', 1);
define('U_WRIT', 2);
define('U_READ', 4);
$our_perm = 7;
$req_perm = U_EXEC | U_WRIT | U_READ;
var_dump( ($our_perm & $req_perm) == $req_perm ); # Will be bool(true)
$our_perm = 3;
var_dump( ... The same thing ...); # Will be bool(false)
$our_perm = U_READ;
$req_perm = U_READ | U_WRIT;
var_dumo(...); # Will be bool(false)
$our_perm = U_READ | U_WRIT | U_EXEC;
$req_perm = U_READ;
var_dump(...); # Will be bool(true)
等等。
我将省去你的代码行,因为variousotherquestions 恰当地描述了该方法,在某种程度上我永远无法描述它。位掩码看起来不错,位掩码似乎很奇特,但让它们在生产中安定下来是没有意义的。
ACL
原始问题中描述的另一个选项是利用关系数据库和 SQL 语言在数据库中设置权限。我们需要在数据库中再创建两个表:
CREATE TABLE `perm_relation` (
`row_id` int(10) NOT NULL AUTO_INCREMENT,
`user_id` int(10) NOT NULL,
`perm_id` int(10) NOT NULL,
PRIMARY KEY (`row_id`),
UNIQUE `permission` (`user_id`, `perm_id`)
) ENGINE=InnoDB;
CREATE TABLE `permission` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`row_id`)
) ENGINE=InnoDB;
perm_relation.perm_id 将是指向permission.id 的外键,perm_relation.user_id 将是我们与users.id 的关系。在此之后,这只是我们如何组合编程逻辑的问题。
SELECT row_id FROM perm_relation
WHERE perm_id = (SELECT id FROM permission WHERE name = "U_SUPERADMIN")
AND user_id = CURRENT_USER_ID;
使用这种方法,我们可以实现更高的兼容性、更快的执行和更轻松的迁移。添加新权限只需要很短的时间,既可以定义新权限,也可以将一些权限授予任意用户。删除同样简单,只需要一个小的 SQL 查询来优化我们的表以删除孤立的整体(例如:具有权限的用户没有在系统中定义相关权限)。
因为我们正在将该系统实现到 PHP 环境中,我们可以假设会有某种管理页面,其中包含许多依赖于该权限列表的功能。列出按他们拥有的权限过滤的用户的示例就是一个示例。在这种情况下,ACL 比位掩码要好得多,因为我们可以进一步利用 JOIN 语句……甚至更多。
结论是位掩码和关系模式有不同的用途。对于用户权限系统而言,位掩码太多并且非常庞大,而在上面提到的 MaNGOS 示例中,关系表将是过度杀伤力。