*/ class LSldap { private static $config; private static $cnx = NULL; /** * Défini la configuration * * Cette methode définis la configuration de l'accès à l'annuaire * * @author Benjamin Renard * * @param[in] $config array Tableau de configuration au format Net_LDAP2 * * @retval void */ public static function setConfig ($config) { self :: $config = $config; } /** * Connect to LDAP server * * This method establish connection to LDAP server * * @author Benjamin Renard * * @param[in] $config array LDAP configuration array in format of Net_LDAP2 * * @retval boolean true if connected, false instead */ public static function connect($config = null) { if ($config) { self :: setConfig($config); } self :: $cnx = Net_LDAP2::connect(self :: $config); if (Net_LDAP2::isError(self :: $cnx)) { LSerror :: addErrorCode('LSldap_01',self :: $cnx -> getMessage()); self :: $cnx = NULL; return; } return true; } /** * Reconnect (or connect) with other credentials * * @author Benjamin Renard * * @param[in] $dn string Bind DN * @param[in] $pwd array Bind password * @param[in] $config array LDAP configuration array in format of Net_LDAP2 * * @retval boolean true if connected, false instead */ public static function reconnectAs($dn,$pwd,$config) { if ($config) { self :: setConfig($config); } if (self :: $cnx) { self :: $cnx -> done(); } $config=self :: $config; $config['binddn']=$dn; $config['bindpw']=$pwd; self :: $cnx = Net_LDAP2::connect($config); if (Net_LDAP2::isError(self :: $cnx)) { LSerror :: addErrorCode('LSldap_01',self :: $cnx -> getMessage()); self :: $cnx = NULL; return; } return true; } /** * Déconnection * * Cette methode clos la connexion à l'annuaire Ldap * * @author Benjamin Renard * * @retval void */ public static function close() { self :: $cnx -> done(); } /** * Recherche dans l'annuaire * * Cette methode effectue une recherche dans l'annuaire et retourne le resultat * de celle-ci sous la forme d'un tableau. * * @author Benjamin Renard * * @param[in] $filter [required] string Filtre de recherche Ldap * @param[in] $basedn string DN de base pour la recherche * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search() * * @see Net_LDAP2::search() * * @retval array Retourne un tableau associatif contenant : * - ['dn'] : le DN de l'entré * - ['attrs'] : tableau associatif contenant les attributs (clé) * et leur valeur (valeur). */ public static function search ($filter,$basedn=NULL,$params = array()) { $ret = self :: $cnx -> search($basedn,$filter,$params); if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode('LSldap_02',$ret -> getMessage()); return; } LSdebug("LSldap::search() : return ".$ret->count()." objet(s)"); $retInfos=array(); foreach($ret as $dn => $entry) { if (!$entry instanceof Net_LDAP2_Entry) { LSerror :: addErrorCode('LSldap_02',"LDAP search return an ".get_class($entry).". object"); continue; } $retInfos[]=array('dn' => $dn, 'attrs' => $entry -> getValues()); } return $retInfos; } /** * Compte le nombre de retour d'une recherche dans l'annuaire * * Cette methode effectue une recherche dans l'annuaire et retourne le nombre * d'entrés trouvées. * * @author Benjamin Renard * * @param[in] $filter [required] string Filtre de recherche Ldap * @param[in] $basedn string DN de base pour la recherche * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search() * * @see Net_LDAP2::search() * * @retval numeric Le nombre d'entré trouvées */ public static function getNumberResult ($filter,$basedn=NULL,$params = array() ) { if (empty($filter)) $filter=NULL; $ret = self :: $cnx -> search($basedn,$filter,$params); if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode('LSldap_02',$ret -> getMessage()); return; } return $ret -> count(); } /** * Charge les valeurs des attributs d'une entré de l'annuaire * * Cette methode recupère les valeurs des attributs d'une entrée de l'annaire * et les retournes sous la forme d'un tableau. * * @author Benjamin Renard * * @param[in] $dn string DN de l'entré Ldap * * @retval array Tableau associatif des valeurs des attributs avec en clef, le nom de l'attribut. */ public static function getAttrs($dn) { $infos = ldap_explode_dn($dn,0); if((!$infos)||($infos['count']==0)) return; $return=self :: search('(objectClass=*)',$dn); return $return[0]['attrs']; } /** * Retourne une entrée existante ou nouvelle * * @author Benjamin Renard * * @param[in] $object_type string Type de l'objet Ldap * @param[in] $dn string DN de l'entré Ldap * * @retval ldapentry|array Un objet ldapentry (PEAR::Net_LDAP2) * ou un tableau (si c'est une nouvelle entrée): * Array ( * 'entry' => ldapentry, * 'new' => true * ) */ public static function getEntry($object_type,$dn) { $obj_conf=LSconfig :: get('LSobjects.'.$object_type); if(is_array($obj_conf)){ $entry = self :: getLdapEntry($dn); if ($entry === false) { $newentry = self :: getNewEntry($dn,$obj_conf['objectclass'],array()); if (!$newentry) { return; } return array('entry' => $newentry,'new' => true); } else { return $entry; } } else { LSerror :: addErrorCode('LSldap_03'); return; } } /** * Retourne un object NetLDAP d'une entree existante * * @author Benjamin Renard * * @param[in] $dn string DN de l'entré Ldap * * @retval ldapentry|boolean Un objet ldapentry (PEAR::Net_LDAP2) ou false en * cas de problème */ public static function getLdapEntry($dn) { $entry = self :: $cnx -> getEntry($dn); if (Net_LDAP2::isError($entry)) { return false; } else { return $entry; } } /** * Retourne une nouvelle entrée * * @param[in] $dn string Le DN de l'objet * @param[in] $objectClass array Un tableau contenant les objectClass de l'objet * @param[in] $attrs array Un tabeau du type array('attr_name' => attr_value, ...) * * @retval mixed Le nouvelle objet en cas de succès, false sinon */ public static function getNewEntry($dn,$objectClass,$attrs,$add=false) { $newentry = Net_LDAP2_Entry::createFresh($dn,array_merge(array('objectclass' =>$objectClass),(array)$attrs)); if(Net_LDAP2::isError($newentry)) { return false; } if($add) { if(!self :: $cnx -> add($newentry)) { return; } } return $newentry; } /** * Met à jour une entrée dans l'annuaire * * Remarque : Supprime les valeurs vides de attributs et les attributs sans valeur. * * @author Benjamin Renard * * @param[in] $object_type string Type de l'objet Ldap * @param[in] $dn string DN de l'entré Ldap * @param[in] $change array Tableau des modifications à apporter * * @retval boolean true si l'objet a bien été mis à jour, false sinon */ public static function update($object_type,$dn,$change) { LSdebug($change); $dropAttr=array(); $entry=self :: getEntry($object_type,$dn); if (is_array($entry)) { $new = $entry['new']; $entry = $entry['entry']; } else { $new = false; } if($entry) { foreach($change as $attrName => $attrVal) { $drop = true; if (is_array($attrVal)) { foreach($attrVal as $val) { if (!empty($val)||(is_string($val)&&($val=="0"))) { $drop = false; $changeData[$attrName][]=$val; } } } else { if (!empty($attrVal)||(is_string($attrVal)&&($attrVal=="0"))) { $drop = false; $changeData[$attrName][]=$attrVal; } } if($drop) { $dropAttr[] = $attrName; } } if (isset($changeData)) { $entry -> replace($changeData); LSdebug('change :
'.print_r($changeData,true).'
'); LSdebug('drop :
'.print_r($dropAttr,true).'
'); } else { LSdebug('No change'); } if ($new) { LSdebug('LSldap :: add()'); $ret = self :: $cnx -> add($entry); } else { LSdebug('LSldap :: update()'); $ret = $entry -> update(); } if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode('LSldap_05',$dn); LSerror :: addErrorCode(0,'NetLdap-Error : '.$ret->getMessage()); } else { if (!empty($dropAttr) && !$new) { foreach($dropAttr as $attr) { $value = $entry -> getValue($attr); if(Net_LDAP2::isError($value) || empty($value)) { // Attribut n'existe pas dans l'annuaire continue; } // Méthode buggé : suppression impossible de certain attribut // exemple : jpegPhoto // $entry -> delete($attr); $entry -> replace(array($attr =>array())); } $ret = $entry -> update(); if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode('LSldap_06'); LSerror :: addErrorCode(0,'NetLdap-Error : '.$ret->getMessage()); } } return true; } } else { LSerror :: addErrorCode('LSldap_04'); return; } } /** * Test de bind * * Cette methode établie une connexion à l'annuaire Ldap et test un bind * avec un login et un mot de passe passé en paramètre * * @author Benjamin Renard * * @retval boolean true si la connection à réussi, false sinon */ public static function checkBind($dn,$pwd) { $config = self :: $config; $config['binddn'] = $dn; $config['bindpw'] = $pwd; $cnx = Net_LDAP2::connect($config); if (Net_LDAP2::isError($cnx)) { return; } return true; } /** * Retourne l'état de la connexion Ldap * * @retval boolean True si le serveur est connecté, false sinon. */ public static function isConnected() { return (self :: $cnx == NULL)?false:true; } /** * Supprime un objet de l'annuaire * * @param[in] string DN de l'objet à supprimer * * @retval boolean True si l'objet à été supprimé, false sinon */ public static function remove($dn) { $ret = self :: $cnx -> delete($dn,array('recursive' => true)); if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode(0,'NetLdap-Error : '.$ret->getMessage()); return; } return true; } /** * Déplace un objet LDAP dans l'annuaire * * @param[in] $old string Le DN actuel * @param[in] $new string Le futur DN * * @retval boolean True si l'objet a été déplacé, false sinon */ public static function move($old,$new) { $ret = self :: $cnx -> move($old,$new); if (Net_LDAP2::isError($ret)) { LSerror :: addErrorCode('LSldap_07'); LSerror :: addErrorCode(0,'NetLdap-Error : '.$ret->getMessage()); return; } return true; } /** * Combine LDAP Filters * * @params array Array of LDAP filters * * @retval Net_LDAP2_Filter | False The combined filter or False **/ public static function combineFilters($op,$filters,$asStr=false) { if (is_array($filters) && !empty($filters)) { if (count($filters)==1) { if ($asStr && $filters[0] instanceof Net_LDAP2_Filter) { return $filters[0]->asString(); } else { return $filters[0]; } } $filter=Net_LDAP2_Filter::combine($op,$filters); if (!Net_LDAP2::isError($filter)) { if ($asStr) { return $filter->asString(); } else { return $filter; } } else { LSerror :: addErrorCode(0,$filter -> getMessage()); } } return; } /** * Check LDAP Filters String * * @params string A LDAP filter as string * * @retval boolean True only if the filter could be parsed **/ public static function isValidFilter($filter) { if (is_string($filter) && !empty($filter)) { $filter=Net_LDAP2_Filter::parse($filter); if (!Net_LDAP2::isError($filter)) { return true; } else { LSerror :: addErrorCode(0,$filter -> getMessage()); } } return; } } /* * Error Codes */ LSerror :: defineError('LSldap_01', _("LSldap : Error during the LDAP server connection (%{msg}).") ); LSerror :: defineError('LSldap_02', _("LSldap : Error during the LDAP search (%{msg}).") ); LSerror :: defineError('LSldap_03', _("LSldap : Object type unknown.") ); LSerror :: defineError('LSldap_04', _("LSldap : Error while fetching the LDAP entry.") ); LSerror :: defineError('LSldap_05', _("LSldap : Error while changing the LDAP entry (DN : %{dn}).") ); LSerror :: defineError('LSldap_06', _("LSldap : Error while deleting empty attributes.") ); LSerror :: defineError('LSldap_07', _("LSldap : Error while changing the DN of the object.") );