Code

Added max query time for search / ls
[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 ldapserver is answering very slow (%.2f), 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;
642     foreach ($l as $part){
643       $cdn= "$part,$cdn";
645       /* Ignore referrals */
646       $found= false;
647       foreach($this->referrals as $ref){
648         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
649         if ($base == $cdn){
650           $found= true;
651           break;
652         }
653       }
654       if ($found){
655         continue;
656       }
658       $this->cat ($cdn);
659       $attrs= $this->fetch();
661       /* Create missing entry? */
662       if (!count ($attrs)){
663         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
664         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
666         $na= array();
667         switch ($type){
668           case 'ou':
669             $na["objectClass"]= "organizationalUnit";
670             $na["ou"]= $param;
671             break;
672           case 'dc':
673             $na["objectClass"]= array("dcObject", "top", "locality");
674             $na["dc"]= $param;
675             break;
676           default:
677             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
678             echo $_SESSION['errors'];
679             exit;
680         }
681         $this->cd($cdn);
682         $this->add($na);
683       }
684     }
685   }
687   function recursive_remove()
688   {
689     $delarray= array();
691     /* Get sorted list of dn's to delete */
692     $this->search ("(objectClass=*)");
693     while ($this->fetch()){
694       $deldn= $this->getDN();
695       $delarray[$deldn]= strlen($deldn);
696     }
697     arsort ($delarray);
698     reset ($delarray);
700     /* Delete all dn's in subtree */
701     foreach ($delarray as $key => $value){
702       $this->rmdir($key);
703     }
704   }
706   function get_attribute($dn, $name,$r_array=0)
707   {
708     $data= "";
709     if ($this->reconnect) $this->connect();
710     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
712     /* fill data from LDAP */
713     if ($sr) {
714       $ei= @ldap_first_entry($this->cid, $sr);
715       if ($ei) {
716         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
717           $data= $info[0];
718         }
720       }
721     }
722     if($r_array==0)
723     return ($data);
724     else
725     return ($info);
726   
727   
728   }
729  
732   function get_additional_error()
733   {
734     $error= "";
735     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
736     return ($error);
737   }
739   function get_error()
740   {
741     if ($this->error == 'Success'){
742       return $this->error;
743     } else {
744       $error= $this->error." (".$this->get_additional_error().")";
745       return $error;
746     }
747   }
749   function get_credentials($url, $referrals= NULL)
750   {
751     $ret= array();
752     $url= preg_replace('!\?\?.*$!', '', $url);
753     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
755     if ($referrals == NULL){
756       $referrals= $this->referrals;
757     }
759     if (isset($referrals[$server])){
760       return ($referrals[$server]);
761     } else {
762       $ret['ADMIN']= $this->fix($this->binddn);
763       $ret['PASSWORD']= $this->bindpw;
764     }
766     return ($ret);
767   }
770   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
771   {
772     $display= "";
774     if ($recursive){
775       $this->cd($dn);
776       $this->search("$filter", array('dn'));
777       while ($attrs= $this->fetch()){
778         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
779         $display.= "\n";
780       }
781     } else {
782       $display.= $this->gen_one_entry($dn);
783     }
785     return ($display);
786   }
788 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
789   {
790     $display= "";
792       $this->cd($dn);
793       $this->search("$filter");
795       $i=0;
796       while ($attrs= $this->fetch()){
797         $j=0;
799         foreach ($attributes as $at){
800           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
801           $j++;
802         }
804         $i++;
805       }
807     return ($display);
808   }
811   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
812   {
813     $ret = "";
814     $data = "";
815     if($this->reconnect){
816       $this->connect();
817     }
819     /* Searching Ldap Tree */
820     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
822     /* Get the first entry */   
823     $entry= @ldap_first_entry($this->cid, $sr);
825     /* Get all attributes related to that Objekt */
826     $atts = array();
827     
828     /* Assemble dn */
829     $atts[0]['name']  = "dn";
830     $atts[0]['value'] = array('count' => 1, 0 => $dn);
832     /* Reset index */
833     $i = 1 ; 
834   $identifier = array();
835     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
836     while ($attribute) {
837       $i++;
838       $atts[$i]['name']  = $attribute;
839       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
841       /* Next one */
842       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
843     }
845     foreach($atts as $at)
846     {
847       for ($i= 0; $i<$at['value']['count']; $i++){
849         /* Check if we must encode the data */
850         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
851           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
852         } else {
853           $ret .= $at['name'].": ".$at['value'][$i]."\n";
854         }
855       }
856     }
858     return($ret);
859   }
862   function dn_exists($dn)
863   {
864     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
865   }
866   
869   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
870   {
871     if($this->reconnect) $this->connect();
873     /* First we have to splitt the string ito detect empty lines
874        An empty line indicates an new Entry */
875     $entries = split("\n",$str_attr);
877     $data = "";
878     $cnt = 0; 
879     $current_line = 0;
881     /* Every single line ... */
882     foreach($entries as $entry) {
883       $current_line ++;
885       /* Removing Spaces to .. 
886          .. test if a new entry begins */
887       $tmp  = str_replace(" ","",$data );
889       /* .. prevent empty lines in an entry */
890       $tmp2 = str_replace(" ","",$entry);
892       /* If the Block ends (Empty Line) */
893       if((empty($entry))&&(!empty($tmp))) {
894         /* Add collected lines as a complete block */
895         $all[$cnt] = $data;
896         $cnt ++;
897         $data ="";
898       } else {
900         /* Append lines ... */
901         if(!empty($tmp2)) {
902           /* check if we need base64_decode for this line */
903           if(ereg("::",$tmp2))
904           {
905             $encoded = split("::",$entry);
906             $attr  = $encoded[0];
907             $value = base64_decode($encoded[1]);
908             /* Add linenumber */
909             $data .= $current_line."#".$attr.":".$value."\n";
910           }
911           else
912           {
913             /* Add Linenumber */ 
914             $data .= $current_line."#".$entry."\n";
915           }
916         }
917       }
918     }
920     /* The Data we collected is not in the array all[];
921        For example the Data is stored like this..
923        all[0] = "1#dn : .... \n 
924        2#ObjectType: person \n ...."
925        
926        Now we check every insertblock and try to insert */
927     foreach ( $all as $single) {
928       $lineone = split("\n",$single);  
929       $ndn = split("#", $lineone[0]);
930       $line = $ndn[1];
932       $dnn = split (":",$line);
933       $current_line = $ndn[0];
934       $dn    = $dnn[0];
935       $value = $dnn[1];
937       /* Every block must begin with a dn */
938       if($dn != "dn") {
939         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
940         return -2;  
941       }
943       /* Should we use Modify instead of Add */
944       $usemodify= false;
946       /* Delete before insert */
947       $usermdir= false;
948     
949       /* The dn address already exists! */
950       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
952         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
953         return ALREADY_EXISTING_ENTRY;   
955       } elseif(($this->dn_exists($value))&&($cleanup)){
957         /* Delete first, then add */
958         $usermdir = true;        
960       } elseif(($this->dn_exists($value))&&($overwrite)) {
961         
962         /* Modify instead of Add */
963         $usemodify = true;
964       }
965      
966       /* If we can't Import, return with a file error */
967       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
968         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
969                         $current_line);
970         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
971     }
973     return (INSERT_OK);
974   }
977   /* Imports a single entry */
978   function import_single_entry($str_attr,$modify,$delete)
979   {
980     if($this->reconnect) $this->connect();
982     $ret = false;
983     $rows= split("\n",$str_attr);
984     $data= false;
986     foreach($rows as $row) {
987       
988       /* Check if we use Linenumbers (when import_complete_ldif is called we use
989          Linenumbers) Linenumbers are use like this 123#attribute : value */
990       if(!empty($row)) {
991         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
993           /* We are using line numbers 
994              Because there is a # before a : */
995           $tmp1= split("#",$row);
996           $current_line= $tmp1[0];
997           $row= $tmp1[1];
998         }
1000         /* Split the line into  attribute  and value */
1001         $attr   = split(":", $row);
1002         $attr[0]= trim($attr[0]);  /* attribute */
1003         $attr[1]= trim($attr[1]);  /* value */
1005         /* Check for attributes that are used more than once */
1006         if(!isset($data[$attr[0]])) {
1007           $data[$attr[0]]=$attr[1];
1008         } else {
1009           $tmp = $data[$attr[0]];
1011           if(!is_array($tmp)) {
1012             $new[0]=$tmp;
1013             $new[1]=$attr[1];
1014             $datas[$attr[0]]['count']=1;             
1015             $data[$attr[0]]=$new;
1016           } else {
1017             $cnt = $datas[$attr[0]]['count'];           
1018             $cnt ++;
1019             $data[$attr[0]][$cnt]=$attr[1];
1020             $datas[$attr[0]]['count'] = $cnt;
1021           }
1022         }
1023       }
1024     } 
1025     
1026     /* If dn is an index of data, we should try to insert the data */
1027     if(isset($data['dn'])) {
1028       /* Creating Entry */
1029       $this->cd($data['dn']);
1031       /* Delete existing entry */
1032       if($delete){
1033         $this->rmdir($data['dn']);
1034       }
1035       
1036       /* Create missing trees */
1037       $this->create_missing_trees($data['dn']);
1038       unset($data['dn']);
1039       
1040       /* If entry exists use modify */
1041       if(!$modify){
1042         $ret = $this->add($data);
1043       } else {
1044         $ret = $this->modify($data);
1045       }
1046     }
1048     return($ret);
1049   }
1051   
1052   function importcsv($str)
1053   {
1054     $lines = split("\n",$str);
1055     foreach($lines as $line)
1056     {
1057       /* continue if theres a comment */
1058       if(substr(trim($line),0,1)=="#"){
1059         continue;
1060       }
1062       $line= str_replace ("\t\t","\t",$line);
1063       $line= str_replace ("\t"  ,"," ,$line);
1064       echo $line;
1066       $cells = split(",",$line )  ;
1067       $linet= str_replace ("\t\t",",",$line);
1068       $cells = split("\t",$line);
1069       $count = count($cells);  
1070     }
1072   }
1073   
1074   function get_objectclasses()
1075   {
1076           $objectclasses = array();
1077         
1078           # Get base to look for schema 
1079           $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1080           $attr = @ldap_get_entries($this->cid,$sr);
1081           if (!isset($attr[0]['subschemasubentry'][0])){
1082             return array();
1083           }
1084         
1085           # Get list of objectclasses
1086           $nb= $attr[0]['subschemasubentry'][0];
1087           $objectclasses= array();
1088           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1089           $attrs= ldap_get_entries($this->cid,$sr);
1090           if (!isset($attrs[0])){
1091             return array();
1092           }
1093           foreach ($attrs[0]['objectclasses'] as $val){
1094             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1095             if ($name != $val){
1096               $objectclasses[$name]= $val;
1097             }
1098           }
1099           
1100           return $objectclasses;
1101   }
1105 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1106 ?>