Pergunta

Estou trabalhando em um sistema de papel / permissão no PHP para um script.

Abaixo está um código usando um método de máscara de bits para permissões que encontrei no phpbuilder.com.

Abaixo dessa parte, há uma versão muito mais simples que o W3Hich poderia fazer básico a mesma coisa sem a parte do bit.

Muitas pessoas recomendaram o uso de operadores de bits e tal para configurações e outras coisas no PHP, nunca entendi por que. No código abaixo está lá Qualquer benefício de usar o primeiro código em vez do segundo?

<?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.';
}
?>

versão não bit

<?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.';
}

?>
Foi útil?

Solução

Por que não apenas fazer isso ...

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.';
}

Você também pode criar muitas combinações arbitrárias de permissões se usar bits ...

$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

Outras dicas

O primeiro permite que as pessoas tenham muitas permissões - Leia/Adicionar/atualizar, por exemplo. O segundo exemplo, o usuário tem apenas PERMISSION_UPDATE.

Os testes bitweeques funcionam testando bits para valores da verdade.

Por exemplo, a sequência binária 10010 identificaria um usuário com PERMISSION_DELETE e PERMISSION_READ (a parte identificando PERMISSION_READ é a coluna para 2, o bit identificando PERMISSION_DELETE é a coluna para 16), 10010 em binário é 18 em decimal (16 + 2 = 18). Seu segundo amostra de código não permite que você faça esse tipo de teste. Você pode fazer verificações maiores do que no estilo, mas isso assume todos com PERMISSION_DELETE também deve ter PERMISSION_UPDATE, o que pode não ser uma suposição válida.

Talvez seja apenas porque eu não uso máscaras de bits com muita frequência, mas acho que em um idioma como PHP, onde a produtividade e a legibilidade do código dos desenvolvedores são mais importantes que o uso de velocidade ou memória (dentro dos limites, obviamente), não há razão real para usar o Bitmasking .

Por que não criar uma classe que rastreia coisas como permissões e login nos usuários e assim por diante? Vamos chamá -lo de auth. Então, se você deseja verificar se um usuário tem uma permissão, poderá criar um método Haspermission. por exemplo,

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

Então, se você quiser verificar se eles têm alguma combinação de permissões:

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

Ou se você quiser verificar se eles têm algum de um determinado grupo de permissões:

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

Obviamente, pode não ser uma má idéia definir constantes, como permissão_read, que você pode definir como a string 'Read' e assim por diante.

Acho essa abordagem mais fácil de ler do que máscaras de bits, porque os nomes de métodos dizem exatamente o que você está procurando.

Editar: Relendo a pergunta, parece que as permissões do usuário estão voltando do seu banco de dados em um campo de bits. Se for esse o caso, você terá que usar operadores bitwise. Um usuário que tem permissão no banco de dados é 5 tem PERMISSION_READ e PERMISSION_DENIED Porque (PERMISSION_READ & 5) != 0, e (PERMISSION_DENIED & 5) != 0. Ele não teria PERMISSION_ADD, Porque (PERMISSION_ADD & 5) == 0

Isso faz sentido? Todas as coisas complexas em seu exemplo bit -bones parecem desnecessárias.


Se você não entende completamente as operações bit newise, não as use. Isso só levará a muitas dores de cabeça. Se você se sentir confortável com eles, use -os onde você sente que são apropriados. Você (ou quem escreveu o código bit) não parece compreender completamente as operações bit -new. Existem vários problemas com isso, como o fato de que o pow() A função é usada, que negaria qualquer tipo de benefício de desempenho. (Ao invés de pow(2, $n), você deve usar o bit a bit 1 << $n, por exemplo.)

Dito isto, as duas peças de código não parecem fazer as mesmas coisas.

Tente usar o que está no bit.class.php em http://code.google.com/p/samstyle-php-framework/source/browse/trunk/class/bit.class.php

Verificando contra um bit específico:

<?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
}

?>

E para ligar e desligar:

<?php

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

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

?>

O problema disso é se permissão_read for uma máscara

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

Então, para 0101 - $ RightWehave 0011 - $ RightWerequire

é o acesso concedido, o que provavelmente não queremos, então deve ser

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

Então agora para

0101 0011

resultado é

0001 Portanto, o acesso não é concedido porque não é igual a 0011

mas pelo

1101 0101

Tudo bem, pois o resultado é 0101

Verifica qual máscara foi definida em decimal. Talvez alguém precise:

<?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";

Saída (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

Eu acho que o primeiro exemplo oferece mais controle sobre exatamente quais permissões um usuário tem. No segundo, você apenas tem um 'nível' de usuário; Presumivelmente, os níveis mais altos herdam todas as permissões concedidas a um usuário do nível mais baixo, para que você não tenha um controle tão bom.

Além disso, se eu entendi corretamente, a linha

if($user_permission_level === 4)

significa que apenas usuários com exatamente O nível de permissão 4 tem acesso à ação - certamente você gostaria de verificar se os usuários têm pelo menos esse nível?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top