18

我正在为脚本开发 PHP 中的用户角色/权限系统。

下面是我在 phpbuilder.com 上找到的使用位掩码方法获取权限的代码。

在该部分下面是一个更简单的版本,w3hich 可以在没有位部分的情况下做基本相同的事情。

许多人建议在 PHP 中使用位运算符等进行设置和其他操作,但我一直不明白为什么。在下面的代码中,使用第一个代码而不是第二个代码有什么好处吗?

<?php
/**
 * Correct the variables stored in array.
 * @param    integer    $mask Integer of the bit
 * @return    array
 */
function bitMask($mask = 0) {
    $return = array();
    while ($mask > 0) {
        for($i = 0, $n = 0; $i <= $mask; $i = 1 * pow(2, $n), $n++) {
            $end = $i;
        }
        $return[] = $end;
        $mask = $mask - $end;
    }
    sort($return);
    return $return;
}


define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = bitMask('5');

if(in_array(PERMISSION_READ, $_ARR_permission)) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}
?>

非位版本

<?PHP
/*
   NON bitwise method
*/

// this value would be pulled from a user's setting mysql table
$user_permission_level = 4;

if($user_permission_level === 4) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

?>
4

8 回答 8

41

为什么不这样做...

define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = 5;

if($_ARR_permission & PERMISSION_READ) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

如果您使用位,您还可以创建许多任意的权限组合......

$read_only = PERMISSION_READ;
$read_delete = PERMISSION_READ | PERMISSION_DELETE;
$full_rights = PERMISSION_DENIED | PERMISSION_READ | PERMISSION_ADD | PERMISSION_UPDATE | PERMISSION_DELETE;

//manipulating permissions is easy...
$myrights = PERMISSION_READ;
$myrights |= PERMISSION_UPDATE;    // add Update permission to my rights
于 2009-09-04T15:55:49.253 回答
10

第一个允许人们拥有很多权限——例如​​读取/添加/更新。第二个例子,用户刚刚PERMISSION_UPDATE.

按位测试通过测试位的真值来工作。

例如,二进制序列10010将使用PERMISSION_DELETEPERMISSION_READ(位标识PERMISSION_READ是 2 的列,位标识PERMISSION_DELETE是 16 的列)标识用户,10010二进制是十进制的 18 (16 + 2 = 18)。您的第二个代码示例不允许您进行那种测试。您可以进行大于样式检查,但这假设每个人都PERMISSION_DELETE应该也有PERMISSION_UPDATE,这可能不是一个有效的假设。

于 2009-09-04T15:54:01.143 回答
10

也许只是因为我不经常使用位掩码,但我发现在像 PHP 这样的语言中,开发人员的生产力和代码可读性比速度或内存使用更重要(显然在限制范围内),没有真正的理由使用位掩码.

为什么不创建一个类来跟踪权限、登录用户等内容呢?我们称它为 Auth。然后,如果你想检查一个用户是否有权限,你可以创建一个方法 HasPermission。例如,

if(Auth::logged_in() && Auth::currentUser()->hasPermission('read'))
    //user can read

那么如果你想检查它们是否具有某种权限组合:

if(Auth::logged_in() && Auth::currentUser()->hasAllPermissions('read', 'write'))
    //user can read, and write

或者,如果您想检查他们是否具有某组权限中的任何一个:

if(Auth::logged_in() && Auth::currentUser()->hasAnyPermissions('read', 'write'))
    //user can read, or write

当然,定义常量可能不是一个坏主意,例如PERMISSION_READ,您可以将其定义为字符串'read',等等。

我发现这种方法比位掩码更容易阅读,因为方法名称可以准确地告诉您要查找的内容。

于 2009-09-04T16:24:38.103 回答
1

编辑:重新阅读问题,看起来用户的权限正在从您的数据库中的位域返回。如果是这种情况,您将不得不使用按位运算符。一个用户在数据库中的权限是5has PERMISSION_READandPERMISSION_DENIED因为(PERMISSION_READ & 5) != 0, and (PERMISSION_DENIED & 5) != 0。他不会有PERMISSION_ADD,因为(PERMISSION_ADD & 5) == 0

那有意义吗?您的按位示例中的所有复杂内容看起来都没有必要。


如果您不完全了解按位运算,请不要使用它们。 它只会导致很多头痛。如果您对它们感到满意,请在您认为合适的地方使用它们。您(或编写按位代码的人)似乎没有完全掌握按位运算。它有几个问题,例如使用该pow()函数的事实,这将否定任何类型的性能优势。(例如pow(2, $n),您应该使用按位1 << $n来代替 。)

也就是说,这两段代码似乎没有做同样的事情。

于 2009-09-04T15:53:11.097 回答
1

尝试在http://code.google.com/p/samstyle-php-framework/source/browse/trunk/class/bit.class.php使用 bit.class.php 中的内容

检查特定位:

<?php

define('PERMISSION_DENIED', 1);
define('PERMISSION_READ', 2);
define('PERMISSION_ADD',  3);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 5);


if(bit::query($permission,PERMISSION_DENIED)){
echo 'Your permission is denied';
exit();
}else{
// so on
}

?>

并打开和关闭:

<?php

$permissions = 8;
bit::toggle(&$permissions,PERMISSION_DENIED);

var_dump($permissions); // outputs int(9)

?>
于 2009-09-05T15:32:28.307 回答
1

这个问题是如果 PERMISSION_READ 本身就是一个掩码

if($ARR_permission & PERMISSION_READ) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';

然后为 0101 - $rightWeHave 0011 - $rightWeRequire

它是授予访问权限的,我们可能不希望这样做

if (($rightWeHave & $rightWeRequire) == $rightWeRequire) {
echo 'access granted';
}

所以现在

0101 0011

结果是

0001 因此不授予访问权限,因为它不等于 0011

但对于

1101 0101

没关系,因为结果是 0101

于 2012-03-21T10:37:05.713 回答
1

脚本检查哪个掩码已设置为十进制。也许有人会需要它:

<?php

$max = 1073741824;
$series = array(0);
$x = 1;
$input = $argv[1]; # from command line eg.'12345': php script.php 12345
$sum = 0;

# generates all bitmasks (with $max)
while ($x <= $max) {
    $series[] = $x;
    $x = $x * 2;
}

# show what bitmask has been set in '$argv[1]'
foreach ($series as $value) {
    if ($value & $input) {
        $sum += $value;
        echo "$value - SET,\n";
    } else {
        echo "$value\n";
    }
}

# sum of set masks
echo "\nSum of set masks: $sum\n\n";

输出(php maskChecker.php 123):

0
1 - SET,
2 - SET,
4
8 - SET,
16 - SET,
32 - SET,
64 - SET,
128
256
512
1024
2048
4096
8192
(...)

Sum of set mask: 123
于 2016-06-16T09:58:24.287 回答
0

我想第一个示例可以让您更好地控制用户拥有的权限。在第二个中,您只有一个用户“级别”;大概较高级别会继承授予较低“级别”用户的所有权限,因此您没有如此精细的控制。

另外,如果我理解正确的话,这条线

if($user_permission_level === 4)

意味着只有具有完全权限级别 4 的用户才能访问该操作 - 您肯定想要检查用户是否至少具有该级别?

于 2009-09-04T15:53:02.813 回答