Squelette de gestion des droits

Soyez le premier à donner votre avis sur cette source.

Snippet vu 10 869 fois - Téléchargée 18 fois

Contenu du snippet

Ca faisait longtemps que je n'avais pas posté quelque chose...alors zou...
Ce code est plutôt un prétexte : un post sur le forum posait des questions sur les opérateurs bit à bit. Je me suis dit "tien, c'est vrai qu'ils sont peu utilisés, et donc peu connus, par la plupart des codeurs PHP". J'ai donc décidé de faire un code prétexte, servant d'exemple pour une utilisation de ces opérateurs.
Ce code est néanmoins implémentable et extensible, donc utilisable (à condition de l'étendre hein...). Et il ne prétend pas détenir LA solution pour gérer des droits : c'est une solution comme une autre...elle a ses avantages et ses inconvénients.
Mais d'abord, les opérateurs bit à bit...le code n'en montrera qu'un, donc une petite explication préalable est nécessaire:
Pour rappel, on lit les bits de droite à gauche, le bit le plus faible se trouvant à droite, et le plus fort à gauche.
Du coup, pour comparer 10 et 110, on peut aussi lire : 010 et 110.
Les opérateurs :
AND ou & : les bits qui sont à 1 dans l'argument de gauche et de droite sont mis à 1
101 & 111 = 101
110 & 10 = 10
101 & 10 = 0
OR ou | : les bits qui sont à 1 dans l'argument de gauche ou de droite sont mis à 1
101 | 111 = 111
110 | 10 = 110
101 | 10 = 111
XOR ou ^ : les bits qui sont à 1 dans l'argument de gauche ou dans l'argument de droit mais pas dans les deux arguments en même temps sont mis à 1
101 ^ 111 = 10
110 ^ 10 = 100
101 ^ 10 = 111
NOT ou ~ : les bits à 1 dans l'argument sont mis à 0, et inversement :
~ 100 = 11111111111111111111111111111011 (et oui, on est sur 32 bits!)
le Shift left ou << : décale les bits de l'argument de gauche X fois (ou X est l'argument de droite) vers la gauche. Cela revient à multiplier par 2 à chaque fois
100 << 2 = 10000
Ou avec des entiers :
1 << 2 = 4 (en binaire : 1 (ou 001 donc) << 2 = 100)
Le shift right, ou >> décale les bits de l'argument de gauche X fois (ou X est l'argument de droite) vers la droite. Cela revient à diviser par 2 à chaque fois
100 >> 2 = 1 (ou 001 donc)
Ou avec des entiers :
4 >> 1 = 2 (en binaire : 100 >> 1 = 10 (ou 010))

Facile, non ?
Ce code va utiliser le | pour vérifier des droits. Le principe est très simple une fois que vous avez compris le fonctionnement des opérateurs bit à bit.
On imagine, pour ce code, que l'on crée la gestion des messages d'un forum, par exemple.
On a 3 types d'utilisateurs :
le visiteur, qui n'a que le droit de lire les messages
le membres, qui peut lire les messages et en écrire de nouveau
l'administrateur, qui peut lire, écrire, mais aussi éditer des messages existants.

On affecte donc des niveaux de droit aux 3 accès :
1 pour lire
10 pour écrire
100 pour éditer

Et on fixe les accès des utilisateurs :
1 pour le visiteur
11 pour le membre
111 pour l'administrateur

Et c'est tout :-)
A noter que decbin() permet de transformer un entier en octets: 4 devient alors 100 (sous forme de chaîne...on ne peut pas écrire directement en binaire en php), et que bindec fait l'inverse : il prend une chaîne représentant un nombre binaire, et le transforme en son équivalent entier : 100 devient 4.

Pour les droit, on pourrait aussi utiliser des entiers :
1 pour lire
2 pour écrire
4 pour éditer
et
1 pour le visiteur
3 pour le membre
7 pour l'administrateur

mais c'était plus parlant avec des bits, pour suivre la petite explication :-) Ceci dit, les entiers seraient plus performants, car on n'aurait alors pas besoin de passer par decbin() et bindec().

Source / Exemple :


<?php
abstract class rights {
	protected $bRights = '0';
	
	public function __get($sProp) {
		switch($sProp) {
			case 'RIGHTS':
				return $this->bRights;
			default:
				throw new Exception('Cannot get property '.$sProp);
		}
	}
}

class read extends rights {
	protected $bRights = '1';
}

class write extends rights {
	protected $bRights = '10';
}

class edit extends rights {
	protected $bRights = '100';
}

abstract class user {
	protected $bRights = '0';
	
	public function hasRights(rights $rights) {
		return (decbin(bindec($rights->RIGHTS) | bindec($this->bRights)) === $this->bRights); 
	}
}

class visitor extends user {
	protected $bRights = '1';
}

class member extends user {
	protected $bRights = '11';
}

class admin extends user {
	protected $bRights = '111';
}

$read = new read;
$write = new write;
$edit = new edit;

$visitor = new visitor;
echo (int)$visitor->hasRights($read),"\n";
echo (int)$visitor->hasRights($write),"\n";
echo (int)$visitor->hasRights($edit),"\n";

$member = new member;
echo (int)$member->hasRights($read),"\n";
echo (int)$member->hasRights($write),"\n";
echo (int)$member->hasRights($edit),"\n";

$admin = new admin;
echo (int)$admin->hasRights($read),"\n";
echo (int)$admin->hasRights($write),"\n";
echo (int)$admin->hasRights($edit),"\n";
?>

Conclusion :


A noter que l'on peut modifier la méthode user::hasRights() pour utiliser le & :
return (decbin(bindec($rights->RIGHTS) & bindec($this->bRights)) === $rights->RIGHTS);

A voir également

Ajouter un commentaire Commentaires
Betamax Messages postés 2 Date d'inscription mercredi 15 février 2006 Statut Membre Dernière intervention 23 décembre 2008
23 déc. 2008 à 00:59
Malalam : J'utilise dans un système de gestion de droits le même principe à part le faite de comparer les droits user avec un mask binaire (droits par défaut) comme le fait le pingouin (UNIX) et un droit pour chaque document :)
de cette façon je pousse un peu plus loin dans le degrés d'autorisation.
Je me lance dans les designs pattern (d'ailleurs tu as posté de très bon tuto :) ) mais but dans la manière de procéder pour la construction de divers objets différent (factory) avec accès à plusieurs tables (multiton) et gestion des droits pour certains objets (masque binaire) (user , image ,file etc...)... dur dur.
surtout que je n'ai pas beaucoup de temps :(
merci @ bientôt
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
22 déc. 2008 à 21:49
'lut Akhe, merci :-)

Betamax : dans un environnement "simple", en restant à 1 niveau de droits, on reste bloqués à 32 possibilités (à moins d'avoir un serveur 64 bits évidemment). Ca n'empêche pas de moduler tout ça : un module, 32 droits...donc un projet, X fois 32 droits. Ca devrait suffire...
Utilisation des objets : ça fait potentiellement bcp d'objets, et ce n'est pas forcément optimal en terme de perf. Tout dépend de la façon dont s'est utilisé...et de savoir si la légère perte en perf vs la très large "scalability", l'évolutivité, etc...n'en vaut pas la chandelle, au final (moi, je suis un convaincu...).
Les droits "binaires", c'est bien, mais on s'y perd vite si on ne gère pas ça correctement (bordel, 100101 ça correspond à QUOI????). Pareil pour les entiers (hmmm...57, donc...voué voué voué...le gars y peut s'logger...ah non, c'est de l'écriture pplus du log plus l'accès en consultation à cette partie du module...ah nan...merde, chais plus).
C'est difficile à débugger pour la même raison.
Enfin, en l'état, c'est insuffisant. Enfin...c'est suffisant pour un petit projet, ça ne l'est pas pour un gros. Il faut moduler plus, réfléchir intensément aux accès, aux groupes d'accès, aux profils utilisateur etc...et faire bien les choses de manière à pouvoir ajouter de nouveaux types d'accès par la suite. Mais ça...c'est après tout le lot commun de tout gros projet :-)

Globalement, je pense que la gestion des droits via les opérateurs binaires est plutôt une approche performante. Et elle est élégante, et permet une programmation "agile" si on s'y prend bien. Mais il y a d'autres solutions...
Utilisateur anonyme
22 déc. 2008 à 13:19
lut malalam, j'adore ce genre de source ;)
Betamax Messages postés 2 Date d'inscription mercredi 15 février 2006 Statut Membre Dernière intervention 23 décembre 2008
22 déc. 2008 à 08:41
salut ;)
par cette note ,je voudrai simplement dire bravo à notre cher malalam que nous apprécions beaucoup mais ça serai cool si tu nous disait ou son les inconvénients dans cette approche .
merci également à CS et à tous ceux qui y contribuent .
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
21 déc. 2008 à 19:14
Plop,

@Opossum_farceur : c'est presque trop technique pour moi... Presque, hein... Disons que j'ai tellement peu l'habitude d'utiliser les opérateurs sur les bits, que j'ai un peu de mal à me représenter quel est le résultat, quand m'en servir et surtout, comment ça marche...
Comment ça marche, je sais : quand je mets sur papier... Faut que je fasse des tableaux, tout ça... Je m'embrouille vite... Donc je plussoie au commentaire de Malalam : un petit tuto, ça pourrait être une super bonne idée, parce qu'effectivement, j'en étais arrivé à la même conclusion que lui quant à l'utilisation des opérateurs de bits par les jeunes développeurs.

@Malalam : pour la mail, je viens de m'y coller... C'est à ton tour. ^^
Sinon, excuse-moi d'avoir soulevé le point que tu ne souhaitais pas aborder lol Je prends ça comme un compliment sur ce coup là :) Et... Cette discussion naissante sur ce sujet que tu ne voulais pas montrer, ben... Ca confirme le bien fondé de notre projet (pu*$€ ça fait pas un an qu'on a commencé à en parler, mais pas loin !)

Allez, zou, bonne soirée à tous !

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.