Code

Added additional information to the extended error message
[gosa.git] / include / class_ldap.inc
1 <?php
2 /*****************************************************************************
3   newldap.inc - version 1.0
4   Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
5   Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
7   Based in code of ldap.inc of
8   Copyright (C) 1998  Eric Kilfoil <eric@ipass.net>
9  *****************************************************************************/
11 define("ALREADY_EXISTING_ENTRY",-10001);
12 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
13 define("NO_FILE_UPLOADED",10003);
14 define("INSERT_OK",10000);
15 define("SPECIALS_OVERRIDE", TRUE);
17 class LDAP{
19   var $hascon   =false;
20   var $hasres   =false;
21   var $reconnect=false;
22   var $tls      = false;
23   var $basedn   ="";
24   var $cid;
25   var $error    = ""; // Any error messages to be returned can be put here
26   var $start    = 0; // 0 if we are fetching the first entry, otherwise 1
27   var $objectClasses = array(); // Information read from slapd.oc.conf
28   var $binddn   = "";
29   var $bindpw   = "";
30   var $hostname = "";
31   var $follow_referral = FALSE;
32   var $referrals= array();
33   var $max_ldap_query_time = 0;   // 0, empty or negative values will disable this check 
35   function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
36   {
37     global $config;
38     $this->follow_referral= $follow_referral;
39     $this->tls=$tls;
40     $this->binddn=$this->convert($binddn);
42     $this->bindpw=$bindpw;
43     $this->hostname=$hostname;
45     /* Check if MAX_LDAP_QUERY_TIME is defined */ 
46     if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){
47       $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME'];
48       $this->max_ldap_query_time = (float)($str);
49     }
51     $this->connect();
52   }
55   /* Function to replace all problematic characters inside a DN by \001XX, where
56      \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely
57      that this character is inside a DN.
58      
59      Currently used codes:
60       ,   => CO
61       \2C => CO
62       (   => OB
63       )   => CB
64       /   => SL                                                                  */
65   function convert($dn)
66   {
67     if (SPECIALS_OVERRIDE == TRUE){
68       return (preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
69                            array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
70                            $dn));
71     } else {
72       return ($dn);
73     }
74   }
77   /* Function to fix all problematic characters inside a DN by replacing \001XX
78      codes to their original values. See "convert" for mor information. 
79      ',' characters are always expanded to \, (not \2C), since all tested LDAP
80      servers seem to take it the correct way.                                  */
81   function fix($dn)
82   {
83     if (SPECIALS_OVERRIDE == TRUE){
84       return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
85                            array("\,", "(", ")", "/"),
86                            $dn));
87     } else {
88       return ($dn);
89     }
90   }
93   function connect()
94   {
95     $this->hascon=false;
96     $this->reconnect=false;
97     if ($this->cid= @ldap_connect($this->hostname)) {
98       @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
99       if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
100         @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
101         @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
102       }
103       if (function_exists("ldap_start_tls") && $this->tls){
104         @ldap_start_tls($this->cid);
105       }
107       $this->error = "No Error";
108       if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
109         $this->error = "Success";
110         $this->hascon=true;
111       } else {
112         if ($this->reconnect){
113           if ($this->error != "Success"){
114             $this->error = "Could not rebind to " . $this->binddn;
115           }
116         } else {
117           $this->error = "Could not bind to " . $this->binddn;
118         }
119       }
120     } else {
121       $this->error = "Could not connect to LDAP server";
122     }
123   }
125   function rebind($ldap, $referral)
126   {
127     $credentials= $this->get_credentials($referral);
128     if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
129       $this->error = "Success";
130       $this->hascon=true;
131       $this->reconnect= true;
132       return (0);
133     } else {
134       $this->error = "Could not bind to " . $credentials['ADMIN'];
135       return NULL;
136     }
137   }
139   function reconnect()
140   {
141     if ($this->reconnect){
142       @ldap_unbind($this->cid);
143       $this->cid = NULL;
144     }
145   }
147   function unbind()
148   {
149     @ldap_unbind($this->cid);
150     $this->cid = NULL;
151   }
153   function disconnect()
154   {
155     if($this->hascon){
156       @ldap_close($this->cid);
157       $this->hascon=false;
158     }
159   }
161   function cd($dir)
162   {
163     if ($dir == "..")
164       $this->basedn = $this->getParentDir();
165     else
166       $this->basedn = $this->convert($dir);
167   }
169   function getParentDir($basedn = "")
170   {
171     if ($basedn=="")
172       $basedn = $this->basedn;
173     else
174       $basedn = $this->convert($this->basedn);
175     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
176   }
178   function search($filter, $attrs= array())
179   {
180     if($this->hascon){
181       if ($this->reconnect) $this->connect();
183       $start = microtime();
184    
185       $this->clearResult();
186       $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
187       $this->error = @ldap_error($this->cid);
188       $this->resetResult();
189       $this->hasres=true;
190    
191       /* Check if query took longer as specified in max_ldap_query_time */
192       if($this->max_ldap_query_time){
193         $diff = get_MicroTimeDiff($start,microtime());
194         if($diff > $this->max_ldap_query_time){
195           print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
196         }
197       }
199       return($this->sr);
200     }else{
201       $this->error = "Could not connect to LDAP server";
202       return("");
203     }
204   }
206   function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
207   {
208     if($this->hascon){
209       if ($this->reconnect) $this->connect();
210       $this->clearResult();
211       if ($basedn == "")
212         $basedn = $this->basedn;
213       else
214         $basedn= $this->convert($basedn);
215   
216       $start = microtime();
218       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
219       $this->error = @ldap_error($this->cid);
220       $this->resetResult();
221       $this->hasres=true;
223        /* Check if query took longer as specified in max_ldap_query_time */
224       if($this->max_ldap_query_time){
225         $diff = get_MicroTimeDiff($start,microtime());
226         if($diff > $this->max_ldap_query_time){
227           print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
228         }
229       }
231       return($this->sr);
232     }else{
233       $this->error = "Could not connect to LDAP server";
234       return("");
235     }
236   }
238   function cat($dn,$attrs= array("*"))
239   {
240     if($this->hascon){
241       if ($this->reconnect) $this->connect();
242       $this->clearResult();
243       $filter = "(objectclass=*)";
244       $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
245       $this->error = @ldap_error($this->cid);
246       $this->resetResult();
247       $this->hasres=true;
248       return($this->sr);
249     }else{
250       $this->error = "Could not connect to LDAP server";
251       return("");
252     }
253   }
255   function set_size_limit($size)
256   {
257     /* Ignore zero settings */
258     if ($size == 0){
259       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
260     }
261     if($this->hascon){
262       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
263     } else {
264       $this->error = "Could not connect to LDAP server";
265     }
266   }
268   function fetch()
269   {
270     $att= array();
271     if($this->hascon){
272       if($this->hasres){
273         if ($this->start == 0)
274         {
275           $this->start = 1;
276           $this->re= @ldap_first_entry($this->cid, $this->sr);
277         } else {
278           $this->re= @ldap_next_entry($this->cid, $this->re);
279         }
280         if ($this->re)
281         {
282           $att= @ldap_get_attributes($this->cid, $this->re);
283           $att['dn']= $this->convert(@ldap_get_dn($this->cid, $this->re));
284         }
285         $this->error = @ldap_error($this->cid);
286         if (!isset($att)){
287           $att= array();
288         }
289         return($att);
290       }else{
291         $this->error = "Perform a Fetch with no Search";
292         return("");
293       }
294     }else{
295       $this->error = "Could not connect to LDAP server";
296       return("");
297     }
298   }
300   function resetResult()
301   {
302     $this->start = 0;
303   }
305   function clearResult()
306   {
307     if($this->hasres){
308       $this->hasres = false;
309       @ldap_free_result($this->sr);
310     }
311   }
313   function getDN()
314   {
315     if($this->hascon){
316       if($this->hasres){
318         if(!$this->re)
319           {
320           $this->error = "Perform a Fetch with no valid Result";
321           }
322           else
323           {
324           $rv = @ldap_get_dn($this->cid, $this->re);
325         
326           $this->error = @ldap_error($this->cid);
327           return($this->convert($rv));
328            }
329       }else{
330         $this->error = "Perform a Fetch with no Search";
331         return("");
332       }
333     }else{
334       $this->error = "Could not connect to LDAP server";
335       return("");
336     }
337   }
339   function count()
340   {
341     if($this->hascon){
342       if($this->hasres){
343         $rv = @ldap_count_entries($this->cid, $this->sr);
344         $this->error = @ldap_error($this->cid);
345         return($rv);
346       }else{
347         $this->error = "Perform a Fetch with no Search";
348         return("");
349       }
350     }else{
351       $this->error = "Could not connect to LDAP server";
352       return("");
353     }
354   }
356   function rm($attrs = "", $dn = "")
357   {
358     if($this->hascon){
359       if ($this->reconnect) $this->connect();
360       if ($dn == "")
361         $dn = $this->basedn;
363       $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
364       $this->error = @ldap_error($this->cid);
365       return($r);
366     }else{
367       $this->error = "Could not connect to LDAP server";
368       return("");
369     }
370   }
372   function rename($attrs, $dn = "")
373   {
374     if($this->hascon){
375       if ($this->reconnect) $this->connect();
376       if ($dn == "")
377         $dn = $this->basedn;
379       $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
380       $this->error = @ldap_error($this->cid);
381       return($r);
382     }else{
383       $this->error = "Could not connect to LDAP server";
384       return("");
385     }
386   }
388   function rmdir($deletedn)
389   {
390     if($this->hascon){
391       if ($this->reconnect) $this->connect();
392       $r = @ldap_delete($this->cid, $this->fix($deletedn));
393       $this->error = @ldap_error($this->cid);
394       return($r ? $r : 0);
395     }else{
396       $this->error = "Could not connect to LDAP server";
397       return("");
398     }
399   }
401   /**
402   *  Function rmdir_recursive
403   *
404   *  Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
405   *  Parameters:  The dn to delete
406   *  GiveBack:    True on sucessfull , 0 in error, and "" when we don't get a ldap conection
407   *
408   */
410   function rmdir_recursive($deletedn)
411   {
412     if($this->hascon){
413       if ($this->reconnect) $this->connect();
414       $delarray= array();
415         
416       /* Get sorted list of dn's to delete */
417       $this->ls ("(objectClass=*)",$deletedn);
418       while ($this->fetch()){
419         $deldn= $this->getDN();
420         $delarray[$deldn]= strlen($deldn);
421       }
422       arsort ($delarray);
423       reset ($delarray);
425       /* Really Delete ALL dn's in subtree */
426       foreach ($delarray as $key => $value){
427         $this->rmdir_recursive($key);
428       }
429       
430       /* Finally Delete own Node */
431       $r = @ldap_delete($this->cid, $this->fix($deletedn));
432       $this->error = @ldap_error($this->cid);
433       return($r ? $r : 0);
434     }else{
435       $this->error = "Could not connect to LDAP server";
436       return("");
437     }
438   }
440   /* Copy given attributes and sub-dns with attributes to destination dn 
441   */
442   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = true,$depth=0)
443   {
444     error_reporting(E_ALL);
445     
446     if($is_first){
447       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".$sourcedn."</i>")."</h2>";
448     }else{
449       if(preg_match("/^ou=/",$sourcedn)){
450         echo "<h3>"._("Processing")." <i>$destinationdn</i></h3>";
451       }else{
452         $tmp = split(",",$sourcedn);
453         
454         echo "&nbsp;<b>"._("Object").":</b> ";
456         $deststr = $destinationdn;
457         if(strlen($deststr) > 96){
458           $deststr = substr($deststr,0,96)."...";
459         }
461         echo $deststr."<br>";
462       }
463     }
465     flush();
466     
467     if($this->hascon){
468       if ($this->reconnect) $this->connect();
470       /* Save base dn */
471       $basedn= $this->basedn;
472       $delarray= array();
473      
474       /* Check if destination entry already exists */
475       $this->cat($destinationdn);
477       if($this->count()){
478         return;
479       }else{
480         
481         $this->clearResult();
483         /* Get source entry */
484         $this->cd($basedn);
485         $this->cat($sourcedn);
486         $attr = $this->fetch();
488         /* Error while fetching object / attribute abort*/
489         if((!$attr) || (count($attr)) ==0) {
490           echo _("Error while fetching source dn - aborted!");
491           return;
492         }
493   
494         /* check if this is a department */
495         if(in_array("organizationalUnit",$attr['objectClass'])){
496           $attr['dn'] = $this->convert($destinationdn);
497           $this->cd($basedn);
498           $this->create_missing_trees($destinationdn);
499           $this->cd($destinationdn);
501           /* If is first entry, append FAIbranch to department entry */
502           if($is_first){
503             $this->cat($destinationdn);
504             $attr= $this->fetch();
506             /* Filter unneeded informations */
507             foreach($attr as $key => $value){
508               if(is_numeric($key)) unset($attr[$key]);
509               if(isset($attr[$key]['count'])){
510                 if(is_array($attr[$key])){
511                   unset($attr[$key]['count']);
512                 }
513               }
514             }
515             
516             unset($attr['count']);
517             unset($attr['dn']);
519             /* Add marking attribute */
520             $attr['objectClass'][] = "FAIbranch";
521             
522             /* Add this entry */
523             $this->modify($attr);
524           }
525         }else{
527           /* If this is no department */
528           foreach($attr as $key => $value){
529             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
530               $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
531               $ei= ldap_first_entry($this->cid, $sr);
532               if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
533                 $attr[$key] = $tmp;
534               }
535             }
537             if(is_numeric($key)) unset($attr[$key]);
538             if(isset($attr[$key]['count'])){
539               if(is_array($attr[$key])){
540                 unset($attr[$key]['count']);
541               }
542             }
543           }
544           unset($attr['count']);
545           unset($attr['dn']);
547           if(!in_array("gosaApplication" , $attr['objectClass'])){
548             if($type=="branch"){
549               $attr['FAIstate'] ="branch";
550             }elseif($type=="freeze"){
551               $attr['FAIstate'] ="freeze";
552             }else{
553               print_red(_("Unknown FAIstate %s"),$type);
554             }
555           }
557           /* Add entry */
558           $this->cd($destinationdn);
559           $this->cat($destinationdn);
560           $a = $this->fetch();
561           if(!count($a)){
562             $this->add($attr);
563           }
565           if($this->error != "Success"){
566             /* Some error occured */
567             print "---------------------------------------------";
568             print $this->get_error()."<br>";
569             print $sourcedn."<br>";
570             print $destinationdn."<br>";
571             print_a( $attr);
572             exit();
573           }          
574         }
575       }
577       $this->ls ("(objectClass=*)",$sourcedn);
578       while ($this->fetch()){
579         $deldn= $this->getDN();
580         $delarray[$deldn]= strlen($deldn);
581       }
582       asort ($delarray);
583       reset ($delarray);
585        $depth ++;
586       foreach($delarray as $dn => $bla){
587         if($dn != $destinationdn){
588           $this->cd($basedn);
589           $item = $this->fetch($this->cat($dn));
590           if(!in_array("FAIbranch",$item['objectClass'])){
591             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$type,false,$depth);
592           } 
593         }
594       }
595     }
596     if($is_first){
597       echo "<p class='seperator'>&nbsp;</p>";
598     }
600   }
602   function modify($attrs)
603   {
604     if(count($attrs) == 0){
605       return (0);
606     }
607     if($this->hascon){
608       if ($this->reconnect) $this->connect();
609       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
610       $this->error = @ldap_error($this->cid);
611       return($r ? $r : 0);
612     }else{
613       $this->error = "Could not connect to LDAP server";
614       return("");
615     }
616   }
618   function add($attrs)
619   {
620     if($this->hascon){
621       if ($this->reconnect) $this->connect();
622       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
623       $this->error = @ldap_error($this->cid);
624       return($r ? $r : 0);
625     }else{
626       $this->error = "Could not connect to LDAP server";
627       return("");
628     }
629   }
631   function create_missing_trees($target)
632   {
633     /* Ignore create_missing trees if the base equals target */
634     if ($target == $this->basedn){
635      return;
636     }
638     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
639     $l= array_reverse(ldap_explode_dn($real_path,0));
640     unset($l['count']);
641     $cdn= $this->basedn;
642     $tag= "";
644     foreach ($l as $part){
645       $cdn= "$part,$cdn";
647       /* Ignore referrals */
648       $found= false;
649       foreach($this->referrals as $ref){
650         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
651         if ($base == $cdn){
652           $found= true;
653           break;
654         }
655       }
656       if ($found){
657         continue;
658       }
660       $this->cat ($cdn);
661       $attrs= $this->fetch();
663       /* Create missing entry? */
664       if (count ($attrs)){
665       
666         /* Catch the tag - if present */
667         if (isset($attrs['gosaUnitTag'][0])){
668           $tag= $attrs['gosaUnitTag'][0];
669         }
671       } else {
672         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
673         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
675         $na= array();
676         switch ($type){
677           case 'ou':
678             if ($tag != ""){
679               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
680               $na["gosaUnitTag"]= $tag;
681             } else {
682               $na["objectClass"]= "organizationalUnit";
683             }
684             $na["ou"]= $param;
685             break;
686           case 'dc':
687             if ($tag != ""){
688               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
689               $na["gosaUnitTag"]= $tag;
690             } else {
691               $na["objectClass"]= array("dcObject", "top", "locality");
692             }
693             $na["dc"]= $param;
694             break;
695           default:
696             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
697             echo $_SESSION['errors'];
698             exit;
699         }
700         $this->cd($cdn);
701         $this->add($na);
702       }
703     }
704   }
706   function recursive_remove()
707   {
708     $delarray= array();
710     /* Get sorted list of dn's to delete */
711     $this->search ("(objectClass=*)");
712     while ($this->fetch()){
713       $deldn= $this->getDN();
714       $delarray[$deldn]= strlen($deldn);
715     }
716     arsort ($delarray);
717     reset ($delarray);
719     /* Delete all dn's in subtree */
720     foreach ($delarray as $key => $value){
721       $this->rmdir($key);
722     }
723   }
725   function get_attribute($dn, $name,$r_array=0)
726   {
727     $data= "";
728     if ($this->reconnect) $this->connect();
729     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
731     /* fill data from LDAP */
732     if ($sr) {
733       $ei= @ldap_first_entry($this->cid, $sr);
734       if ($ei) {
735         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
736           $data= $info[0];
737         }
739       }
740     }
741     if($r_array==0)
742     return ($data);
743     else
744     return ($info);
745   
746   
747   }
748  
751   function get_additional_error()
752   {
753     $error= "";
754     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
755     return ($error);
756   }
758   function get_error()
759   {
760     if ($this->error == 'Success'){
761       return $this->error;
762     } else {
763       $adderror= $this->get_additional_error();
764       if ($adderror != ""){
765         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->base, $this->hostname).")";
766       } else {
767         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
768       }
769       return $error;
770     }
771   }
773   function get_credentials($url, $referrals= NULL)
774   {
775     $ret= array();
776     $url= preg_replace('!\?\?.*$!', '', $url);
777     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
779     if ($referrals == NULL){
780       $referrals= $this->referrals;
781     }
783     if (isset($referrals[$server])){
784       return ($referrals[$server]);
785     } else {
786       $ret['ADMIN']= $this->fix($this->binddn);
787       $ret['PASSWORD']= $this->bindpw;
788     }
790     return ($ret);
791   }
794   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
795   {
796     $display= "";
798     if ($recursive){
799       $this->cd($dn);
800       $this->search("$filter", array('dn'));
801       while ($attrs= $this->fetch()){
802         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
803         $display.= "\n";
804       }
805     } else {
806       $display.= $this->gen_one_entry($dn);
807     }
809     return ($display);
810   }
812 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
813   {
814     $display= "";
816       $this->cd($dn);
817       $this->search("$filter");
819       $i=0;
820       while ($attrs= $this->fetch()){
821         $j=0;
823         foreach ($attributes as $at){
824           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
825           $j++;
826         }
828         $i++;
829       }
831     return ($display);
832   }
835   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
836   {
837     $ret = "";
838     $data = "";
839     if($this->reconnect){
840       $this->connect();
841     }
843     /* Searching Ldap Tree */
844     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
846     /* Get the first entry */   
847     $entry= @ldap_first_entry($this->cid, $sr);
849     /* Get all attributes related to that Objekt */
850     $atts = array();
851     
852     /* Assemble dn */
853     $atts[0]['name']  = "dn";
854     $atts[0]['value'] = array('count' => 1, 0 => $dn);
856     /* Reset index */
857     $i = 1 ; 
858   $identifier = array();
859     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
860     while ($attribute) {
861       $i++;
862       $atts[$i]['name']  = $attribute;
863       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
865       /* Next one */
866       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
867     }
869     foreach($atts as $at)
870     {
871       for ($i= 0; $i<$at['value']['count']; $i++){
873         /* Check if we must encode the data */
874         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
875           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
876         } else {
877           $ret .= $at['name'].": ".$at['value'][$i]."\n";
878         }
879       }
880     }
882     return($ret);
883   }
886   function dn_exists($dn)
887   {
888     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
889   }
890   
893   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
894   {
895     if($this->reconnect) $this->connect();
897     /* First we have to splitt the string ito detect empty lines
898        An empty line indicates an new Entry */
899     $entries = split("\n",$str_attr);
901     $data = "";
902     $cnt = 0; 
903     $current_line = 0;
905     /* Every single line ... */
906     foreach($entries as $entry) {
907       $current_line ++;
909       /* Removing Spaces to .. 
910          .. test if a new entry begins */
911       $tmp  = str_replace(" ","",$data );
913       /* .. prevent empty lines in an entry */
914       $tmp2 = str_replace(" ","",$entry);
916       /* If the Block ends (Empty Line) */
917       if((empty($entry))&&(!empty($tmp))) {
918         /* Add collected lines as a complete block */
919         $all[$cnt] = $data;
920         $cnt ++;
921         $data ="";
922       } else {
924         /* Append lines ... */
925         if(!empty($tmp2)) {
926           /* check if we need base64_decode for this line */
927           if(ereg("::",$tmp2))
928           {
929             $encoded = split("::",$entry);
930             $attr  = $encoded[0];
931             $value = base64_decode($encoded[1]);
932             /* Add linenumber */
933             $data .= $current_line."#".$attr.":".$value."\n";
934           }
935           else
936           {
937             /* Add Linenumber */ 
938             $data .= $current_line."#".$entry."\n";
939           }
940         }
941       }
942     }
944     /* The Data we collected is not in the array all[];
945        For example the Data is stored like this..
947        all[0] = "1#dn : .... \n 
948        2#ObjectType: person \n ...."
949        
950        Now we check every insertblock and try to insert */
951     foreach ( $all as $single) {
952       $lineone = split("\n",$single);  
953       $ndn = split("#", $lineone[0]);
954       $line = $ndn[1];
956       $dnn = split (":",$line);
957       $current_line = $ndn[0];
958       $dn    = $dnn[0];
959       $value = $dnn[1];
961       /* Every block must begin with a dn */
962       if($dn != "dn") {
963         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
964         return -2;  
965       }
967       /* Should we use Modify instead of Add */
968       $usemodify= false;
970       /* Delete before insert */
971       $usermdir= false;
972     
973       /* The dn address already exists! */
974       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
976         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
977         return ALREADY_EXISTING_ENTRY;   
979       } elseif(($this->dn_exists($value))&&($cleanup)){
981         /* Delete first, then add */
982         $usermdir = true;        
984       } elseif(($this->dn_exists($value))&&($overwrite)) {
985         
986         /* Modify instead of Add */
987         $usemodify = true;
988       }
989      
990       /* If we can't Import, return with a file error */
991       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
992         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
993                         $current_line);
994         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
995     }
997     return (INSERT_OK);
998   }
1001   /* Imports a single entry */
1002   function import_single_entry($str_attr,$modify,$delete)
1003   {
1004     if($this->reconnect) $this->connect();
1006     $ret = false;
1007     $rows= split("\n",$str_attr);
1008     $data= false;
1010     foreach($rows as $row) {
1011       
1012       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1013          Linenumbers) Linenumbers are use like this 123#attribute : value */
1014       if(!empty($row)) {
1015         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1017           /* We are using line numbers 
1018              Because there is a # before a : */
1019           $tmp1= split("#",$row);
1020           $current_line= $tmp1[0];
1021           $row= $tmp1[1];
1022         }
1024         /* Split the line into  attribute  and value */
1025         $attr   = split(":", $row);
1026         $attr[0]= trim($attr[0]);  /* attribute */
1027         $attr[1]= trim($attr[1]);  /* value */
1029         /* Check for attributes that are used more than once */
1030         if(!isset($data[$attr[0]])) {
1031           $data[$attr[0]]=$attr[1];
1032         } else {
1033           $tmp = $data[$attr[0]];
1035           if(!is_array($tmp)) {
1036             $new[0]=$tmp;
1037             $new[1]=$attr[1];
1038             $datas[$attr[0]]['count']=1;             
1039             $data[$attr[0]]=$new;
1040           } else {
1041             $cnt = $datas[$attr[0]]['count'];           
1042             $cnt ++;
1043             $data[$attr[0]][$cnt]=$attr[1];
1044             $datas[$attr[0]]['count'] = $cnt;
1045           }
1046         }
1047       }
1048     } 
1049     
1050     /* If dn is an index of data, we should try to insert the data */
1051     if(isset($data['dn'])) {
1052       /* Creating Entry */
1053       $this->cd($data['dn']);
1055       /* Delete existing entry */
1056       if($delete){
1057         $this->rmdir($data['dn']);
1058       }
1059       
1060       /* Create missing trees */
1061       $this->create_missing_trees($data['dn']);
1062       unset($data['dn']);
1063       
1064       /* If entry exists use modify */
1065       if(!$modify){
1066         $ret = $this->add($data);
1067       } else {
1068         $ret = $this->modify($data);
1069       }
1070     }
1072     return($ret);
1073   }
1075   
1076   function importcsv($str)
1077   {
1078     $lines = split("\n",$str);
1079     foreach($lines as $line)
1080     {
1081       /* continue if theres a comment */
1082       if(substr(trim($line),0,1)=="#"){
1083         continue;
1084       }
1086       $line= str_replace ("\t\t","\t",$line);
1087       $line= str_replace ("\t"  ,"," ,$line);
1088       echo $line;
1090       $cells = split(",",$line )  ;
1091       $linet= str_replace ("\t\t",",",$line);
1092       $cells = split("\t",$line);
1093       $count = count($cells);  
1094     }
1096   }
1097   
1098   function get_objectclasses()
1099   {
1100           $objectclasses = array();
1101         
1102           # Get base to look for schema 
1103           $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1104           $attr = @ldap_get_entries($this->cid,$sr);
1105           if (!isset($attr[0]['subschemasubentry'][0])){
1106             return array();
1107           }
1108         
1109           # Get list of objectclasses
1110           $nb= $attr[0]['subschemasubentry'][0];
1111           $objectclasses= array();
1112           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1113           $attrs= ldap_get_entries($this->cid,$sr);
1114           if (!isset($attrs[0])){
1115             return array();
1116           }
1117           foreach ($attrs[0]['objectclasses'] as $val){
1118             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1119             if ($name != $val){
1120               $objectclasses[$name]= $val;
1121             }
1122           }
1123           
1124           return $objectclasses;
1125   }
1129 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1130 ?>