[php5] package users - gestion utilisateurs - les iterateurs en php

Soyez le premier à donner votre avis sur cette source.

Vue 12 795 fois - Téléchargée 1 321 fois

Description

Bon, toujours dans ma croisade pour faire découvrir la SPL, voici un nouveau package.
C'est une gestion utilisateur basique.
Je fournis une classe db basique, avec juste ce dont j'ai besoin. VOus pouvez utiliser la votre, mais attention, certaines méthodes doivent être implémentées, avec ces noms (sinon, cherchez leur utilisation dans la classe oUser et modifiez les appels) :
fetch_assoc ()
query ()
insert_id
C'est tout :-)

Le package gère ceci :
identification d'un utilisateur
création d'un utilisateur
récupération d'un utilisateur
modification d'un utilisateur

Le tout, évidemment, avec gestion des sessions.

je montre 2 exemples:
test.php fait un tour sur les possibilités d'itération, essentiellement.
exemple.php montre une page de formulaire d'identification, avec création à la volée si un utilisateur n'existe pas, identification s'il existe et possibilité de modifier son nom, et gestion d'erreur si il se plante d'identification.

Le tout est basé sur un fichier de configuration XML.
Ce fichier se présente obligatoirement ainsi :
sous la racine, un noeud USER et un noeud SESSION
Dans USER, un noeud ID obligatoire, idem pour SESSION.
Les autres noeuds sous USER et SESSION sont à votre préférence!
Les sous noeuds pour chaque propriétés :
BDD_NAME est le nom du champ dans votre table.
TYPE est son type (en fait, string ou int)
Ca, c'est obligatoire.
Ensuite : IDENT indique que ce champ est utilisé pour l'identification.
MANDATORY indique qu'il est obligatoire pour la création d'un utilisateur (s'il manque, la création renverra une erreur)
DEDOUBLE indique qu'on dédoublonne la table sur ce (ou ces) champ. Exemple, un mec entre un email et un mot de passe; vous dédoublonnez sur l'email : si le couple email/password existe, ok, le mec est identifié. Sinon, si email existe, le mec s'est planté de mot de passe (c'est là le dédoublonnage). Sinon, ben il n'existe pas.

Vous pouvez ajouter autant de champs que vous voulez, pour peu que vous les ayez dans votre table utilisateur, évidemment... : adresse, code postal, ville, etc...
Idem pour la session.

La table créée pour les 2 fichiers exemples :
sous mysql
nom base de donnée : bdd_test
nom table : users
champs :
user_id (int) autoincrement
user_email (varchar)
user_pwd (varchar)
user_nom (varchar)

à vous de la créer.
Voili :-)

Source / Exemple :


<?php
/**

  • oUser package
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
  • /
if (!class_exists ('RecursiveArrayIterator')) { // PHP5 < 5.1 /**
  • class RecursiveArrayIterator
  • @author php.net
  • implementation for PHP5 < 5.1
  • /
class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator { private $ref; function hasChildren () { return is_array ($this -> current ()); } function getChildren () { if ($this -> current () instanceof self) { return $this -> current (); } if (empty ($this -> ref)) { $this -> ref = new ReflectionClass ($this); } return $this -> ref -> newInstance ($this -> current ()); } } } /**
  • class oUserException extends Exception
  • personalized Exception class for this package
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
  • /
class oUserException extends Exception { const ERROR_GEN_NOT_SETABLE = '{__PROP__} is not a setable property'; const ERROR_GEN_NOT_GETABLE = '{__PROP__} is not a getable property'; const ERROR_USER_PROP_NOT_EXISTS = '{__PROP__} property does not exist'; const ERROR_USER_PROP_HAS_NO_VALUE = '{__PROP__} property has no value'; const ERROR_USER_XML_KEY_NOT_COMPLETE = '{__KEY__} has no children'; const ERROR_USER_XML_FILE_NOT_EXISTS = '{__FILE__} has not been found'; const ERROR_USER_XML_LOADING_FAILED = 'Failed to load {__FILE__}'; const ERROR_USER_CHECKIDENT_BAD_VALUES_COUNT = 'Values given in arguments and Authentication fields do not match'; const ERROR_USER_MANDATORY_FIELD_MISSING = 'The mandatory field {__FIELD__} is missing'; const ERROR_USER_ID_NOT_INTEGER = 'User ID must be an integer'; public function __construct($sMsg, $iCode = 0) { parent::__construct($sMsg, $iCode); } } /**
  • class myFilter extends FilterIterator
  • filter Iterator class dedicated to oUser class
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
  • /
class myFilter extends FilterIterator { /**
  • private oIt
  • Iterator object
  • @var Iterator
  • /
private $oIt = null; /**
  • private mFilter
  • main filter
  • @var string
  • /
private $mFilter = null; /**
  • public function __construct
  • constructor
*
  • @param (RecursiveIteratorIterator) oIt
  • @param (string) mFilter
  • /
public function __construct (RecursiveIteratorIterator $oIt, $mFilter = null) { parent::__construct ($oIt); $this -> oIt = $oIt; $this -> mFilter = $mFilter; } /**
  • public function accept
*
  • @return (boolean)
  • /
public function accept () { if (!is_null ($this -> mFilter)) { if ($this -> oIt -> key () === $this -> mFilter && $this -> oIt -> getDepth () === 0) { return true; } if ($this -> oIt -> key () === $this -> mFilter && $this -> oIt -> getDepth () === 1) { return true; } if ($this -> oIt -> getDepth () > 0 && $this -> oIt -> getSubIterator (0) -> key () === $this -> mFilter) { return true; } return false; } return true; } } /**
  • abstract class abstractUser
  • abstraction class defining oUser
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
  • /
abstract class abstractUser { /**
  • protected aCanBeGet
  • array of properties that can be get
  • @var array
  • /
protected $aCanBeGet = array ( 'FILTER', 'SUBFILTER', 'ITMODE' ); /**
  • protected aCanBeSet
  • array of properties that can be set
  • @var array
  • /
protected $aCanBeSet = array ( 'FILTER', 'SUBFILTER', 'ITMODE' ); /**
  • protected cItMode
  • RecursiveIteratorIterator mode
  • @var RecursiveIteratorIterator constant
  • /
protected $cItMode = true; /**
  • protected mFilter
  • main filter
  • @var string
  • /
protected $mFilter = null; /**
  • protected aProps
  • array of properties
  • @var array
  • /
protected $aProps = array (); /**
  • public oSession
  • oSession object
  • @var oSession
  • /
public $oSession = null; /**
  • protected oXml
  • simpleXML object
  • @var simpleXML
  • /
protected $oXml = null; /**
  • public function __construct
  • constructor
  • @param (string) $fXml : xml config filename
  • /
public function __construct ($fXml) { if (!file_exists ($fXml)) { throw new oUserException (str_replace ('{__FILE__}', $fXml, oUserException::ERROR_USER_XML_FILE_NOT_EXISTS)); } if (!($this -> oXml = @simplexml_load_file ($fXml)) instanceof SimpleXMLElement) { throw new oUserException (str_replace ('{__FILE__}', $fXml, oUserException::ERROR_USER_XML_LOADING_FAILED)); } $this -> oSession = new oSession ($this -> oXml); $this -> aPropsFill (); } /**
  • private function aPropsFill
  • fills the array of properties aProps from oXml
  • /
private function aPropsFill () { foreach ($this -> oXml -> USER -> children () as $oNode) { $aTmp = array (); foreach ($oNode -> children() as $oChild) { $aTmp[(string)dom_import_simplexml($oChild) -> tagName] = (string)$oChild['value']; } if (empty ($aTmp)) { throw new oUserException (str_replace ('{__KEY__}', (string)dom_import_simplexml($oNode) -> tagName, self::ERROR_XML_KEY_NOT_COMPLETE)); } $this -> aProps[(string)dom_import_simplexml($oNode) -> tagName] = $aTmp; } } /**
  • public function __get
  • getter
  • @param (string) sProp
  • @return sProp value
  • /
public function __get ($sProp) { if (!in_array ($sProp, $this -> aCanBeGet) && !array_key_exists ($sProp, $this -> aProps)) { throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_GEN_NOT_GETABLE)); } switch ($sProp) { case 'FILTER' : return $this -> mFilter; break; case 'SUBFILTER' : return $this -> mSubFilter; break; case 'ITMODE' : return $this -> cItMode; break; default : if (!isset ($this -> aProps[$sProp])) { throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_USER_NOT_EXISTS)); } if (!is_null ($this -> mFilter)) { if (isset ($this -> aProps[$sProp][$this -> mFilter])) { return $this -> aProps[$sProp][$this -> mFilter]; } } if (!isset ($this -> aProps[$sProp]['VALUE'])) { //throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_USER_PROP_HAS_NO_VALUE)); return null; } return $this -> aProps[$sProp]['VALUE']; break; } } /**
  • public function __set
  • setter
  • @param (string) sProp
  • @param (mixed) mVal
  • @return void
  • /
public function __set ($sProp, $mVal) { if (!array_key_exists ($sProp, $this -> aProps) && !in_array ($sProp, $this -> aCanBeSet)) { throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_GEN_NOT_SETABLE)); } switch ($sProp) { case 'FILTER' : $this -> mFilter = $mVal; break; case 'ITMODE' : $this -> cItMode = $mVal; break; default : $this -> aProps[$sProp]['VALUE'] = $mVal; break; } } /**
  • public function getProps
  • get the aProps array of properties
  • @return RecursiveIteratorIterator or myFilter Iterator
  • /
public function getProps () { if (!is_null ($this -> mFilter)) { if (is_string ($this -> mFilter)) { return new myFilter (new RecursiveIteratorIterator (new RecursiveArrayIterator ($this -> aProps), $this -> cItMode), $this -> mFilter); } } return new RecursiveIteratorIterator (new RecursiveArrayIterator ($this -> aProps), $this -> cItMode); } /**
  • abstract public function checkIdent
  • check if a user exists in the database, given IDENT fields in the xml config file
  • @param (string) sTable : users DB table name
  • @param (array) aValues : array of fields to be checked, each key being the key of the config file, and the value being the input value
  • /
abstract public function checkIdent ($sTable, $aValues); /**
  • abstract public function createUser
  • create a user if values are correct
  • @param (string) sTable : users db table name
  • @param (array) aValues : array of fields to be created, each key being the key of the config file, and the value being the input value
  • /
abstract public function createUser ($sTable, $aValues); /**
  • abstract public function getUser
  • get a user from DB
  • @param (mixed) iUserId : existing user ID in the DB
  • @param (string) sTable : users db table name
  • @param (boolean) bSession : true if get values must fill the session (if config file defines these fields for the session), false if not
  • /
abstract public function getUser ($iUserId, $sTable, $bSession = true); /**
  • abstract public function modUser
  • modify a user in DB
  • @param (mixed) iUserId : existing user ID in the DB
  • @param (string) sTable : users db table name
  • @param (array) aValues : array of fields to be modified, each key being the key of the config file, and the value being the input value
  • @param (boolean) bSession : true if get values must fill the session (if config file defines these fields for the session), false if not
  • /
abstract public function modUser ($iUserId, $sTable, $aValues, $bSession = true); } /**
  • class oSession
  • session class
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
*
  • see abstractUser for info about the methods and properties of this class, same definitions apply here
  • /
class oSession { private $aProps = array (); private $oXml; public function __construct (simpleXMLElement $oXml) { $sSessionId = session_id (); if (empty ($sSessionId)) { session_start (); } $this -> oXml = $oXml; $this -> aPropsFill (); } private function aPropsFill () { foreach ($this -> oXml -> SESSION -> children () as $oNode) { $this -> aProps[(string)dom_import_simplexml($oNode) -> tagName] = null; } } public function __get ($sProp) { if (!array_key_exists ($sProp, $this -> aProps)) { throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_GEN_NOT_SETABLE)); } return $this -> aProps[$sProp]; } public function __set ($sProp, $mVal) { if (!array_key_exists ($sProp, $this -> aProps)) { throw new oUserException (str_replace ('{__PROP__}', $sProp, oUserException::ERROR_GEN_NOT_GETABLE)); } $this -> aProps[$sProp] = $mVal; $_SESSION['USER'][$sProp] = $mVal; } public function __isset ($sProp) { if (!array_key_exists ($sProp, $this -> aProps)) { return false; } return true; } } /**
  • class oUser extends abstractUser
  • user class
  • @author Johan Barbier <johan.barbier@gmail.com>
  • @version 20061124
*
  • see abstractUser for info about the methods and properties of this class, same definitions apply here
  • /
class oUser extends abstractUser { private $oDB; public function __construct ($sXml, $oDB) { parent::__construct ($sXml); $this -> oDB = $oDB; } public function checkIdent ($sTable, $aValues) { $sTmp = $this -> mFilter; $this -> mFilter = 'IDENT'; $aProps = $this -> getProps (); foreach ($aProps as $sV) { $sKeyName = $aProps -> getInnerIterator () -> getSubIterator (0) -> key (); $sCurrentDbName = $this -> aProps [$sKeyName]['BDD_NAME']; if (empty ($aValues[$sKeyName])) { throw new oUserException (oUserException::ERROR_USER_CHECKIDENT_BAD_VALUES_COUNT); } if ($this -> aProps[$sKeyName]['TYPE'] === 'string') { if (isset ($this -> aProps[$sKeyName]['DEDOUBLE'])) { $aDedoub[] = $sCurrentDbName.' = \''.$aValues[$sKeyName].'\''; } $aIdent[] = $sCurrentDbName.' = \''.$aValues[$sKeyName].'\''; } else { if (isset ($this -> aProps[$sKeyName]['DEDOUBLE'])) { $aDedoub[] = $sCurrentDbName.' = '.$aValues[$sKeyName]; } $aIdent[] = $sCurrentDbName.' = '.$aValues[$sKeyName]; } } $this -> mFilter = $sTmp; if (count ($aValues) !== count ($aIdent)) { throw new oUserException (oUserException::ERROR_USER_CHECKIDENT_BAD_VALUES_COUNT); } $sWhereClause = implode (' AND ', $aIdent); $sQuery = 'SELECT '.$this -> aProps['ID']['BDD_NAME'].' FROM '.$sTable.' WHERE '.$sWhereClause; $this -> oDB -> query ($sQuery); $aRes = $this -> oDB -> fetch_assoc (); if (!empty ($aRes[$this -> aProps['ID']['BDD_NAME']])) { $this -> oSession -> ID = $aRes[$this -> aProps['ID']['BDD_NAME']]; return true; } else { if (!empty ($aDedoub)) { $sWhereDedoubClause = implode (' AND ', $aDedoub); $sQuery = 'SELECT '.$this -> aProps['ID']['BDD_NAME'].' FROM '.$sTable.' WHERE '.$sWhereDedoubClause; $this -> oDB -> query ($sQuery); $aRes = $this -> oDB -> fetch_assoc (); if (!empty ($aRes[$this -> aProps['ID']['BDD_NAME']])) { return -1; } } return false; } } public function createUser ($sTable, $aValues) { $sTmp = $this -> mFilter; $this -> mFilter = 'MANDATORY'; $aProps = $this -> getProps (); foreach ($aProps as $sK => $sV) { $sMandatory = $aProps -> getInnerIterator () -> getSubIterator (0) -> key (); if (empty ($aValues[$sMandatory])) { throw new oUserException (str_replace ('{__FIELD__}', $sMandatory, oUserException::ERROR_USER_MANDATORY_FIELD_MISSING)); } } $this -> mFilter = 'BDD_NAME'; $aProps = $this -> getProps (); foreach ($aProps as $sV) { $sKeyName = $aProps -> getInnerIterator () -> getSubIterator (0) -> key (); if (!empty ($aValues[$sKeyName])) { $aFields[] = $sV; if ($this -> aProps [$aProps -> getInnerIterator () -> getSubIterator (0) -> key ()]['TYPE'] === 'string') { $aVals[] = '\''.$aValues[$sKeyName].'\''; } else { $aVals[] = $aValues[$sKeyName]; } } } $this -> mFilter = $sTmp; $sFields = implode (',', $aFields); $sVals = implode (',', $aVals); $sQuery = 'INSERT INTO '.$sTable.' ('.$sFields.') VALUES ('.$sVals.')' ; if ($this -> oDB -> query ($sQuery)) { $this -> oSession -> ID = $this -> oDB -> insert_id (); return true; } return false; } public function getUser ($iUserId, $sTable, $bSession = true) { $sTmp = $this -> mFilter; $this -> mFilter = 'BDD_NAME'; $aProps = $this -> getProps (); foreach ($aProps as $sV) { $aFields[] = $sV; } $sFields = implode (',', $aFields); $sQuery = 'SELECT '.$sFields.' FROM '.$sTable.' WHERE '.$this -> aProps['ID']['BDD_NAME'].' = '.$iUserId; $this -> oDB -> query ($sQuery); $aRes = $this -> oDB -> fetch_assoc (); if (empty ($aRes)) { return false; } foreach ($aProps as $sV) { $sKeyName = $aProps -> getInnerIterator () -> getSubIterator (0) -> key (); $this -> aProps[$sKeyName]['VALUE'] = $aRes[$sV]; // PHP5 < 5.1 if (true === $bSession && true === $this -> oSession -> __isset ($sKeyName)) { $this -> oSession -> $sKeyName = $aRes[$sV]; } /*PHP5 >= 5.1 if (true === $bSession && true === isset ($this -> oSession -> $sKeyName)) { $this -> oSession -> $sKeyName = $aRes[$sV]; }
  • /
} $this -> mFilter = $sTmp; return true; } public function modUser ($iUserId, $sTable, $aValues, $bSession = true) { $sTmp = $this -> mFilter; $this -> mFilter = 'BDD_NAME'; $aProps = $this -> getProps (); foreach ($aProps as $sV) { $sKeyName = $aProps -> getInnerIterator () -> getSubIterator (0) -> key (); if (!empty ($aValues[$sKeyName])) { if ($this -> aProps [$aProps -> getInnerIterator () -> getSubIterator (0) -> key ()]['TYPE'] === 'string') { $aVals[] = $sV.'= \''.$aValues[$sKeyName].'\''; } else { $aVals[] = $sV.'='.$aValues[$sKeyName]; } // PHP5 < 5.1 if (true === $bSession && true === $this -> oSession -> __isset ($sKeyName)) { $this -> oSession -> $sKeyName = $aValues[$sKeyName]; } } } $this -> mFilter = $sTmp; if (empty ($aVals)) { return false; } $sVals = implode (',', $aVals); $sQuery = 'UPDATE '.$sTable.' SET '.$sVals.' WHERE '.$this -> aProps['ID']['BDD_NAME'].' = '.$iUserId; if ($this -> oDB -> query ($sQuery)) { return true; } return false; } } ?>

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Naixn Messages postés 455 Date d'inscription mardi 17 septembre 2002 Statut Membre Dernière intervention 22 juillet 2007
24 nov. 2006 à 14:14
Hé bé, c'est un truc bien complet.
J'ai pas testé, parceque 1/ je sais que ça marche 2/ Flemme de créer une table MySQL, mais sinon ça m'a l'air bien complet.

Juste deux remarques, notemment au niveau de dbfactory :
1/ Même pas utilisé les réflexions, tssss :p
2/ Je ne vois pas du tout à quoi te sert ton __construct ? Vu qu'il est protégé, et que tu utilise le singleton, il ne peut donc être qu'appelé par des classes filles, mais... Tu ne te serts ni de la fonction dbfactory::singleton(), ni de parent::__construct dans la classe qui étend dbfactory.

D'ailleurs, je remarque aussi qu'en fait tu n'utilises même pas la méthode singleton : ta fonction dbfactory::factory() te retourne à chaque fois une nouvelle instance de la classe, même si une instance a déjà été créée.

Après, si c'est volontaire, à savoir que tu utilises une classe générique pour différentes utilisations, alors là je comprends mieux. Mais il est vrai que je ne suis pas habitué à voir du code non utilisé dans des trucs d'exemples XD.
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
24 nov. 2006 à 14:48
Hello,

à dire vrai, j'ai pris une classe incomplète pour la DB, vu que ce n'était pas du tout le sujet de ce package. J'ai juste réécrit rapidement ce qui me manquait. Je mise plutôr sur le fait que les gens vont utiliser leur propre classe de DB.
Mais pour te répondre : j'ai 2 classes : une pour mysql, et une pour mssql en réalité. Là, je n'ai mis que mysql.
Le constructeur de la classe parente est automatiquement utilisé, vu que les filles n'en ont pas.
Le singleton est optionnel, simplement, je le règle si je veux un singleton. En général, je n'en veux pas, car j'utilise souvent plusieurs serveurs de bdd (à mon taf en tous cas).
Mais il est là, juste au cas où...j'aurais pu l'utiliser ici en effet. Mais bon...je t'ai dit, la classe est juste là comme support au package, parce qu'il me fallait bien une classe DB.
Ce n'est même pas la classe DB que j'utilise généralement, mais la mienne est exclusivement mssql.
Naixn Messages postés 455 Date d'inscription mardi 17 septembre 2002 Statut Membre Dernière intervention 22 juillet 2007
24 nov. 2006 à 15:18
Ok, c'est bien ce que je pensais :)

Bon boulot quoiqu'il en soit. C'est marrant que tu t'amuses à appliquer les itérateurs un peu partout en tout cas :)

Bonne continuation ;)
soundpanther Messages postés 68 Date d'inscription vendredi 27 juillet 2007 Statut Membre Dernière intervention 31 janvier 2009
4 mai 2008 à 17:12
j'aime bien
Azorkast Messages postés 1 Date d'inscription vendredi 28 janvier 2011 Statut Membre Dernière intervention 29 janvier 2011
29 janv. 2011 à 11:34
Merci bcp pour ce code !

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.