Sahid Ferdjaoui Blog - Funraill Foundation Bienvenue, Log in - thème 2007 RC1

Powered by OpenSource Softwares

Outil de déboggage colaborative
reduire

Gestion des utilisateurs en PHP5 via l’utilisation de patterns

le 18 juillet 2007 par sahid

Concepts objets pour gérer ses utilisateurs via Singleton et Factory PHP

Ca faisait un petit moment que je ne rédigeais plus trop d’articles sur PHP, il est vrai que Python me prend pas mal de temps ces jours-ci, alors j’ai décidé de sortir mon Apache et ma DB préférée du sommeil pour voir un peu comment gérer dans une application ses utilisateurs. Bon comme d’habitude, je préviens, tout ça est le mix dans mon cerveau de nombreuses documentations ainsi que d’expériences personnelles, donc il se peut que la méthode que je vais présenter comprenne des erreurs et peut sans doute être améliorée.

Pour moi la grande force de PHP5 est sa partie objet, qui même si elle n’est pas encore parfaite, nous permet de travailler avec de nombreux design patterns (motif de conception) plutÃŽt intéressants. Dans un précédent article j’ai essayé de démontrer l’utilité des registres pour la conservation
et le transfert d’objet dans toutes les couches d’une application, ce soir je vais présenter le bien connu Singleton ainsi que l’excellente Factory.

Gestion des utilisateurs

Dans notre application, un utilisateur enregistré pourra soit être administrateur soit être invité. Un invité est un utilisateur de base, il a le droit en lecteur seul. Un administrateur lui, a le droit de lecture, écriture, modification. L’application va donc se découper en deux parties, la premiÚre sera la gestion des utilisateurs via le pattern Factory, la seconde sera la gestion de la base de donnée via le pattern Singleton.

Concept du Singleton

Le Singleton, est un des motifs de conception les plus connus, et un des plus pratiques. Il a sa place dans toutes sortes de classes. Il permet d’instancier une seule fois la classe ainsi dans toutes les couches de notre application on retrouvera la même instance. Pour ça, il utilise un constructeur privé qui sera appelé par une méthode public souvent nommée par convention “getInstance” celle-ci va mettre en attribut l’instance retournée par le constructeur, ainsi au nouvel appel de “getInstance” si notre objet a déjà été créée il le retourne, sinon il le créée. Le principe est assez simple ou plutÃŽt ingénieux ! seulement j’explique pas trÚs bien (; …un bout de code devrait nous éclairer.

  1. class unSingleton
  2. {
  3.   private static $_instance;
  4.   public static getInstance ()
  5.   {
  6.     if (is_null (self::$_instance)) {
  7.       self::$_instance = new unSingleton ();
  8.     }
  9.   }
  10.   private function __construct () {}

Concept de la Factory

Donc la Factory …ce pattern sert d’intermédiaire, son but est de retourner à notre application un objet du type qu’on souhaite. Pour ça, on lui passe en paramÚtre un ou plusieurs arguments, et via la définition de classe “modÚle” elle retournera l’objet adéquat. Cette fois-ci je vais plutÃŽt vous rediriger ver wikipedia, car ce pattern demande un peu plus de code, et on va l’utiliser pour gérer les utilisateurs.

Table utilisateur

Voila la table chargée de stocker les utilisateurs en base de données

  1. CREATE TABLE users (
  2.   id serial,
  3.   username varchar (40),
  4.   password varchar (40),
  5.   usrlevel bool,
  6. PRIMARY KEY (id)
  7. );

Les utilisateurs

Pour la gestion des utilisateurs, nous allons donc utiliser une Factory, dans un premier temps on définit la classe abstraite qui servira de modÚle aux autres classes, qui dériverons d’elle.

La classe User

  1. /**
  2.  * ModÚle Utilisateur
  3.  */
  4. abstract class User
  5. {
  6.         private $_username;
  7.         private $_password;
  8.         private $_usrlevel;
  9.        
  10.         public function __construct ($usr, $pwd, $lvl)
  11.         {
  12.                 $this->_username = $usr;
  13.                 $this->_password = $pwd;
  14.                 $this->_usrlevel = $lvl;
  15.         }
  16.  
  17.         public function canRead () { return true; }
  18.         public function canWrite () { return false; }
  19.         public function canModify () { return false; }
  20.  
  21.         public function getUsername () { return $this->_username; }
  22.         public function getPassword () { return $this->_password; }
  23.         public function getUsrlevel () { return $this->_usrlevel; }
  24. }

Maintenant ses dérivés

  1. /**
  2.  * Invité
  3.  */
  4. class GuestUser extends User {}
  5.  
  6. /**
  7.  * Administrateur
  8.  */
  9. class AdminUser extends User
  10. {
  11.         public function canRead () { return true; }
  12.         public function canWrite () { return true; }
  13.         public function canModify () { return true; }
  14. }

Nous disposons maintenant de tous les éléments nécessaires pour créer notre Factory.

  1. /**
  2.  * Retourne un objet de type User
  3.  * en fonction de son niveau
  4.  */
  5. class UserFactory
  6. {
  7.         public static function getUserFactory ($usr, $pwd, $lvl)
  8.         {
  9.                 if ($lvl == 0)
  10.                         return new AdminUser ($usr, $pwd, $lvl);
  11.                 if ($lvl == 1)
  12.                         return new GuestUser ($usr, $pwd, $lvl);
  13.         }
  14. }

Donc, en fonction d’un identifiant, d’un mot de passe ainsi que d’un niveau d’autorisation, notre Factory nous retournera un objet GuestUser, ou un objet AdminUser.

Nous allons à présent définir notre classe qui fera l’intéraction avec la base de données en utilisant le pattern Singleton. Celle-ci devra être capable d’enregistrer un utilisateur, ainsi que de retourner un utilisateur déjà enregistré. Pour l’enregistrement nous utiliserons la méthode “addUser” qui demandera en paramÚtre un objet de type User, ensuite pour la restauration d’un utilisateur, nous utiliserons la méthode “getUser” qui demandera en paramÚtre un identifiant ainsi qu’un mot de passe, celle-ci retournera grâce à notre Factory un objet de type User, soit Admin soit Invité.

  1. /**
  2.  * Gestion des utilisateurs avec la db
  3.  */
  4. class UserAuthSingleton
  5. {
  6.         private static $_instance;
  7.        
  8.         private $_dbh;
  9.         private $_tbl;
  10.        
  11.         /**
  12.          * Retourne une l’instance de la classe */
  13.         public static function getInstance ()
  14.         {
  15.                 if (is_null (self::$_instance)) {
  16.                         self::$_instance = new UserAuthSingleton ();
  17.                 }
  18.                 return self::$_instance;
  19.         }
  20.  
  21.         /**
  22.          * Constructeur. */
  23.         private function __construct ()
  24.         {
  25.                 $this->_dbh = new PDO (‘pgsql:host=localhost;dbname=users_db’, ’sahid’, ‘test’);
  26.                 $this->_dbh->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  27.                 $this->_tbl = "users";
  28.         }
  29.  
  30.         /**
  31.          * Ajoute un utilisateur. */
  32.         public function addUser (User $u)
  33.         {
  34.                 if ($this->userExist ($u->getUsername ())) {
  35.                                 throw new Exception ("Le nom d’utilisateur exist déjà ");
  36.                 }
  37.                 else {
  38.                         $sql = "
  39.                                insert into {$this->_tbl} (username, password, usrlevel)
  40.                                values (:usr, :pwd, :lvl);";
  41.  
  42.                         $stmt = $this->_dbh->prepare ($sql);
  43.                         $stmt->execute (array (":usr" => $u->getUsername (),
  44.                                                           ":pwd" => $u->getPassword (),
  45.                                                           ":lvl" => $u->getUsrlevel ()));
  46.                 }
  47.         }
  48.  
  49.         /**
  50.          * Retourne un utilisateur. */
  51.         public function getUser ($usr, $pwd)
  52.         {
  53.                 $sql = "
  54.                         select username, password, usrlevel
  55.                         from {$this->_tbl}
  56.                         where username = :usr and password = :pwd;";
  57.  
  58.                         $stmt = $this->_dbh->prepare ($sql);
  59.                         $stmt->bindParam (":usr", $usr);
  60.                         $stmt->bindParam (":pwd", sha1 ($pwd));
  61.                         $stmt->execute ();
  62.  
  63.                 // Retourne un objet User en fonction du level
  64.                 if ($stmt->rowCount () == 1) {
  65.                         $row = $stmt->fetchAll ();
  66.                         $user = UserFactory::getUser ($row[0][‘username’],
  67.                                                                     $row[0][‘password’],
  68.                                                                     $row[0][‘usrlevel’]);
  69.                         return $user;
  70.                 }
  71.                 else
  72.                         return false;
  73.         }
  74.  
  75.         public function userExist ($usr)
  76.         {
  77.                 $sql = "
  78.                         select username, password
  79.                         from {$this->_tbl}
  80.                         where username = :usr";
  81.  
  82.                 $stmt = $this->_dbh->prepare ($sql);
  83.                 $stmt->bindParam (":usr", $usr);
  84.                 $stmt->execute ();
  85.  
  86.                 if ($stmt->rowCount () > 0)
  87.                         return true;
  88.                 else
  89.                         return false;
  90.         }
  91. }

Testons tout ça

Création d’un nouvel utilisateur

  1. $user = UserFactory::getUserFactory ("sahid", sha1 ("foobar"), 0);
  2.  
  3. try {
  4.         UserAuthSingleton::getInstance ()->addUser ($user);
  5. }
  6. catch (Exception $e) {
  7.         echo $e->getMessage ();
  8. }

Récupération d’un utilisateur

  1. $user = UserAuthSingleton::getInstance ()->getUser ("sahid", "foobar");
  2. if ($user instanceof AdminUser)
  3.   echo $user->getUsername ()."est admin !";
  4. if ($user instanceof GuestUser)
  5.   echo $user->getUsername ()."est invité !";

En conclusion…

Voila comment peuvent être géré des utilisateurs avec un concept objet bien sur il peut y avoir bien plus de niveaux d’autorisation pour nos utilisateurs, et ceux-ci peuvent disposer de bien plus de propriétés, ensuite cette implémentation peut etre sans doute améliorée, le plus important étant la séparation des données.

10 commentaires pour Gestion des utilisateurs en PHP5 via l’utilisation de patterns

  1. Matt dit :

    Parfait que dire de plus, comme d’habitude :)

  2. Jean-Yves dit :

    Bravo pour ce beau concept objet !
    J’essaye maintenant d’adapter la class PDO en MySQLi et de faire __autoload($class_name) pour profiter à fond des nouveautés de PHP5 :) … et pour que ça fonctionne…
    J’ai pas encore tout compris sans un beau diagramme UML , mais avec l’ingénierie inverse d’une classe de zend je crois, on devrait pouvoir faire une belle image en jpeg.

    Dans tous les cas beau tuto.

    JY

  3. zeojex dit :

    Intéressant !
    Ce qui me dérange un peu c’est le fait que tu aies choisi le même nom de méthode au sein de deux classes différentes==> getUser(). Mais c’est secondaire…

    Merci pour ce tuto, il remet les idées en place.

    ZjX

  4. Sahid dit :

    ah voui c vrai, ca perd en clarté …

    Au niveau de la factory j’aurais peut être du nommer ma méthode getUserFactory () ou autre …
    surtout que jean yves n’a pas tort … un petit diagramme UML aurai été un plus… j’y penserai pour les prochains articles (;

  5. zeojex dit :
    1. UserAuthSingleton::getInstance ()->addUser ($user);

    Encore une petite remarque ;)
    Je démarre les patterns depuis peu et j’ai du mal à comprendre pourquoi une méthode “d’ajout d’utilisateur” (addUser) se trouve dans une classe d’authentification d’utilisateur “UserAuthSingleton” ?
    Dans le cas de la séparation des traitements j’organiserai différement les méthodes pour ma part. Mais peut-être n’ai-je pas encore bien compris l’utilisation des patterns !! ^^’

    Merci !

    ZjX

  6. sahid dit :

    ( ; … tu peux renommer la classe comme bon te semble.

    UserAuthSingleton est l’intermédiaire entre ta base de données et un objet utilisateur. développer une classe pour l’ajout des informations utilisateur en db et retrait des informations me parait inutile, néanmoins libre à toi de le faire ( :

  7. zeojex dit :

    Oui oui c’était bien dans ce sens que je considÚrais la chose.
    Le renommage de la classe suffit.

    a+

  8. Jeff dit :

    Bonjour,

    Peut-on utiliser un formulaire pour gerer les Utilisateurs ?

    Si oui, comment ?

    J’ai essayé, sans aucun succès.

    Merci

    Jaff

  9. Jeff dit :

    Bonjour,

    J’ai oublié de dire ceci :

    Cette ligne de code ne fonctionne pas avec ma configuration :

    66 # $user = UserFactory::getUser ($row[0][‘username’],

    Il me faut ajouter getUserFactory :

    $user = UserFactory::getUserFactory ($row[0]['username'],

    Merci de me dire pourquoi ?

    Jeff

  10. Grégoire dit :

    Bon tutoriel!

Ajouter un commentaire pour Gestion des utilisateurs en PHP5 via l’utilisation de patterns

  • levitra versus cialis
  • ingredient in phentermine
  • lipitor drug
  • generic trileptal
  • januvia 100 mg
  • gabapentin 100 mg
  • new anxiety drugs
  • keppra
  • reglan 10 mg
  • order prednisolone
  • fluticasone propionate
  • rogaine coupons
  • yasmin prescription
  • singulair 5 mg
  • sexual stamina tips
  • alavert drug
  • revatio 20 mg
  • lexapro drugs
  • european pharmacy anxiety
  • attacking anxiety and depression
  • cheap retin a
  • drugs for depression
  • cialis table
  • singulair 10 mg
  • penis enlargement exercises
  • cephalexin sinus
  • phentermine no prescription
  • order nolvadex
  • green tea pill
  • cialis advertisement
  • supplement hoodia
  • cheap viamax
  • valium without prescription
  • fosamax generic
  • cialis name brand cheap
  • ambien dosage
  • viagra and blood pressure
  • xanax rx
  • order viagra without prescription
  • atacand
  • buy prandin
  • cheap yohimbe
  • half life of valium
  • order capoten
  • alprazolam cheap
  • buy cialis by check
  • vitamins for erectile dysfunction
  • klonopin medication
  • drugs used to treat depression
  • online claritin
  • buy cialis online uk
  • benadryl loratadine
  • anxiety meds online
  • asthma in elderly
  • propecia 1mg
  • levitra vardenafil generic
  • cialis online discount
  • order cialis professional
  • clomid treatment
  • medicine xanax
  • methylsulfonylmethane
  • xanax mechanism of action
  • pharmacy online australia
  • cialis vs viagra
  • order lisinopril
  • viagra online best price
  • increase penis size with herbs
  • oxybutynin
  • bayer levitra online pharmacy
  • phentermine consultation
  • free levitra samples
  • acticin cream
  • ventolin inhalador
  • natural viagra substitute
  • glipizide side effects
  • benadryl dosing
  • new treatments for lung diseases
  • viagra jelly
  • types of antidepressants
  • perennial allergic rhinitis
  • mebendazole
  • levitra ad
  • cheap hangover helper
  • interaction zocor
  • cheapest cialis generic
  • cialis cost low
  • clonazepam .5mg
  • kamagra oral jelly
  • ativan no prescription
  • gerd in children
  • prozac social anxiety
  • antidepressant pill high
  • how to cure depression
  • use imitrex
  • cheap robaxin
  • what are the effects of klonopin
  • how to buy viagra online
  • coral calcium
  • canada in levitra
  • cheap viagra pill
  • discount levitra purchase
  • buy levothroid
  • purchase vardenafil
  • online tramadol
  • cialis dosage 20mg
  • viagra soft tab
  • norvasc 10
  • sample ambien
  • lamictal drug
  • herb echinacea
  • effects side ultram
  • endep
  • bayer levitra professional pro
  • addiction ultram
  • giant eagle pharmacy
  • benfotiamine
  • green tea capsule
  • cheap male enhancement
  • order caffeine
  • how much is viagra
  • drug ceftin
  • sumatriptan
  • cialis tablet
  • danazol
  • soma the drug
  • medication for bipolar disorder
  • cozaar medication
  • recreational use of xanax
  • cheap avandia
  • zithromax medication
  • buy lorazepam without prescription
  • reglan side effects
  • drug skelaxin
  • canada pharmacy viagra
  • buy zelnorm
  • phentermine no prescription overnight
  • impotence depression
  • buy ampicillin
  • levitra for sale
  • viagra patent lawsuit levitra
  • cialis vs viagra vs levitra
  • metformin hcl 500mg
  • ways to relieve anxiety
  • order rimonabant
  • natural prednisone
  • generic orlistat
  • nitroglycerin sublingual
  • wellbutrin paxil
  • schizophrenia drugs new zealand
  • lasix furosemide
  • unisom online
  • viagra half price pharmacy
  • manufacturer of revatio
  • clomiphene tablets
  • valium low cost
  • vpxl uk
  • ibuprofen
  • buy probenecid
  • buy etodolac
  • cialis canadian generic
  • stop smoking gum
  • order topamax
  • celebrex pharmacy
  • stop smoking zyban
  • purchase cheap cialis online
  • children aspirin
  • treatment for impotence
  • cialis line order
  • what prednisone
  • buy cialis by the pill
  • buying ultram no prescription
  • venlafaxin
  • buy generic tramadol no prescription
  • allegra side effects
  • prescription nexium
  • order starlix
  • serevent
  • soft tab viagra
  • effects of premarin
  • cheap lovastatin
  • order amantadine
  • viagra and cialis
  • discount levitra online
  • meds for erectile dysfunction
  • sale carisoprodol
  • effects propecia
  • on rx legal diazepam
  • effects of viagra on women
  • buy generic allergy medication
  • ciallis or viagra
  • cheap imitrex
  • order amoxicillin
  • ativan normal doses
  • generic cialis soft
  • purchase phentermine mexico
  • saw palmetto products
  • buy ativan online
  • discount soma online
  • allegra order
  • genric viagra