*/ class LSldapObject { var $config; var $type_name; var $attrs; var $forms; var $dn=false; var $other_values=array(); var $submitError=true; /** * Constructeur * * Cette methode construit l'objet et définis la configuration. * Elle lance la construction du tableau d'attributs représentés par un objet LSattribute. * * @author Benjamin Renard * * @param[in] $type_name [required] string Le nom du type de l'objet * @param[in] $config array La configuration de l'objet * * @retval boolean true si l'objet a été construit, false sinon. */ function LSldapObject($type_name,$config='auto') { $this -> type_name = $type_name; $this -> config = $config; if($config=='auto') { if(isset($GLOBALS['LSobjects'][$type_name])) $this -> config = $GLOBALS['LSobjects'][$type_name]; else { $GLOBALS['LSerror'] -> addErrorCode(21); return; } } foreach($this -> config['attrs'] as $attr_name => $attr_config) { if(!$this -> attrs[$attr_name]=new LSattribute($attr_name,$attr_config,$this)) { return; } } return true; } /** * Charge les données de l'objet * * Cette methode définis le DN de l'objet et charge les valeurs de attributs de l'objet * à partir de l'annuaire. * * @author Benjamin Renard * * @param[in] $dn string Le DN de l'objet. * * @retval boolean true si la chargement a réussi, false sinon. */ function loadData($dn) { $this -> dn = $dn; $data = $GLOBALS['LSldap'] -> getAttrs($dn); foreach($this -> attrs as $attr_name => $attr) { if(!$this -> attrs[$attr_name] -> loadData($data[$attr_name])) return; } return true; } /** * Recharge les données de l'objet * * @author Benjamin Renard * * @retval boolean true si la rechargement a réussi, false sinon. */ function reloadData() { $data = $GLOBALS['LSldap'] -> getAttrs($this -> dn); foreach($this -> attrs as $attr_name => $attr) { if(!$this -> attrs[$attr_name] -> reloadData($data[$attr_name])) return; } return true; } /** * Retourne le format d'affichage de l'objet * * @author Benjamin Renard * * @retval string Format d'affichage de l'objet. */ function getDisplayAttributes() { return $this -> config['select_display_attrs']; } /** * Retourne la valeur descriptive d'affichage de l'objet * * Cette fonction retourne la valeur descriptive d'affichage de l'objet en fonction * du format défini dans la configuration de l'objet ou spécifié en paramètre. * * @author Benjamin Renard * * @param[in] $spe [optionnel] string Format d'affichage de l'objet * * @retval string Valeur descriptive d'affichage de l'objet */ function getDisplayValue($spe) { if ($spe=='') { $spe = $this -> getDisplayAttributes(); } return $this -> getFData($spe,&$this -> attrs,'getDisplayValue'); } /** * Chaine formatée * * Cette fonction retourne la valeur d'une chaine formatée en prennant les valeurs * de l'objet. * * @author Benjamin Renard * * @param[in] $format string Format de la chaine * * @retval string Valeur d'une chaine formatée */ function getFData($format) { $format=getFData($format,$this,'getValue'); return $format; } /** * Construit un formulaire de l'objet * * Cette méthode construit un formulaire LSform à partir de la configuration de l'objet * et de chaque attribut. * * @param[in] $idForm [required] Identifiant du formulaire a créer * @param[in] $config Configuration spécifique pour le formulaire * * @author Benjamin Renard * * @retval LSform Le formulaire crée */ function getForm($idForm,$config=array()) { $LSform = new LSform($this,$idForm); $this -> forms[$idForm] = array($LSform,$config); foreach($this -> attrs as $attr_name => $attr) { if(!$this -> attrs[$attr_name] -> addToForm($LSform,$idForm,$this)) { $LSform -> can_validate = false; } } return $LSform; } /** * Rafraichis le formulaire de l'objet * * Cette méthode recharge les données d'un formulaire LSform. * * @param[in] $idForm [required] Identifiant du formulaire a créer * * @author Benjamin Renard * * @retval boolean true sile formulaire a été rafraichis, false sinon */ function refreshForm($idForm) { $LSform = $this -> forms[$idForm][0]; foreach($this -> attrs as $attr_name => $attr) { if(!$this -> attrs[$attr_name] -> refreshForm($LSform,$idForm)) { return; } } return true; } /** * Met à jour les données de l'objet et de l'entré de l'annuaire * * Met à jour les données de l'objet à partir d'un retour d'un formulaire. * * @param[in] $idForm Identifiant du formulaire d'origine * * @author Benjamin Renard * * @retval boolean true si la mise à jour a réussi, false sinon * * @see validateAttrsData() * @see submitChange() */ function updateData($idForm=NULL) { if($idForm!=NULL) { if(isset($this -> forms[$idForm])) $LSform = $this -> forms[$idForm][0]; else { $GLOBALS['LSerror'] -> addErrorCode(22,$this -> type_name); return; } } else { if(count($this -> forms) > 0) { reset($this -> forms); $idForm = key($this -> forms); $LSform = current($this -> forms); $config = $LSform[1]; $LSform = $LSform[0]; } else { $GLOBALS['LSerror'] -> addErrorCode(23,$this -> type_name); $GLOBALS['LSerror'] -> stop(); } } $new_data = $LSform -> exportValues(); foreach($new_data as $attr_name => $attr_val) { if(isset($this -> attrs[$attr_name])) { $this -> attrs[$attr_name] -> setUpdateData($attr_val); } } if($this -> validateAttrsData($idForm)) { debug("les données sont validées"); if(isset($this -> config['before_save'])) { if(function_exists($this -> config['before_save'])) { if(!$this -> config['before_save']($this)) { $GLOBALS['LSerror'] -> addErrorCode(28,$this -> config['before_save']); $GLOBALS['LSerror'] -> stop(); } } else { $GLOBALS['LSerror'] -> addErrorCode(27,$this -> config['before_save']); $GLOBALS['LSerror'] -> stop(); } } if ($this -> submitChange($idForm)) { debug('Les modifications sont submitées'); $this -> submitError = false; $this -> reloadData(); $this -> refreshForm($idForm); } if((isset($this -> config['after_save']))&&(!$this -> submitError)) { if(function_exists($this -> config['after_save'])) { if(!$this -> config['after_save']($this)) { $GLOBALS['LSerror'] -> addErrorCode(30,$this -> config['after_save']); } } else { $GLOBALS['LSerror'] -> addErrorCode(29,$this -> config['after_save']); } } } } /** * Valide les données retournées par un formulaire * * @param[in] $idForm Identifiant du formulaire d'origine * * @author Benjamin Renard * * @retval boolean true si les données sont valides, false sinon */ function validateAttrsData($idForm) { $LSform=$this -> forms[$idForm][0]; foreach($this -> attrs as $attr) { if (!$attr -> isValidate()) { if($attr -> isUpdate()) { if (!$this -> validateAttrData($LSform, $attr)) { return; } } else if( ($attr -> getValue() == '') && ($attr -> isRequired()) ) { if ( $attr -> canBeGenerated()) { if ($attr -> generateValue()) { if (!$this -> validateAttrData($LSform, $attr)) { $GLOBALS['LSerror'] -> addErrorCode(48,$attr -> getLabel()); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(47,$attr -> getLabel()); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(46,$attr -> getLabel()); return; } } } } return true; } /** * Valide les données d'un attribut * * @param[in] $LSForm Formulaire d'origine * @param[in] &$attr Attribut à valider * * @author Benjamin Renard * * @retval boolean true si les données sont valides, false sinon */ function validateAttrData(&$LSform,&$attr) { $vconfig=$attr -> getValidateConfig(); $data=$attr -> getUpdateData(); if(!is_array($data)) { $data=array($data); } // Validation des valeurs de l'attribut if(is_array($vconfig)) { foreach($vconfig as $test) { // Définition du message d'erreur if (!empty($test['msg'])) { $msg_error=getFData($test['msg'],$this,'getValue'); } else { $msg_error=getFData(_("L'attribut %{attr} n'est pas valide."),$attr -> getLabel()); } foreach($data as $val) { // validation par check LDAP if((isset($test['filter'])||isset($test['basedn']))&&(isset($test['result']))) { $sparams=(isset($test['scope']))?array('scope' => $test['scope']):array(); $this -> other_values['val']=$val; $sfilter_user=(isset($test['basedn']))?getFData($test['filter'],$this,'getValue'):NULL; if(isset($test['object_type'])) { $test_obj = new $test['object_type']('auto'); $sfilter=$test_obj->getObjectFilter(); $sfilter='(&'.$sfilter; if($sfilter_user[0]=='(') { $sfilter=$sfilter.$sfilter_user.')'; } else { $sfilter=$sfilter.'('.$sfilter_user.'))'; } } else { $sfilter=$sfilter_user; } $sbasedn=(isset($test['basedn']))?getFData($test['basedn'],$this,'getValue'):NULL; $ret=$GLOBALS['LSldap'] -> getNumberResult ($sfilter,$sbasedn,$sparams); if($test['result']==0) { if($ret!=0) { $LSform -> setElementError($attr,$msg_error); return; } } else { if($ret<=0) { $LSform -> setElementError($attr,$msg_error); return; } } } // Validation par fonction externe else if(isset($test['function'])) { if (function_exists($test['function'])) { if(!$test['function']($this)) { $LSform -> setElementError($attr,$msg_error); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(24,array('attr' => $attr->name,'obj' => $this->type_name,'func' => $test['function'])); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(25,array('attr' => $attr->name,'obj' => $this->type_name)); return; } } } } // Génération des valeurs des attributs dépendants $dependsAttrs=$attr->getDependsAttrs(); if (!empty($dependsAttrs)) { foreach($dependsAttrs as $dependAttr) { if(!isset($this -> attrs[$dependAttr])){ $GLOBALS['LSerror'] -> addErrorCode(34,array('attr_depend' => $dependAttr, 'attr' => $attr -> getLabel())); continue; } if($this -> attrs[$dependAttr] -> canBeGenerated()) { if (!$this -> attrs[$dependAttr] -> generateValue()) { $GLOBALS['LSerror'] -> addErrorCode(47,$this -> attrs[$dependAttr] -> getLabel()); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(46,$this -> attrs[$dependAttr] -> getLabel()); return; } } } $attr -> validate(); unset($this -> other_values['val']); return true; } /** * Met à jour les données modifiés dans l'annuaire * * @param[in] $idForm Identifiant du formulaire d'origine * * @author Benjamin Renard * * @retval boolean true si la mise à jour a réussi, false sinon */ function submitChange($idForm) { $submitData=array(); foreach($this -> attrs as $attr) { if(($attr -> isUpdate())&&($attr -> isValidate())) { $submitData[$attr -> name] = $attr -> getUpdateData(); } } if(!empty($submitData)) { $dn=$this -> getDn(); if($dn) { return $GLOBALS['LSldap'] -> update($this -> type_name,$dn, $submitData); } else { $GLOBALS['LSerror'] -> addErrorCode(33); return; } } } /** * Retourne les informations issus d'un DN * * @param[in] $dn Un DN. * * @author Benjamin Renard * * @retval array Tableau : * - [0] : le premier paramètre * - [1] : les paramètres suivants */ function getDnInfos($dn) { $infos=ldap_explode_dn($dn,0); if(!$infos) return; $first=true; for($i=1;$i<$infos['count'];$i++) if($first) { $basedn.=$infos[$i]; $first=false; } else $basedn.=','.$infos[$i]; return array($infos[0],$basedn); } /** * Fait la somme de DN * * Retourne un DN qui correspond au point de séparation des DN si les DN * ne sont pas dans la meme dans la meme branche ou le dn le plus long sinon. * * @param[in] $dn Un premier DN. * @param[in] $dn Un deuxième DN. * * @author Benjamin Renard * * @retval string Un DN (ou false si les DN ne sont pas valide) */ function sumDn($dn1,$dn2) { $infos1=ldap_explode_dn($dn1,0); if(!$infos1) return; $infos2=ldap_explode_dn($dn2,0); if(!$infos2) return; if($infos2['count']>$infos1['count']) { $tmp=$infos1; $infos1=$infos2; $infos2=$tmp; } $infos1=array_reverse($infos1); $infos2=array_reverse($infos2); $first=true; $basedn=''; for($i=0;$i<$infos1['count'];$i++) { if(($infos1[$i]==$infos2[$i])||(!isset($infos2[$i]))) { if($first) { $basedn=$infos1[$i]; $first=false; } else $basedn=$infos1[$i].','.$basedn; } else { return $basedn; } } return $basedn; } /** * Vérifie la compatibilite des DN * * Vérifie que les DNs sont dans la même branche de l'annuaire. * * @param[in] $dn Un premier DN. * @param[in] $dn Un deuxième DN. * * @author Benjamin Renard * * @retval boolean true si les DN sont compatibles, false sinon. */ function isCompatibleDNs($dn1,$dn2) { $infos1=ldap_explode_dn($dn1,0); if(!$infos1) return; $infos2=ldap_explode_dn($dn2,0); if(!$infos2) return; if($infos2['count']>$infos1['count']) { $tmp=$infos1; $infos1=$infos2; $infos2=$tmp; } $infos1=array_reverse($infos1); $infos2=array_reverse($infos2); for($i=0;$i<$infos1['count'];$i++) { if(($infos1[$i]==$infos2[$i])||(!isset($infos2[$i]))) continue; else return false; } return true; } /** * Retourne le filtre correpondants aux objetcClass de l'objet * * @author Benjamin Renard * * @retval string le filtre ldap correspondant au type de l'objet */ function getObjectFilter() { if(!isset($this -> config['objectclass'])) return; foreach ($this -> config['objectclass'] as $class) $filter.='(objectClass='.$class.')'; return $filter; } /** * Retourne une liste d'objet du même type. * * Effectue une recherche en fonction des paramètres passé et retourne un * tableau d'objet correspond au resultat de la recherche. * * @author Benjamin Renard * * @param[in] $filter array (ou string) Filtre de recherche Ldap / Tableau de filtres de recherche * @param[in] $basedn string DN de base pour la recherche * @param[in] $params array Paramètres de recherche au format Net_LDAP::search() * * @retval array Tableau d'objet correspondant au resultat de la recherche */ function listObjects($filter='',$basedn=NULL,$params=array()) { $retInfos=array(); $attrs=false; $check_final_dn=false; if(!is_array($filter)) $filter=array(array('filter' => $filter)); $nbFilter=count($filter); for($i=0;$i<$nbFilter;$i++) { $new_attrs=array(); // Défintion des paramètres de base pour la recherche $sbasedn=$basedn; $sparams=$params; $ret=array(); if (isset($filter[$i]['scope'])) $sparams["scope"]=$filter[$i]['scope']; // Definition des critères de recherche correspondant au type d'objet à lister if(($nbFilter==1)||(!isset($filter[$i]['attr']))) { // Filtre sur l'objet souhaité $sfilter='(&'; $sfilter.=$this -> getObjectFilter(); $sfilter_end=')'; $check_final_dn=true; } // Initialisation des critères d'une recherche intermédiaire else { if(isset($filter[$i]['object_type'])) { $obj_tmp=new $filter[$i]['object_type'](); $obj_filter=$obj_tmp->getObjectFilter(); $sfilter='(&'.$obj_filter; $sfilter_end=')'; } else { $sfilter=''; $sfilter_end=''; } if(isset($filter[$i]['scope'])) { $sparams['scope']=$filter[$i]['scope']; } if(isset($filter[$i]['basedn'])) { $sbasedn=$filter[$i]['basedn']; } } // Dans le cas d'une recherche intermédiaire ou finale if($attrs!=false) { // Initialisation des variables $ret_gen=array(); $new_attrs=array(); // Pour tout les attributs retournés for($ii=0;$ii isCompatibleDNs($sbasedn,$basedn))&&($check_final_dn)) continue; } // Vérification de la compatibilité du basedn de la recherche et du basedn générale // Finalisation du filtre $sfilter_for.=$sfilter_end; // Execution de la recherche $ret=$GLOBALS['LSldap'] -> search ($sfilter_for,$sbasedn,$sparams); // Si il y un retour if(isset($ret[0])) { // si il ya une suite (recherche intermédiaire) if($filter[$i]['attr']){ for($iii=0;$iii isCompatibleDNs($ret[0]['dn'],$basedn)) continue; // ajout du DN au resultat finale $ret_gen[]=$ret[0]['dn']; } } } // cas du dernier filtre if(!empty($ret_gen)) { // on quitte la boucle des filtres de la conf $ret=$ret_gen; break; } // dans le cas d'une suite prévu mais d'un retour nul de la précédente recherche else if(empty($new_attrs)) { // retour vide et arrêt de la recherche $ret=array(); break; } else { $attrs=$new_attrs; } } // Dans le cas de la recherche initiale else { // Déclaration du filtre de recherche if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) { if($filter[$i]['filter'][0]=='(') { $sfilter.=$filter[$i]['filter']; } else { $sfilter.='('.$filter[$i]['filter'].')'; } } // fermeture du filtre $sfilter.=$sfilter_end; // Lancement de la recherche $ret=$GLOBALS['LSldap'] -> search ($sfilter,$sbasedn,$sparams); //Si filtre multiple => on recupère une liste d'attributs if(isset($filter[$i]['attr'])) { for($ii=0;$ii type_name($this -> config); $retInfos[$i] -> loadData($ret[$i]); } return $retInfos; } /** * Retourne une valeur de l'objet * * Retourne une valeur en fonction du paramètre. Si la valeur est inconnue, la valeur retourné est ' '. * tableau d'objet correspond au resultat de la recherche. * * Valeurs possibles : * - 'dn' ou '%{dn} : DN de l'objet * - [nom d'un attribut] : valeur de l'attribut * - [clef de $this -> other_values] : valeur de $this -> other_values * * @author Benjamin Renard * * @param[in] $val string Le nom de la valeur demandée * * @retval mixed la valeur demandé ou ' ' si celle-ci est inconnue. */ function getValue($val) { if(($val=='dn')||($val=='%{dn}')) { return $this -> dn; } else if(isset($this -> attrs[$val])){ if (method_exists($this -> attrs[$val],'getValue')) return $this -> attrs[$val] -> getValue(); else return ' '; } else if(isset($this -> other_values[$val])){ return $this -> other_values[$val]; } else { return ' '; } } /** * Retourne le DN de l'objet * * Cette methode retourne le DN de l'objet. Si celui-ci n'existe pas, il le construit à partir de la * configuration de l'objet et la valeur de son attribut rdn. * * @author Benjamin Renard * * @retval string Le DN de l'objet */ function getDn() { if($this -> dn) { return $this -> dn; } else { $rdn_attr=$this -> config['rdn']; if( (isset($this -> config['rdn'])) && (isset($this -> attrs[$rdn_attr])) && (isset($this -> config['container_dn'])) && (isset($GLOBALS['LSsession']['topDn'])) ) { debug('RDN : '.$rdn_attr); $rdn_val=$this -> attrs[$rdn_attr] -> getUpdateData(); if (!empty($rdn_val)) { return $rdn_attr.'='.$rdn_val[0].','.$this -> config['container_dn'].','.$GLOBALS['LSsession']['topDn']; } else { $GLOBALS['LSerror'] -> addErrorCode(32,$this -> config['rdn']); return; } } else { $GLOBALS['LSerror'] -> addErrorCode(31,$this -> type_name); return; } } } } ?>