5a96ff15a3da4a5ebf552dea3ca31fa525273f7f
[ldapsaisie.git] / trunk / includes / class / class.LSldap.php
1 <?php
2 /*******************************************************************************
3  * Copyright (C) 2007 Easter-eggs
4  * http://ldapsaisie.labs.libre-entreprise.org
5  *
6  * Author: See AUTHORS file in top-level directory.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 ******************************************************************************/
22
23 /**
24  * Gestion de l'accès à l'annaire Ldap
25  *
26  * Cette classe gère l'accès à l'annuaire ldap en s'appuyant sur PEAR :: Net_LDAP2
27  *
28  * @author Benjamin Renard <brenard@easter-eggs.com>
29  */
30 class LSldap {
31
32   var $config;
33   var $cnx = NULL;
34
35   /**
36    * Constructeur
37    *
38    * Cette methode définis la configuration de l'accès à l'annuaire
39    * et établie la connexion.
40    *
41    * @author Benjamin Renard <brenard@easter-eggs.com>
42    *
43    * @param[in] $config array Tableau de configuration au formar Net_LDAP2
44    *
45    * @retval void
46    *
47    * @see Net_LDAP2::connect()
48    */
49   function LSldap ($config) {
50     $this -> config = $config;
51     $this -> connect();
52   }
53   
54   /**
55    * Connection
56    *
57    * Cette methode établie la connexion à l'annuaire Ldap
58    *
59    * @author Benjamin Renard <brenard@easter-eggs.com>
60    *
61    * @retval boolean true si la connection est établie, false sinon
62    */
63   function connect() {
64     $this -> cnx = Net_LDAP2::connect($this -> config);
65     if (Net_LDAP2::isError($this -> cnx)) {
66       $GLOBALS['LSerror'] -> addErrorCode(1,$this -> cnx -> getMessage());
67       $this -> cnx = NULL;
68       return;
69     }
70     return true;
71   }
72   
73   /**
74    * Déconnection
75    *
76    * Cette methode clos la connexion à l'annuaire Ldap
77    *
78    * @author Benjamin Renard <brenard@easter-eggs.com>
79    *
80    * @retval void
81    */
82   function close() {
83     $this -> cnx -> done();
84   }
85   
86   /**
87    * Recherche dans l'annuaire
88    *
89    * Cette methode effectue une recherche dans l'annuaire et retourne le resultat
90    * de celle-ci sous la forme d'un tableau.
91    *
92    * @author Benjamin Renard <brenard@easter-eggs.com>
93    *
94    * @param[in] $filter [<b>required</b>] string Filtre de recherche Ldap
95    * @param[in] $basedn string DN de base pour la recherche
96    * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search()
97    *
98    * @see Net_LDAP2::search()
99    *
100    * @retval array Retourne un tableau associatif contenant :
101    *               - ['dn'] : le DN de l'entré
102    *               - ['attrs'] : tableau associatif contenant les attributs (clé)
103    *                             et leur valeur (valeur).
104    */
105   function search ($filter,$basedn=NULL,$params = array()) {
106     $ret = $this -> cnx -> search($basedn,$filter,$params);
107     if (Net_LDAP2::isError($ret)) {
108       $GLOBALS['LSerror'] -> addErrorCode(2,$ret -> getMessage());
109       return;
110     }
111     $retInfos=array();
112     foreach($ret -> entries() as $entry) {
113       $retInfos[]=array('dn' => $entry -> dn(), 'attrs' => $entry -> getValues());
114     }
115     return $retInfos;
116   }
117   
118   /**
119    * Compte le nombre de retour d'une recherche dans l'annuaire
120    *
121    * Cette methode effectue une recherche dans l'annuaire et retourne le nombre
122    * d'entrés trouvées.
123    *
124    * @author Benjamin Renard <brenard@easter-eggs.com>
125    *
126    * @param[in] $filter [<b>required</b>] string Filtre de recherche Ldap
127    * @param[in] $basedn string DN de base pour la recherche
128    * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search()
129    *
130    * @see Net_LDAP2::search()
131    *
132    * @retval numeric Le nombre d'entré trouvées
133    */
134   function getNumberResult ($filter,$basedn=NULL,$params = array() ) {
135     if (empty($filter))
136       $filter=NULL;
137     $ret = $this -> cnx -> search($basedn,$filter,$params);
138     if (Net_LDAP2::isError($ret)) {
139       $GLOBALS['LSerror'] -> addErrorCode(2,$ret -> getMessage());
140       return;
141     }
142     return $ret -> count();
143   }
144   
145   /**
146    * Charge les valeurs des attributs d'une entré de l'annuaire
147    *
148    * Cette methode recupère les valeurs des attributs d'une entrée de l'annaire
149    * et les retournes sous la forme d'un tableau.
150    *
151    * @author Benjamin Renard <brenard@easter-eggs.com>
152    *
153    * @param[in] $dn string DN de l'entré Ldap
154    *
155    * @retval array Tableau associatif des valeurs des attributs avec en clef, le nom de l'attribut.
156    */
157   function getAttrs($dn) {
158     $infos = ldap_explode_dn($dn,0);
159     if((!$infos)||($infos['count']==0))
160       return;
161     $basedn='';
162     for ($i=1;$i<$infos['count'];$i++) {
163       $sep=($basedn=='')?'':',';
164       $basedn.=$sep.$infos[$i];
165     }
166     $return=$this -> search($infos[0],$basedn);
167     return $return[0]['attrs'];
168   }
169   
170   /**
171    * Retourne une entrée existante ou nouvelle
172    *
173    * @author Benjamin Renard <brenard@easter-eggs.com>
174    *
175    * @param[in] $object_type string Type de l'objet Ldap
176    * @param[in] $dn string DN de l'entré Ldap
177    *
178    * @retval ldapentry|array Un objet ldapentry (PEAR::Net_LDAP2)
179    *                         ou un tableau (si c'est une nouvelle entrée):
180    *                          Array (
181    *                            'entry' => ldapentry,
182    *                            'new' => true
183    *                          )
184    */
185   function getEntry($object_type,$dn) {
186     if(isset($GLOBALS['LSobjects'][$object_type])){
187       $obj_conf=$GLOBALS['LSobjects'][$object_type];
188       $entry = $this -> cnx -> getEntry($dn);
189       if (Net_LDAP2::isError($entry)) {
190         //$newentry = new Net_LDAP2_Entry(&$this -> cnx);
191         //$newentry -> dn($dn);
192         //$newentry -> add(array('objectclass' => $obj_conf['objectclass']));
193         //foreach($obj_conf['attrs'] as $attr_name => $attr_conf) {
194         //  $newentry->add(array($attr_name => $attr_conf['default_value']));
195         //}
196         $attributes = array();
197         foreach($obj_conf['attrs'] as $attr_name => $attr_conf) {
198           if( isset($attr_conf['default_value']) ) {
199             $attributes[$attr_name]=$attr_conf['default_value'];
200           }
201         }
202         
203         $newentry = $this -> getNewEntry($dn,$obj_conf['objectclass'],$attributes);
204         
205         if (!$newentry) {
206           return;
207         }
208         return array('entry' => $newentry,'new' => true);
209       }
210       else {
211         return $entry;
212       }
213     }
214     else {
215       $GLOBALS['LSerror'] -> addErrorCode(3);
216       return;
217     }
218   }
219   
220  /**
221   * Retourne une nouvelle entrée
222   * 
223   * @param[in] $dn string Le DN de l'objet
224   * @param[in] $objectClass array Un tableau contenant les objectClass de l'objet
225   * @param[in] $attrs array Un tabeau du type array('attr_name' => attr_value, ...)
226   * 
227   * @retval mixed Le nouvelle objet en cas de succès, false sinon
228   */
229   function getNewEntry($dn,$objectClass,$attrs,$add=false) {
230     $newentry = Net_LDAP2_Entry::createFresh($dn,array_merge(array('objectclass' =>$objectClass),(array)$attrs));
231     if(Net_LDAP2::isError($newentry)) {
232       return false;
233     }
234     if($add) {
235       if(!$this -> cnx -> add($newentry)) {
236         return;
237       }
238     }
239     return $newentry;
240   }
241   
242   /**
243    * Met à jour une entrée dans l'annuaire
244    * 
245    * Remarque : Supprime les valeurs vides de attributs et les attributs sans valeur.
246    *
247    * @author Benjamin Renard <brenard@easter-eggs.com>
248    *
249    * @param[in] $object_type string Type de l'objet Ldap
250    * @param[in] $dn string DN de l'entré Ldap
251    * @param[in] $change array Tableau des modifications à apporter
252    *
253    * @retval boolean true si l'objet a bien été mis à jour, false sinon
254    */
255   function update($object_type,$dn,$change) {
256     LSdebug($change);
257     $dropAttr=array();
258     $entry=$this -> getEntry($object_type,$dn);
259     if (is_array($entry)) {
260       $new = $entry['new'];
261       $entry = $entry['entry'];
262     }
263     else {
264       $new = false;
265     }
266
267     if($entry) {
268       foreach($change as $attrName => $attrVal) {
269         $drop = true;
270         if (is_array($attrVal)) {
271           foreach($attrVal as $val) {
272             if (!empty($val)) {
273               $drop = false;
274               $changeData[$attrName][]=$val;
275             }
276           }
277         }
278         else {
279           if (!empty($attrVal)) {
280             $drop = false;
281             $changeData[$attrName][]=$attrVal;
282           }
283         }
284         if($drop) {
285           $dropAttr[] = $attrName;
286         }
287       }
288       $entry -> replace($changeData);
289       LSdebug('change : <pre>'.print_r($changeData,true).'</pre>');
290       LSdebug('drop : <pre>'.print_r($dropAttr,true).'</pre>');
291
292       if ($new) {
293         $ret = $this -> cnx -> add($entry);
294       }
295       else {
296         $ret = $entry -> update();
297       }
298       
299       if (Net_LDAP2::isError($ret)) {
300         $GLOBALS['LSerror'] -> addErrorCode(5,$dn);
301         $GLOBALS['LSerror'] -> addErrorCode(0,'NetLdap-Error : '.$ret->getMessage());
302       }
303       else {
304         if (!empty($dropAttr)) {
305           foreach($dropAttr as $attr) {
306             // Méthode buggé : suppression impossible de certain attribut
307             // exemple : jpegPhoto
308             // $entry -> delete($attr);
309             $entry -> replace(array($attr =>array()));
310           }
311           $ret = $entry -> update();
312           if (Net_LDAP2::isError($ret)) {
313             $GLOBALS['LSerror'] -> addErrorCode(6);
314             $GLOBALS['LSerror'] -> addErrorCode(0,'NetLdap-Error : '.$ret->getMessage());
315           }
316         }
317         return true;
318       }
319     }
320     else {
321       $GLOBALS['LSerror'] -> addErrorCode(4);
322       return;
323     }
324   }
325
326   /**
327    * Test de bind
328    *
329    * Cette methode établie une connexion à l'annuaire Ldap et test un bind
330    * avec un login et un mot de passe passé en paramètre
331    *
332    * @author Benjamin Renard <brenard@easter-eggs.com>
333    *
334    * @retval boolean true si la connection à réussi, false sinon
335    */
336   function checkBind($dn,$pwd) {
337     $config = $this -> config;
338     $config['binddn'] = $dn;
339     $config['bindpw'] = $pwd;
340     $cnx = Net_LDAP2::connect($config);
341     if (Net_LDAP2::isError($cnx)) {
342       return;
343     }
344     return true;
345   }
346
347   /**
348    * Retourne l'état de la connexion Ldap
349    *
350    * @retval boolean True si le serveur est connecté, false sinon.
351    */
352   function isConnected() {
353     return ($this -> cnx == NULL)?false:true;
354   }
355   
356   /**
357    * Supprime un objet de l'annuaire
358    *
359    * @param[in] string DN de l'objet à supprimer
360    * 
361    * @retval boolean True si l'objet à été supprimé, false sinon
362    */
363   function remove($dn) {
364     $ret = $this -> cnx -> delete($dn,array('recursive' => true));
365     if (Net_LDAP2::isError($ret)) {
366       $GLOBALS['LSerror'] -> addErrorCode(0,'NetLdap-Error : '.$ret->getMessage());
367       return;
368     }
369     return true;
370   }
371
372   /**
373    * Déplace un objet LDAP dans l'annuaire
374    * 
375    * @param[in] $old string Le DN actuel
376    * @param[in] $new string Le futur DN
377    * 
378    * @retval boolean True si l'objet a été déplacé, false sinon
379    */
380   function move($old,$new) {
381     $ret = $this -> cnx -> move($old,$new);
382     if (Net_LDAP2::isError($ret)) {
383       $GLOBALS['LSerror'] -> addErrorCode(7);
384       $GLOBALS['LSerror'] -> addErrorCode(0,'NetLdap-Error : '.$ret->getMessage());
385       return;
386     }
387     return true;
388   }
389 }
390
391 ?>