Code

Made create_missing_trees gosaUnitTag aware.
[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     if($this->hascon){
271       if($this->hasres){
272         if ($this->start == 0)
273         {
274           $this->start = 1;
275           $this->re= @ldap_first_entry($this->cid, $this->sr);
276         } else {
277           $this->re= @ldap_next_entry($this->cid, $this->re);
278         }
279         if ($this->re)
280         {
281           $att= @ldap_get_attributes($this->cid, $this->re);
282           $att['dn']= $this->convert(@ldap_get_dn($this->cid, $this->re));
283         }
284         $this->error = @ldap_error($this->cid);
285         if (!isset($att)){
286           $att= array();
287         }
288         return($att);
289       }else{
290         $this->error = "Perform a Fetch with no Search";
291         return("");
292       }
293     }else{
294       $this->error = "Could not connect to LDAP server";
295       return("");
296     }
297   }
299   function resetResult()
300   {
301     $this->start = 0;
302   }
304   function clearResult()
305   {
306     if($this->hasres){
307       $this->hasres = false;
308       @ldap_free_result($this->sr);
309     }
310   }
312   function getDN()
313   {
314     if($this->hascon){
315       if($this->hasres){
317         if(!$this->re)
318           {
319           $this->error = "Perform a Fetch with no valid Result";
320           }
321           else
322           {
323           $rv = @ldap_get_dn($this->cid, $this->re);
324         
325           $this->error = @ldap_error($this->cid);
326           return($this->convert($rv));
327            }
328       }else{
329         $this->error = "Perform a Fetch with no Search";
330         return("");
331       }
332     }else{
333       $this->error = "Could not connect to LDAP server";
334       return("");
335     }
336   }
338   function count()
339   {
340     if($this->hascon){
341       if($this->hasres){
342         $rv = @ldap_count_entries($this->cid, $this->sr);
343         $this->error = @ldap_error($this->cid);
344         return($rv);
345       }else{
346         $this->error = "Perform a Fetch with no Search";
347         return("");
348       }
349     }else{
350       $this->error = "Could not connect to LDAP server";
351       return("");
352     }
353   }
355   function rm($attrs = "", $dn = "")
356   {
357     if($this->hascon){
358       if ($this->reconnect) $this->connect();
359       if ($dn == "")
360         $dn = $this->basedn;
362       $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
363       $this->error = @ldap_error($this->cid);
364       return($r);
365     }else{
366       $this->error = "Could not connect to LDAP server";
367       return("");
368     }
369   }
371   function rename($attrs, $dn = "")
372   {
373     if($this->hascon){
374       if ($this->reconnect) $this->connect();
375       if ($dn == "")
376         $dn = $this->basedn;
378       $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
379       $this->error = @ldap_error($this->cid);
380       return($r);
381     }else{
382       $this->error = "Could not connect to LDAP server";
383       return("");
384     }
385   }
387   function rmdir($deletedn)
388   {
389     if($this->hascon){
390       if ($this->reconnect) $this->connect();
391       $r = @ldap_delete($this->cid, $this->fix($deletedn));
392       $this->error = @ldap_error($this->cid);
393       return($r ? $r : 0);
394     }else{
395       $this->error = "Could not connect to LDAP server";
396       return("");
397     }
398   }
400   /**
401   *  Function rmdir_recursive
402   *
403   *  Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
404   *  Parameters:  The dn to delete
405   *  GiveBack:    True on sucessfull , 0 in error, and "" when we don't get a ldap conection
406   *
407   */
409   function rmdir_recursive($deletedn)
410   {
411     if($this->hascon){
412       if ($this->reconnect) $this->connect();
413       $delarray= array();
414         
415       /* Get sorted list of dn's to delete */
416       $this->ls ("(objectClass=*)",$deletedn);
417       while ($this->fetch()){
418         $deldn= $this->getDN();
419         $delarray[$deldn]= strlen($deldn);
420       }
421       arsort ($delarray);
422       reset ($delarray);
424       /* Really Delete ALL dn's in subtree */
425       foreach ($delarray as $key => $value){
426         $this->rmdir_recursive($key);
427       }
428       
429       /* Finally Delete own Node */
430       $r = @ldap_delete($this->cid, $this->fix($deletedn));
431       $this->error = @ldap_error($this->cid);
432       return($r ? $r : 0);
433     }else{
434       $this->error = "Could not connect to LDAP server";
435       return("");
436     }
437   }
439   /* Copy given attributes and sub-dns with attributes to destination dn 
440   */
441   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = true,$depth=0)
442   {
443     error_reporting(E_ALL);
444     
445     if($is_first){
446       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".$sourcedn."</i>")."</h2>";
447     }else{
448       if(preg_match("/^ou=/",$sourcedn)){
449         echo "<h3>"._("Processing")." <i>$destinationdn</i></h3>";
450       }else{
451         $tmp = split(",",$sourcedn);
452         
453         echo "&nbsp;<b>"._("Object").":</b> ";
455         $deststr = $destinationdn;
456         if(strlen($deststr) > 96){
457           $deststr = substr($deststr,0,96)."...";
458         }
460         echo $deststr."<br>";
461       }
462     }
464     flush();
465     
466     if($this->hascon){
467       if ($this->reconnect) $this->connect();
469       /* Save base dn */
470       $basedn= $this->basedn;
471       $delarray= array();
472      
473       /* Check if destination entry already exists */
474       $this->cat($destinationdn);
476       if($this->count()){
477         return;
478       }else{
479         
480         $this->clearResult();
482         /* Get source entry */
483         $this->cd($basedn);
484         $this->cat($sourcedn);
485         $attr = $this->fetch();
487         /* Error while fetching object / attribute abort*/
488         if((!$attr) || (count($attr)) ==0) {
489           echo _("Error while fetching source dn - aborted!");
490           return;
491         }
492   
493         /* check if this is a department */
494         if(in_array("organizationalUnit",$attr['objectClass'])){
495           $attr['dn'] = $this->convert($destinationdn);
496           $this->cd($basedn);
497           $this->create_missing_trees($destinationdn);
498           $this->cd($destinationdn);
500           /* If is first entry, append FAIbranch to department entry */
501           if($is_first){
502             $this->cat($destinationdn);
503             $attr= $this->fetch();
505             /* Filter unneeded informations */
506             foreach($attr as $key => $value){
507               if(is_numeric($key)) unset($attr[$key]);
508               if(isset($attr[$key]['count'])){
509                 if(is_array($attr[$key])){
510                   unset($attr[$key]['count']);
511                 }
512               }
513             }
514             
515             unset($attr['count']);
516             unset($attr['dn']);
518             /* Add marking attribute */
519             $attr['objectClass'][] = "FAIbranch";
520             
521             /* Add this entry */
522             $this->modify($attr);
523           }
524         }else{
526           /* If this is no department */
527           foreach($attr as $key => $value){
528             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
529               $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
530               $ei= ldap_first_entry($this->cid, $sr);
531               if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
532                 $attr[$key] = $tmp;
533               }
534             }
536             if(is_numeric($key)) unset($attr[$key]);
537             if(isset($attr[$key]['count'])){
538               if(is_array($attr[$key])){
539                 unset($attr[$key]['count']);
540               }
541             }
542           }
543           unset($attr['count']);
544           unset($attr['dn']);
546           if(!in_array("gosaApplication" , $attr['objectClass'])){
547             if($type=="branch"){
548               $attr['FAIstate'] ="branch";
549             }elseif($type=="freeze"){
550               $attr['FAIstate'] ="freeze";
551             }else{
552               print_red(_("Unknown FAIstate %s"),$type);
553             }
554           }
556           /* Add entry */
557           $this->cd($destinationdn);
558           $this->cat($destinationdn);
559           $a = $this->fetch();
560           if(!count($a)){
561             $this->add($attr);
562           }
564           if($this->error != "Success"){
565             /* Some error occured */
566             print "---------------------------------------------";
567             print $this->get_error()."<br>";
568             print $sourcedn."<br>";
569             print $destinationdn."<br>";
570             print_a( $attr);
571             exit();
572           }          
573         }
574       }
576       $this->ls ("(objectClass=*)",$sourcedn);
577       while ($this->fetch()){
578         $deldn= $this->getDN();
579         $delarray[$deldn]= strlen($deldn);
580       }
581       asort ($delarray);
582       reset ($delarray);
584        $depth ++;
585       foreach($delarray as $dn => $bla){
586         if($dn != $destinationdn){
587           $this->cd($basedn);
588           $item = $this->fetch($this->cat($dn));
589           if(!in_array("FAIbranch",$item['objectClass'])){
590             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$type,false,$depth);
591           } 
592         }
593       }
594     }
595     if($is_first){
596       echo "<p class='seperator'>&nbsp;</p>";
597     }
599   }
601   function modify($attrs)
602   {
603     if(count($attrs) == 0){
604       return (0);
605     }
606     if($this->hascon){
607       if ($this->reconnect) $this->connect();
608       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
609       $this->error = @ldap_error($this->cid);
610       return($r ? $r : 0);
611     }else{
612       $this->error = "Could not connect to LDAP server";
613       return("");
614     }
615   }
617   function add($attrs)
618   {
619     if($this->hascon){
620       if ($this->reconnect) $this->connect();
621       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
622       $this->error = @ldap_error($this->cid);
623       return($r ? $r : 0);
624     }else{
625       $this->error = "Could not connect to LDAP server";
626       return("");
627     }
628   }
630   function create_missing_trees($target)
631   {
632     /* Ignore create_missing trees if the base equals target */
633     if ($target == $this->basedn){
634      return;
635     }
637     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
638     $l= array_reverse(ldap_explode_dn($real_path,0));
639     unset($l['count']);
640     $cdn= $this->basedn;
641     $tag= "";
643     foreach ($l as $part){
644       $cdn= "$part,$cdn";
646       /* Ignore referrals */
647       $found= false;
648       foreach($this->referrals as $ref){
649         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
650         if ($base == $cdn){
651           $found= true;
652           break;
653         }
654       }
655       if ($found){
656         continue;
657       }
659       $this->cat ($cdn);
660       $attrs= $this->fetch();
662       /* Create missing entry? */
663       if (count ($attrs)){
664       
665         /* Catch the tag - if present */
666         if (isset($attrs['gosaUnitTag'][0])){
667           $tag= $attrs['gosaUnitTag'][0];
668         }
670       } else {
671         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
672         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
674         $na= array();
675         switch ($type){
676           case 'ou':
677             if ($tag != ""){
678               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
679               $na["gosaUnitTag"]= $tag;
680             } else {
681               $na["objectClass"]= "organizationalUnit";
682             }
683             $na["ou"]= $param;
684             break;
685           case 'dc':
686             if ($tag != ""){
687               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
688               $na["gosaUnitTag"]= $tag;
689             } else {
690               $na["objectClass"]= array("dcObject", "top", "locality");
691             }
692             $na["dc"]= $param;
693             break;
694           default:
695             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
696             echo $_SESSION['errors'];
697             exit;
698         }
699         $this->cd($cdn);
700         $this->add($na);
701       }
702     }
703   }
705   function recursive_remove()
706   {
707     $delarray= array();
709     /* Get sorted list of dn's to delete */
710     $this->search ("(objectClass=*)");
711     while ($this->fetch()){
712       $deldn= $this->getDN();
713       $delarray[$deldn]= strlen($deldn);
714     }
715     arsort ($delarray);
716     reset ($delarray);
718     /* Delete all dn's in subtree */
719     foreach ($delarray as $key => $value){
720       $this->rmdir($key);
721     }
722   }
724   function get_attribute($dn, $name,$r_array=0)
725   {
726     $data= "";
727     if ($this->reconnect) $this->connect();
728     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
730     /* fill data from LDAP */
731     if ($sr) {
732       $ei= @ldap_first_entry($this->cid, $sr);
733       if ($ei) {
734         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
735           $data= $info[0];
736         }
738       }
739     }
740     if($r_array==0)
741     return ($data);
742     else
743     return ($info);
744   
745   
746   }
747  
750   function get_additional_error()
751   {
752     $error= "";
753     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
754     return ($error);
755   }
757   function get_error()
758   {
759     if ($this->error == 'Success'){
760       return $this->error;
761     } else {
762       $error= $this->error." (".$this->get_additional_error().")";
763       return $error;
764     }
765   }
767   function get_credentials($url, $referrals= NULL)
768   {
769     $ret= array();
770     $url= preg_replace('!\?\?.*$!', '', $url);
771     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
773     if ($referrals == NULL){
774       $referrals= $this->referrals;
775     }
777     if (isset($referrals[$server])){
778       return ($referrals[$server]);
779     } else {
780       $ret['ADMIN']= $this->fix($this->binddn);
781       $ret['PASSWORD']= $this->bindpw;
782     }
784     return ($ret);
785   }
788   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
789   {
790     $display= "";
792     if ($recursive){
793       $this->cd($dn);
794       $this->search("$filter", array('dn'));
795       while ($attrs= $this->fetch()){
796         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
797         $display.= "\n";
798       }
799     } else {
800       $display.= $this->gen_one_entry($dn);
801     }
803     return ($display);
804   }
806 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
807   {
808     $display= "";
810       $this->cd($dn);
811       $this->search("$filter");
813       $i=0;
814       while ($attrs= $this->fetch()){
815         $j=0;
817         foreach ($attributes as $at){
818           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
819           $j++;
820         }
822         $i++;
823       }
825     return ($display);
826   }
829   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
830   {
831     $ret = "";
832     $data = "";
833     if($this->reconnect){
834       $this->connect();
835     }
837     /* Searching Ldap Tree */
838     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
840     /* Get the first entry */   
841     $entry= @ldap_first_entry($this->cid, $sr);
843     /* Get all attributes related to that Objekt */
844     $atts = array();
845     
846     /* Assemble dn */
847     $atts[0]['name']  = "dn";
848     $atts[0]['value'] = array('count' => 1, 0 => $dn);
850     /* Reset index */
851     $i = 1 ; 
852   $identifier = array();
853     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
854     while ($attribute) {
855       $i++;
856       $atts[$i]['name']  = $attribute;
857       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
859       /* Next one */
860       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
861     }
863     foreach($atts as $at)
864     {
865       for ($i= 0; $i<$at['value']['count']; $i++){
867         /* Check if we must encode the data */
868         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
869           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
870         } else {
871           $ret .= $at['name'].": ".$at['value'][$i]."\n";
872         }
873       }
874     }
876     return($ret);
877   }
880   function dn_exists($dn)
881   {
882     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
883   }
884   
887   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
888   {
889     if($this->reconnect) $this->connect();
891     /* First we have to splitt the string ito detect empty lines
892        An empty line indicates an new Entry */
893     $entries = split("\n",$str_attr);
895     $data = "";
896     $cnt = 0; 
897     $current_line = 0;
899     /* Every single line ... */
900     foreach($entries as $entry) {
901       $current_line ++;
903       /* Removing Spaces to .. 
904          .. test if a new entry begins */
905       $tmp  = str_replace(" ","",$data );
907       /* .. prevent empty lines in an entry */
908       $tmp2 = str_replace(" ","",$entry);
910       /* If the Block ends (Empty Line) */
911       if((empty($entry))&&(!empty($tmp))) {
912         /* Add collected lines as a complete block */
913         $all[$cnt] = $data;
914         $cnt ++;
915         $data ="";
916       } else {
918         /* Append lines ... */
919         if(!empty($tmp2)) {
920           /* check if we need base64_decode for this line */
921           if(ereg("::",$tmp2))
922           {
923             $encoded = split("::",$entry);
924             $attr  = $encoded[0];
925             $value = base64_decode($encoded[1]);
926             /* Add linenumber */
927             $data .= $current_line."#".$attr.":".$value."\n";
928           }
929           else
930           {
931             /* Add Linenumber */ 
932             $data .= $current_line."#".$entry."\n";
933           }
934         }
935       }
936     }
938     /* The Data we collected is not in the array all[];
939        For example the Data is stored like this..
941        all[0] = "1#dn : .... \n 
942        2#ObjectType: person \n ...."
943        
944        Now we check every insertblock and try to insert */
945     foreach ( $all as $single) {
946       $lineone = split("\n",$single);  
947       $ndn = split("#", $lineone[0]);
948       $line = $ndn[1];
950       $dnn = split (":",$line);
951       $current_line = $ndn[0];
952       $dn    = $dnn[0];
953       $value = $dnn[1];
955       /* Every block must begin with a dn */
956       if($dn != "dn") {
957         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
958         return -2;  
959       }
961       /* Should we use Modify instead of Add */
962       $usemodify= false;
964       /* Delete before insert */
965       $usermdir= false;
966     
967       /* The dn address already exists! */
968       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
970         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
971         return ALREADY_EXISTING_ENTRY;   
973       } elseif(($this->dn_exists($value))&&($cleanup)){
975         /* Delete first, then add */
976         $usermdir = true;        
978       } elseif(($this->dn_exists($value))&&($overwrite)) {
979         
980         /* Modify instead of Add */
981         $usemodify = true;
982       }
983      
984       /* If we can't Import, return with a file error */
985       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
986         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
987                         $current_line);
988         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
989     }
991     return (INSERT_OK);
992   }
995   /* Imports a single entry */
996   function import_single_entry($str_attr,$modify,$delete)
997   {
998     if($this->reconnect) $this->connect();
1000     $ret = false;
1001     $rows= split("\n",$str_attr);
1002     $data= false;
1004     foreach($rows as $row) {
1005       
1006       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1007          Linenumbers) Linenumbers are use like this 123#attribute : value */
1008       if(!empty($row)) {
1009         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1011           /* We are using line numbers 
1012              Because there is a # before a : */
1013           $tmp1= split("#",$row);
1014           $current_line= $tmp1[0];
1015           $row= $tmp1[1];
1016         }
1018         /* Split the line into  attribute  and value */
1019         $attr   = split(":", $row);
1020         $attr[0]= trim($attr[0]);  /* attribute */
1021         $attr[1]= trim($attr[1]);  /* value */
1023         /* Check for attributes that are used more than once */
1024         if(!isset($data[$attr[0]])) {
1025           $data[$attr[0]]=$attr[1];
1026         } else {
1027           $tmp = $data[$attr[0]];
1029           if(!is_array($tmp)) {
1030             $new[0]=$tmp;
1031             $new[1]=$attr[1];
1032             $datas[$attr[0]]['count']=1;             
1033             $data[$attr[0]]=$new;
1034           } else {
1035             $cnt = $datas[$attr[0]]['count'];           
1036             $cnt ++;
1037             $data[$attr[0]][$cnt]=$attr[1];
1038             $datas[$attr[0]]['count'] = $cnt;
1039           }
1040         }
1041       }
1042     } 
1043     
1044     /* If dn is an index of data, we should try to insert the data */
1045     if(isset($data['dn'])) {
1046       /* Creating Entry */
1047       $this->cd($data['dn']);
1049       /* Delete existing entry */
1050       if($delete){
1051         $this->rmdir($data['dn']);
1052       }
1053       
1054       /* Create missing trees */
1055       $this->create_missing_trees($data['dn']);
1056       unset($data['dn']);
1057       
1058       /* If entry exists use modify */
1059       if(!$modify){
1060         $ret = $this->add($data);
1061       } else {
1062         $ret = $this->modify($data);
1063       }
1064     }
1066     return($ret);
1067   }
1069   
1070   function importcsv($str)
1071   {
1072     $lines = split("\n",$str);
1073     foreach($lines as $line)
1074     {
1075       /* continue if theres a comment */
1076       if(substr(trim($line),0,1)=="#"){
1077         continue;
1078       }
1080       $line= str_replace ("\t\t","\t",$line);
1081       $line= str_replace ("\t"  ,"," ,$line);
1082       echo $line;
1084       $cells = split(",",$line )  ;
1085       $linet= str_replace ("\t\t",",",$line);
1086       $cells = split("\t",$line);
1087       $count = count($cells);  
1088     }
1090   }
1091   
1092   function get_objectclasses()
1093   {
1094           $objectclasses = array();
1095         
1096           # Get base to look for schema 
1097           $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1098           $attr = @ldap_get_entries($this->cid,$sr);
1099           if (!isset($attr[0]['subschemasubentry'][0])){
1100             return array();
1101           }
1102         
1103           # Get list of objectclasses
1104           $nb= $attr[0]['subschemasubentry'][0];
1105           $objectclasses= array();
1106           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1107           $attrs= ldap_get_entries($this->cid,$sr);
1108           if (!isset($attrs[0])){
1109             return array();
1110           }
1111           foreach ($attrs[0]['objectclasses'] as $val){
1112             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1113             if ($name != $val){
1114               $objectclasses[$name]= $val;
1115             }
1116           }
1117           
1118           return $objectclasses;
1119   }
1123 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1124 ?>