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.
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();
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;
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);
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);
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();
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 }
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);
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);
454 echo " <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();
467 if($this->hascon){
468 if ($this->reconnect) $this->connect();
470 /* Save base dn */
471 $basedn= $this->basedn;
472 $delarray= array();
474 /* Check if destination entry already exists */
475 $this->cat($destinationdn);
477 if($this->count()){
478 return;
479 }else{
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 }
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 }
516 unset($attr['count']);
517 unset($attr['dn']);
519 /* Add marking attribute */
520 $attr['objectClass'][] = "FAIbranch";
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'> </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)){
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);
747 }
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();
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 }
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 ...."
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;
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)) {
986 /* Modify instead of Add */
987 $usemodify = true;
988 }
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) {
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 }
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 }
1060 /* Create missing trees */
1061 $this->create_missing_trees($data['dn']);
1062 unset($data['dn']);
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 }
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 }
1098 function get_objectclasses()
1099 {
1100 $objectclasses = array();
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 }
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 }
1124 return $objectclasses;
1125 }
1127 }
1129 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1130 ?>