dolibarr 24.0.0-beta
ldap.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
4 * Copyright (C) 2005-2021 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2006-2021 Laurent Destailleur <eldy@users.sourceforge.net>
6 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
7 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
8 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 * or see https://www.gnu.org/
23 */
24
39class Ldap
40{
44 public $error = '';
45
49 public $errors = array();
50
54 public $server = array();
55
59 public $connectedServer;
60
64 public $serverPort;
65
70 public $dn;
75 public $serverType;
80 public $ldapProtocolVersion;
85 public $domain;
86
90 public $domainFQDN;
91
95 public $bind;
96
101 public $searchUser;
106 public $searchPassword;
107
111 public $people;
112
116 public $groups;
117
121 public $ldapErrorCode;
122
126 public $ldapErrorText;
127
131 public $filter;
132
136 public $filtergroup;
137
141 public $filtermember;
142
146 public $attr_login;
147
151 public $attr_sambalogin;
152
156 public $attr_name;
157
161 public $attr_firstname;
162
166 public $attr_mail;
167
171 public $attr_phone;
172
176 public $attr_fax;
177
181 public $attr_mobile;
182
186 public $badpwdtime;
187
191 public $ldapUserDN;
192
196 public $name;
197
201 public $firstname;
202
206 public $login;
207
211 public $phone;
212
216 public $fax;
217
221 public $mail;
222
226 public $mobile;
227
231 public $uacf;
232
236 public $pwdlastset;
237
242 public $ldapcharset = 'UTF-8';
243
248 public $connection;
249
253 public $result;
254
258 const SYNCHRO_NONE = 0;
259
263 const SYNCHRO_DOLIBARR_TO_LDAP = 1;
264
268 const SYNCHRO_LDAP_TO_DOLIBARR = 2;
269
273 public function __construct()
274 {
275
276 // Server
277 if (getDolGlobalString('LDAP_SERVER_HOST')) {
278 $this->server[] = getDolGlobalString('LDAP_SERVER_HOST');
279 }
280 if (getDolGlobalString('LDAP_SERVER_HOST_SLAVE')) {
281 $this->server[] = getDolGlobalString('LDAP_SERVER_HOST_SLAVE');
282 }
283 $this->serverPort = getDolGlobalInt('LDAP_SERVER_PORT', 389);
284 $this->ldapProtocolVersion = getDolGlobalString('LDAP_SERVER_PROTOCOLVERSION');
285 $this->dn = getDolGlobalString('LDAP_SERVER_DN');
286 $this->serverType = getDolGlobalString('LDAP_SERVER_TYPE');
287
288 $this->domain = getDolGlobalString('LDAP_SERVER_DN');
289 $this->searchUser = getDolGlobalString('LDAP_ADMIN_DN');
290 $this->searchPassword = getDolGlobalString('LDAP_ADMIN_PASS');
291 $this->people = getDolGlobalString('LDAP_USER_DN');
292 $this->groups = getDolGlobalString('LDAP_GROUP_DN');
293
294 $this->filter = getDolGlobalString('LDAP_FILTER_CONNECTION'); // Filter on user
295 $this->filtergroup = getDolGlobalString('LDAP_GROUP_FILTER'); // Filter on groups
296 $this->filtermember = getDolGlobalString('LDAP_MEMBER_FILTER'); // Filter on member
297
298 // Users
299 $this->attr_login = getDolGlobalString('LDAP_FIELD_LOGIN'); //unix
300 $this->attr_sambalogin = getDolGlobalString('LDAP_FIELD_LOGIN_SAMBA'); //samba, activedirectory
301 $this->attr_name = getDolGlobalString('LDAP_FIELD_NAME');
302 $this->attr_firstname = getDolGlobalString('LDAP_FIELD_FIRSTNAME');
303 $this->attr_mail = getDolGlobalString('LDAP_FIELD_MAIL');
304 $this->attr_phone = getDolGlobalString('LDAP_FIELD_PHONE');
305 $this->attr_fax = getDolGlobalString('LDAP_FIELD_FAX');
306 $this->attr_mobile = getDolGlobalString('LDAP_FIELD_MOBILE');
307 }
308
309 // Connection handling methods -------------------------------------------
310
318 public function connectBind()
319 {
320 global $dolibarr_main_auth_ldap_debug;
321
322 $connected = 0;
323 $this->bind = false;
324 $this->error = '';
325 $this->connectedServer = '';
326
327 $ldapdebug = !((empty($dolibarr_main_auth_ldap_debug) || $dolibarr_main_auth_ldap_debug == "false"));
328
329 if ($ldapdebug) {
330 dol_syslog(get_class($this)."::connectBind");
331 print "DEBUG: connectBind<br>\n";
332 }
333
334 // Check parameters
335 if (count($this->server) == 0 || empty($this->server[0])) {
336 $this->error = 'LDAP setup (file conf.php) is not complete';
337 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
338 return -1;
339 }
340
341 if (!function_exists("ldap_connect")) {
342 $this->error = 'LDAPFunctionsNotAvailableOnPHP';
343 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
344 return -1;
345 }
346
347 if (empty($this->error)) {
348 // Loop on each ldap server
349 foreach ($this->server as $host) {
350 if ($connected) { // @phpstan-ignore if.alwaysFalse
351 break;
352 }
353 if (empty($host)) {
354 continue;
355 }
356
357 if ($this->serverPing($host, $this->serverPort)) {
358 if ($ldapdebug) {
359 dol_syslog(get_class($this)."::connectBind serverPing true, we try ldap_connect to ".$host, LOG_DEBUG);
360 }
361 if (version_compare(PHP_VERSION, '8.3.0', '>=')) {
362 $uri = $host.':'.$this->serverPort;
363 $this->connection = ldap_connect($uri);
364 } else {
365 $this->connection = ldap_connect($host, $this->serverPort);
366 }
367 } else {
368 if (preg_match('/^ldaps/i', $host)) {
369 // With host = ldaps://server, the serverPing to ssl://server sometimes fails, even if the ldap_connect succeed, so
370 // we test this case and continue in such a case even if serverPing fails.
371 if ($ldapdebug) {
372 dol_syslog(get_class($this)."::connectBind serverPing false, we try ldap_connect to ".$host, LOG_DEBUG);
373 }
374 if (version_compare(PHP_VERSION, '8.3.0', '>=')) {
375 $uri = $host.':'.$this->serverPort;
376 $this->connection = ldap_connect($uri);
377 } else {
378 $this->connection = ldap_connect($host, $this->serverPort);
379 }
380 } else {
381 if ($ldapdebug) {
382 dol_syslog(get_class($this)."::connectBind serverPing false, no ldap_connect ".$host, LOG_DEBUG);
383 }
384 continue;
385 }
386 }
387
388 if ($this->connection !== false) {
389 if ($ldapdebug) {
390 dol_syslog(get_class($this)."::connectBind this->connection is ok", LOG_DEBUG);
391 }
392
393 // Upgrade connection to TLS, if requested by the configuration
394 if (getDolGlobalString('LDAP_SERVER_USE_TLS')) {
395 // For test/debug
396 //ldap_set_option($this->connection, LDAP_OPT_DEBUG_LEVEL, 7);
397 //ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
398 //ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
399
400 $resulttls = ldap_start_tls($this->connection);
401 if (!$resulttls) {
402 dol_syslog(get_class($this)."::connectBind failed to start tls", LOG_WARNING);
403 $this->error = 'ldap_start_tls Failed to start TLS '.ldap_errno($this->connection).' '.ldap_error($this->connection);
404 $connected = 0;
405 $this->unbind();
406 }
407 }
408
409 // Execute the ldap_set_option here (after connect and before bind)
410 $this->setVersion();
411 $this->setSizeLimit();
412
413 if ($this->serverType == "activedirectory") {
414 $result = $this->setReferrals();
415 dol_syslog(get_class($this)."::connectBind try bindauth for activedirectory on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
416 $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
417 if ($this->result) {
418 $this->bind = $this->result;
419 $connected = 2;
420 $this->connectedServer = $host;
421 break;
422 } else {
423 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
424 }
425 } else {
426 // Try in auth mode
427 if ($this->searchUser && $this->searchPassword) {
428 dol_syslog(get_class($this)."::connectBind try bindauth on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
429 $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
430 if ($this->result) {
431 $this->bind = $this->result;
432 $connected = 2;
433 $this->connectedServer = $host;
434 break;
435 } else {
436 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
437 }
438 }
439 // Try in anonymous
440 if (!$this->bind) { // @phpstan-ignore booleanNot.alwaysTrue
441 dol_syslog(get_class($this)."::connectBind try bind anonymously on ".$host, LOG_DEBUG);
442 $result = $this->bind();
443 if ($result) {
444 $this->bind = $this->result;
445 $connected = 1;
446 $this->connectedServer = $host;
447 break;
448 } else {
449 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
450 }
451 }
452 }
453 }
454
455 if (!$connected) { // @phpstan-ignore booleanNot.alwaysTrue
456 $this->unbind();
457 }
458 } // End loop on each server
459 }
460
461 if ($connected) {
462 dol_syslog(get_class($this)."::connectBind ".$connected, LOG_DEBUG);
463 return $connected;
464 } else {
465 $this->error = 'Failed to connect to LDAP'.($this->error ? ': '.$this->error : '');
466 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
467 return -1;
468 }
469 }
470
479 public function close()
480 {
481 return $this->unbind();
482 }
483
490 public function bind()
491 {
492 if (!$this->result = @ldap_bind($this->connection)) {
493 $this->ldapErrorCode = ldap_errno($this->connection);
494 $this->ldapErrorText = ldap_error($this->connection);
495 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
496 return false;
497 } else {
498 return true;
499 }
500 }
501
512 public function bindauth($bindDn, $pass)
513 {
514 if (!$this->result = @ldap_bind($this->connection, $bindDn, $pass)) {
515 $this->ldapErrorCode = ldap_errno($this->connection);
516 $this->ldapErrorText = ldap_error($this->connection);
517 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
518 return false;
519 } else {
520 return true;
521 }
522 }
523
530 public function unbind()
531 {
532 $this->result = true;
533 if (version_compare(PHP_VERSION, '8.1.0', '>=')) {
534 if (is_object($this->connection)) {
535 try {
536 $this->result = ldap_unbind($this->connection);
537 } catch (Throwable $exception) {
538 $this->error = 'Failed to unbind LDAP connection: '.$exception;
539 $this->result = false;
540 dol_syslog(get_class($this).'::unbind - '.$this->error, LOG_WARNING);
541 }
542 }
543 } else {
544 if ($this->connection !== false) {
545 // @phan-suppress-next-line PhanTypeMismatchArgumentInternalReal PhanTypeSuspiciousIndirectVariable
546 $this->result = @ldap_unbind($this->connection);
547 }
548 }
549 if ($this->result) {
550 return true;
551 } else {
552 return false;
553 }
554 }
555
556
562 public function getVersion()
563 {
564 @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
565 return $version;
566 }
567
574 public function setVersion()
575 {
576 return ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
577 }
578
584 public function setSizeLimit()
585 {
586 return ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0);
587 }
588
595 public function setReferrals()
596 {
597 return ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
598 }
599
600
610 public function add($dn, $info, $user)
611 {
612 dol_syslog(get_class($this)."::add dn=".$dn." info=".print_r($info, true));
613
614 // Check parameters
615 if (!$this->connection) {
616 $this->error = "NotConnected";
617 return -2;
618 }
619 if (!$this->bind) {
620 $this->error = "NotConnected";
621 return -3;
622 }
623
624 // Encode to LDAP page code
625 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
626 foreach ($info as $key => $val) {
627 if (!is_array($val)) {
628 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
629 }
630 }
631
632 $this->dump($dn, $info);
633
634 //print_r($info);
635 $result = @ldap_add($this->connection, $dn, $info);
636
637 if ($result) {
638 dol_syslog(get_class($this)."::add successful", LOG_DEBUG);
639 return 1;
640 } else {
641 $this->ldapErrorCode = @ldap_errno($this->connection);
642 $this->ldapErrorText = @ldap_error($this->connection);
643 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
644 dol_syslog(get_class($this)."::add failed: ".$this->error, LOG_ERR);
645 return -1;
646 }
647 }
648
658 public function modify($dn, $info, $user)
659 {
660 dol_syslog(get_class($this)."::modify dn=".$dn." info=".print_r($info, true));
661
662 // Check parameters
663 if (!$this->connection) {
664 $this->error = "NotConnected";
665 return -2;
666 }
667 if (!$this->bind) {
668 $this->error = "NotConnected";
669 return -3;
670 }
671
672 // Encode to LDAP page code
673 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
674 foreach ($info as $key => $val) {
675 if (!is_array($val)) {
676 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
677 }
678 }
679
680 $this->dump($dn, $info);
681
682 //print_r($info);
683
684 // For better compatibility with Samba4 AD
685 if ($this->serverType == "activedirectory") {
686 unset($info['cn']); // To avoid error : Operation not allowed on RDN (Code 67)
687
688 // To avoid error : LDAP Error: 53 (Unwilling to perform)
689 if (isset($info['unicodePwd'])) {
690 $info['unicodePwd'] = mb_convert_encoding("\"".$info['unicodePwd']."\"", "UTF-16LE", "UTF-8");
691 }
692 }
693 $result = @ldap_mod_replace($this->connection, $dn, $info);
694
695 if ($result) {
696 dol_syslog(get_class($this)."::modify successful", LOG_DEBUG);
697 return 1;
698 } else {
699 $this->error = @ldap_error($this->connection);
700 dol_syslog(get_class($this)."::modify failed: ".$this->error, LOG_ERR);
701 return -1;
702 }
703 }
704
716 public function rename($dn, $newrdn, $newparent, $user, $deleteoldrdn = true)
717 {
718 dol_syslog(get_class($this)."::modify dn=".$dn." newrdn=".$newrdn." newparent=".$newparent." deleteoldrdn=".($deleteoldrdn ? 1 : 0));
719
720 // Check parameters
721 if (!$this->connection) {
722 $this->error = "NotConnected";
723 return -2;
724 }
725 if (!$this->bind) {
726 $this->error = "NotConnected";
727 return -3;
728 }
729
730 // Encode to LDAP page code
731 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
732 $newrdn = $this->convFromOutputCharset($newrdn, $this->ldapcharset);
733 $newparent = $this->convFromOutputCharset($newparent, $this->ldapcharset);
734
735 //print_r($info);
736 $result = @ldap_rename($this->connection, $dn, $newrdn, $newparent, $deleteoldrdn);
737
738 if ($result) {
739 dol_syslog(get_class($this)."::rename successful", LOG_DEBUG);
740 return 1;
741 } else {
742 $this->error = @ldap_error($this->connection);
743 dol_syslog(get_class($this)."::rename failed: ".$this->error, LOG_ERR);
744 return -1;
745 }
746 }
747
760 public function update($dn, $info, $user, $olddn, $newrdn = '', $newparent = '')
761 {
762 dol_syslog(get_class($this)."::update dn=".$dn." olddn=".$olddn);
763
764 // Check parameters
765 if (!$this->connection) {
766 $this->error = "NotConnected";
767 return -2;
768 }
769 if (!$this->bind) {
770 $this->error = "NotConnected";
771 return -3;
772 }
773
774 if (!$olddn || $olddn != $dn) {
775 if (!empty($olddn) && !empty($newrdn) && !empty($newparent) && $this->ldapProtocolVersion === '3') {
776 // This function currently only works with LDAPv3
777 $result = $this->rename($olddn, $newrdn, $newparent, $user, true);
778 $result = $this->modify($dn, $info, $user); // We force "modify" for avoid some fields not modify
779 } else {
780 // If change we make is rename the key of LDAP record, we create new one and if ok, we delete old one.
781 $result = $this->add($dn, $info, $user);
782 if ($result > 0 && $olddn && $olddn != $dn) {
783 $result = $this->delete($olddn); // If add fails, we do not try to delete old one
784 }
785 }
786 } else {
787 //$result = $this->delete($olddn);
788 $result = $this->add($dn, $info, $user); // If record has been deleted from LDAP, we recreate it. We ignore error if it already exists.
789 $result = $this->modify($dn, $info, $user); // We use add/modify instead of delete/add when olddn is received
790 }
791 if ($result <= 0) {
792 $this->error = ldap_error($this->connection).' (Code '.ldap_errno($this->connection).") ".$this->error;
793 dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
794 //print_r($info);
795 return -1;
796 } else {
797 dol_syslog(get_class($this)."::update done successfully");
798 return 1;
799 }
800 }
801
802
810 public function delete($dn)
811 {
812 dol_syslog(get_class($this)."::delete Delete LDAP entry dn=".$dn);
813
814 // Check parameters
815 if (!$this->connection) {
816 $this->error = "NotConnected";
817 return -2;
818 }
819 if (!$this->bind) {
820 $this->error = "NotConnected";
821 return -3;
822 }
823
824 // Encode to LDAP page code
825 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
826
827 $result = @ldap_delete($this->connection, $dn);
828
829 if ($result) {
830 return 1;
831 }
832 return -1;
833 }
834
842 public function dumpContent($dn, $info)
843 {
844 $content = '';
845
846 // Create file content
847 if (preg_match('/^ldap/', $this->server[0])) {
848 $target = "-H ".implode(',', $this->server);
849 } else {
850 $target = "-h ".implode(',', $this->server)." -p ".$this->serverPort;
851 }
852 $content .= "# ldapadd $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
853 $content .= "# ldapmodify $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
854 $content .= "# ldapdelete $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
855 if (in_array('localhost', $this->server)) {
856 $content .= "# If commands fails to connect, try without -h and -p\n";
857 }
858 $content .= "dn: ".$dn."\n";
859 foreach ($info as $key => $value) {
860 if (!is_array($value)) {
861 $content .= "$key: $value\n";
862 } else {
863 foreach ($value as $valuevalue) {
864 $content .= "$key: $valuevalue\n";
865 }
866 }
867 }
868 return $content;
869 }
870
878 public function dump($dn, $info)
879 {
880 global $conf;
881 $ldapDirTemp = $conf->ldap->dir_temp;
882 // Create content
883 $content = $this->dumpContent($dn, $info);
884
885 //Create directory & file
886 $result = dol_mkdir($ldapDirTemp);
887 if ($result != 0) {
888 $outputfile = $ldapDirTemp.'/ldapinput.in';
889 $fp = fopen($outputfile, "w");
890 if ($fp) {
891 fwrite($fp, $content);
892 fclose($fp);
893 dolChmod($outputfile);
894 return 1;
895 } else {
896 return -1;
897 }
898 } else {
899 return -1;
900 }
901 }
902
911 public function serverPing($host, $port = 389, $timeout = 1)
912 {
913 $regs = array();
914 if (preg_match('/^ldaps:\/\/([^\/]+)\/?$/', $host, $regs)) {
915 // Replace ldaps:// by ssl://
916 $host = 'ssl://'.$regs[1];
917 } elseif (preg_match('/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) {
918 // Remove ldap://
919 $host = $regs[1];
920 }
921
922 //var_dump($newhostforstream); var_dump($host); var_dump($port);
923 //$host = 'ssl://ldap.test.local:636';
924 //$port = 636;
925
926 $errno = $errstr = 0;
927 /*
928 if ($methodtochecktcpconnect == 'socket') {
929 Try to use socket_create() method.
930 Method that use stream_context_create() works only on registered listed in stream stream_get_wrappers(): http, https, ftp, ...
931 }
932 */
933
934 // Use the method fsockopen to test tcp connect. No way to ignore ssl certificate errors with this method !
935 $op = @fsockopen($host, $port, $errno, $errstr, $timeout);
936
937 //var_dump($op);
938 if (!$op) {
939 return false; //DC is N/A
940 } else {
941 fclose($op); //explicitly close open socket connection
942 return true; //DC is up & running, we can safely connect with ldap_connect
943 }
944 }
945
946
947 // Attribute methods -----------------------------------------------------
948
958 public function addAttribute($dn, $info, $user)
959 {
960 dol_syslog(get_class($this)."::addAttribute dn=".$dn." info=".implode(',', $info));
961
962 // Check parameters
963 if (!$this->connection) {
964 $this->error = "NotConnected";
965 return -2;
966 }
967 if (!$this->bind) {
968 $this->error = "NotConnected";
969 return -3;
970 }
971
972 // Encode to LDAP page code
973 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
974 foreach ($info as $key => $val) {
975 if (!is_array($val)) {
976 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
977 }
978 }
979
980 $this->dump($dn, $info);
981
982 //print_r($info);
983 $result = @ldap_mod_add($this->connection, $dn, $info);
984
985 if ($result) {
986 dol_syslog(get_class($this)."::add_attribute successful", LOG_DEBUG);
987 return 1;
988 } else {
989 $this->error = @ldap_error($this->connection);
990 dol_syslog(get_class($this)."::add_attribute failed: ".$this->error, LOG_ERR);
991 return -1;
992 }
993 }
994
1004 public function updateAttribute($dn, $info, $user)
1005 {
1006 dol_syslog(get_class($this)."::updateAttribute dn=".$dn." info=".implode(',', $info));
1007
1008 // Check parameters
1009 if (!$this->connection) {
1010 $this->error = "NotConnected";
1011 return -2;
1012 }
1013 if (!$this->bind) {
1014 $this->error = "NotConnected";
1015 return -3;
1016 }
1017
1018 // Encode to LDAP page code
1019 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
1020 foreach ($info as $key => $val) {
1021 if (!is_array($val)) {
1022 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
1023 }
1024 }
1025
1026 $this->dump($dn, $info);
1027
1028 //print_r($info);
1029 $result = @ldap_mod_replace($this->connection, $dn, $info);
1030
1031 if ($result) {
1032 dol_syslog(get_class($this)."::updateAttribute successful", LOG_DEBUG);
1033 return 1;
1034 } else {
1035 $this->error = @ldap_error($this->connection);
1036 dol_syslog(get_class($this)."::updateAttribute failed: ".$this->error, LOG_ERR);
1037 return -1;
1038 }
1039 }
1040
1050 public function deleteAttribute($dn, $info, $user)
1051 {
1052 dol_syslog(get_class($this)."::deleteAttribute dn=".$dn." info=".implode(',', $info));
1053
1054 // Check parameters
1055 if (!$this->connection) {
1056 $this->error = "NotConnected";
1057 return -2;
1058 }
1059 if (!$this->bind) {
1060 $this->error = "NotConnected";
1061 return -3;
1062 }
1063
1064 // Encode to LDAP page code
1065 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
1066 foreach ($info as $key => $val) {
1067 if (!is_array($val)) {
1068 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
1069 }
1070 }
1071
1072 $this->dump($dn, $info);
1073
1074 //print_r($info);
1075 $result = @ldap_mod_del($this->connection, $dn, $info);
1076
1077 if ($result) {
1078 dol_syslog(get_class($this)."::deleteAttribute successful", LOG_DEBUG);
1079 return 1;
1080 } else {
1081 $this->error = @ldap_error($this->connection);
1082 dol_syslog(get_class($this)."::deleteAttribute failed: ".$this->error, LOG_ERR);
1083 return -1;
1084 }
1085 }
1086
1096 public function getAttribute($dn, $filter)
1097 {
1098 // Check parameters
1099 if (!$this->connection) {
1100 $this->error = "NotConnected";
1101 return -2;
1102 }
1103 if (!$this->bind) {
1104 $this->error = "NotConnected";
1105 return -3;
1106 }
1107
1108 // Honor the admin-configured user search filter (LDAP_FILTER_CONNECTION)
1109 // so an identifier match outside the configured scope does not leak
1110 // attributes for an unrelated LDAP user (see #37120).
1111 if (!empty($this->filter) && !preg_match('/^\s*\‍(\s*&\s*\‍(/', $filter)) {
1112 $filter = '(&(' . $this->filter . ')' . $filter . ')';
1113 }
1114
1115 $search = @ldap_search($this->connection, $dn, $filter);
1116
1117 // Only one entry should ever be returned
1118 $entry = @ldap_first_entry($this->connection, $search);
1119
1120 if (!$entry) {
1121 $this->ldapErrorCode = -1;
1122 $this->ldapErrorText = "Couldn't find entry";
1123 return 0; // Couldn't find entry...
1124 }
1125
1126 // Get values
1127 if (!($values = ldap_get_attributes($this->connection, $entry))) {
1128 $this->ldapErrorCode = ldap_errno($this->connection);
1129 $this->ldapErrorText = ldap_error($this->connection);
1130 return 0; // No matching attributes
1131 }
1132
1133 // Return an array containing the attributes.
1134 return $values;
1135 }
1136
1144 public function getAttributeValues($filterrecord, $attribute)
1145 {
1146 $attributes = array();
1147 $attributes[0] = $attribute;
1148
1149 // We need to search for this user in order to get their entry.
1150 $this->result = @ldap_search($this->connection, $this->people, $filterrecord, $attributes);
1151
1152 // What is this line for ?
1153 //$info = ldap_get_entries($this->connection, $this->result);
1154
1155 // Only one entry should ever be returned (no user will have the same uid)
1156 $entry = ldap_first_entry($this->connection, $this->result);
1157
1158 if (!$entry) {
1159 $this->ldapErrorCode = -1;
1160 $this->ldapErrorText = "Couldn't find user";
1161 return false; // Couldn't find the user...
1162 }
1163
1164 // Get values
1165 if (!$values = @ldap_get_values_len($this->connection, $entry, $attribute)) {
1166 $this->ldapErrorCode = ldap_errno($this->connection);
1167 $this->ldapErrorText = ldap_error($this->connection);
1168 return false; // No matching attributes
1169 }
1170
1171 // Return an array containing the attributes.
1172 return $values;
1173 }
1174
1187 public function getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter = 0, $attributeAsArray = array())
1188 {
1189 $fulllist = array();
1190
1191 dol_syslog(get_class($this)."::getRecords search=".$search." userDn=".$userDn." useridentifier=".$useridentifier." attributeArray=array(".implode(',', $attributeArray).") activefilter=".$activefilter);
1192
1193 // if the directory is AD, then bind first with the search user first
1194 if ($this->serverType == "activedirectory") {
1195 $this->bindauth($this->searchUser, $this->searchPassword);
1196 dol_syslog(get_class($this)."::bindauth serverType=activedirectory searchUser=".$this->searchUser);
1197 }
1198
1199 // Define filter
1200 if (!empty($activefilter)) { // Use a predefined trusted filter (defined into setup by admin).
1201 if (((string) $activefilter == '1' || (string) $activefilter == 'user') && $this->filter) {
1202 $filter = '('.$this->filter.')';
1203 } elseif (((string) $activefilter == 'group') && $this->filtergroup) {
1204 $filter = '('.$this->filtergroup.')';
1205 } elseif (((string) $activefilter == 'member') && $this->filter) {
1206 $filter = '('.$this->filtermember.')';
1207 } else {
1208 // If this->filter/this->filtergroup is empty, make filter on * (all)
1209 $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'=*)';
1210 }
1211 } else { // Use a filter forged using the $search value
1212 $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'='.ldap_escape($search, '', LDAP_ESCAPE_FILTER).')';
1213 }
1214
1215 if (is_array($attributeArray)) {
1216 // Return list with required fields
1217 $attributeArray = array_values($attributeArray); // This is to force to have index reordered from 0 (not make ldap_search fails)
1218 dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter." attributeArray=(".implode(',', $attributeArray).")");
1219 //var_dump($attributeArray);
1220 $this->result = @ldap_search($this->connection, $userDn, $filter, $attributeArray);
1221 } else {
1222 // Return list with fields selected by default
1223 dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter);
1224 $this->result = @ldap_search($this->connection, $userDn, $filter);
1225 }
1226 if (!$this->result) {
1227 $this->error = 'LDAP search failed: '.ldap_errno($this->connection)." ".ldap_error($this->connection);
1228 return -1;
1229 }
1230
1231 $info = @ldap_get_entries($this->connection, $this->result);
1232
1233 // Warning: Dans info, les noms d'attributs sont en minuscule meme si passe
1234 // a ldap_search en majuscule !!!
1235 //print_r($info);
1236
1237 for ($i = 0; $i < $info["count"]; $i++) {
1238 $recordid = $this->convToOutputCharset($info[$i][strtolower($useridentifier)][0], $this->ldapcharset);
1239 if ($recordid) {
1240 //print "Found record with key $useridentifier=".$recordid."<br>\n";
1241 $fulllist[$recordid][$useridentifier] = $recordid;
1242
1243 // Add to the array for each attribute in my list
1244 $num = count($attributeArray);
1245 for ($j = 0; $j < $num; $j++) {
1246 $keyattributelower = strtolower($attributeArray[$j]);
1247 //print " Param ".$attributeArray[$j]."=".$info[$i][$keyattributelower][0]."<br>\n";
1248
1249 // Enables getting the SID using Active Directory
1250 if ($this->serverType == "activedirectory" && $keyattributelower == "objectsid") {
1251 $objectsid = $this->getObjectSid($recordid);
1252 $fulllist[$recordid][$attributeArray[$j]] = $objectsid;
1253 } else {
1254 if (in_array($attributeArray[$j], $attributeAsArray) && is_array($info[$i][$keyattributelower])) {
1255 $valueTab = array();
1256 foreach ($info[$i][$keyattributelower] as $key => $value) {
1257 $valueTab[$key] = $this->convToOutputCharset($value, $this->ldapcharset);
1258 }
1259 $fulllist[$recordid][$attributeArray[$j]] = $valueTab;
1260 } else {
1261 $fulllist[$recordid][$attributeArray[$j]] = $this->convToOutputCharset($info[$i][$keyattributelower][0], $this->ldapcharset);
1262 }
1263 }
1264 }
1265 }
1266 }
1267
1268 asort($fulllist);
1269 return $fulllist;
1270 }
1271
1279 public function littleEndian($hex)
1280 {
1281 $result = '';
1282 for ($x = dol_strlen($hex) - 2; $x >= 0; $x -= 2) {
1283 $result .= substr($hex, $x, 2);
1284 }
1285 return $result;
1286 }
1287
1288
1296 public function getObjectSid($ldapUser)
1297 {
1298 $criteria = '('.$this->getUserIdentifier().'='.$ldapUser.')';
1299 $justthese = array("objectsid");
1300
1301 // if the directory is AD, then bind first with the search user first
1302 if ($this->serverType == "activedirectory") {
1303 $this->bindauth($this->searchUser, $this->searchPassword);
1304 }
1305
1306 $i = 0;
1307 $entry = null;
1308 $searchDN = $this->people;
1309
1310 while ($i <= 2) {
1311 $ldapSearchResult = @ldap_search($this->connection, $searchDN, $criteria, $justthese);
1312
1313 if (!$ldapSearchResult) {
1314 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1315 return -1;
1316 }
1317
1318 $entry = ldap_first_entry($this->connection, $ldapSearchResult);
1319
1320 if (!$entry) {
1321 // Si pas de resultat on cherche dans le domaine
1322 $searchDN = $this->domain;
1323 $i++;
1324 } else {
1325 $i++;
1326 $i++;
1327 }
1328 }
1329
1330 if ($entry) {
1331 $ldapBinary = ldap_get_values_len($this->connection, $entry, "objectsid");
1332 $SIDText = $this->binSIDtoText($ldapBinary[0]);
1333 return $SIDText;
1334 } else {
1335 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1336 return -1;
1337 }
1338 }
1339
1347 public function binSIDtoText($binsid)
1348 {
1349 $hex_sid = bin2hex($binsid);
1350 $rev = hexdec(substr($hex_sid, 0, 2)); // Get revision-part of SID
1351 $subcount = hexdec(substr($hex_sid, 2, 2)); // Get count of sub-auth entries
1352 $auth = hexdec(substr($hex_sid, 4, 12)); // SECURITY_NT_AUTHORITY
1353 $result = "$rev-$auth";
1354 for ($x = 0; $x < $subcount; $x++) {
1355 $result .= "-".hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); // get all SECURITY_NT_AUTHORITY
1356 }
1357 return $result;
1358 }
1359
1360
1374 public function search($checkDn, $filter)
1375 {
1376 dol_syslog(get_class($this)."::search checkDn=".$checkDn." filter=".$filter);
1377
1378 $checkDn = $this->convFromOutputCharset($checkDn, $this->ldapcharset);
1379 $filter = $this->convFromOutputCharset($filter, $this->ldapcharset);
1380
1381 // if the directory is AD, then bind first with the search user first
1382 if ($this->serverType == "activedirectory") {
1383 $this->bindauth($this->searchUser, $this->searchPassword);
1384 }
1385
1386 $this->result = @ldap_search($this->connection, $checkDn, $filter);
1387
1388 $result = @ldap_get_entries($this->connection, $this->result);
1389 if (!$result) {
1390 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1391 return -1;
1392 } else {
1393 ldap_free_result($this->result);
1394 return $result;
1395 }
1396 }
1397
1398
1407 public function fetch($user, $filter)
1408 {
1409 // Perform the search and get the entry handles
1410
1411 // if the directory is AD, then bind first with the search user first
1412 if ($this->serverType == "activedirectory") {
1413 $this->bindauth($this->searchUser, $this->searchPassword);
1414 }
1415
1416 $searchDN = $this->people; // TODO Why searching in people then domain ?
1417
1418 $result = '';
1419 $i = 0;
1420 while ($i <= 2) {
1421 dol_syslog(get_class($this)."::fetch search with searchDN=".$searchDN." filter=".$filter);
1422 $this->result = @ldap_search($this->connection, $searchDN, $filter);
1423 if ($this->result) {
1424 $result = @ldap_get_entries($this->connection, $this->result);
1425 if ($result['count'] > 0) {
1426 dol_syslog('Ldap::fetch search found '.$result['count'].' records');
1427 } else {
1428 dol_syslog('Ldap::fetch search returns but found no records');
1429 }
1430 //var_dump($result);exit;
1431 } else {
1432 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1433 dol_syslog(get_class($this)."::fetch search fails");
1434 return -1;
1435 }
1436
1437 if (!$result) {
1438 // Si pas de resultat on cherche dans le domaine
1439 $searchDN = $this->domain;
1440 $i++;
1441 } else {
1442 break;
1443 }
1444 }
1445
1446 if (!$result) {
1447 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1448 return -1;
1449 } else {
1450 $this->name = $this->convToOutputCharset($result[0][$this->attr_name][0], $this->ldapcharset);
1451 $this->firstname = $this->convToOutputCharset($result[0][$this->attr_firstname][0], $this->ldapcharset);
1452 $this->login = $this->convToOutputCharset($result[0][$this->attr_login][0], $this->ldapcharset);
1453 $this->phone = $this->convToOutputCharset($result[0][$this->attr_phone][0], $this->ldapcharset);
1454 $this->fax = $this->convToOutputCharset($result[0][$this->attr_fax][0], $this->ldapcharset);
1455 $this->mail = $this->convToOutputCharset($result[0][$this->attr_mail][0], $this->ldapcharset);
1456 $this->mobile = $this->convToOutputCharset($result[0][$this->attr_mobile][0], $this->ldapcharset);
1457
1458 $this->uacf = $this->parseUACF($this->convToOutputCharset($result[0]["useraccountcontrol"][0], $this->ldapcharset));
1459 if (isset($result[0]["pwdlastset"][0])) { // If expiration on password exists
1460 $this->pwdlastset = ($result[0]["pwdlastset"][0] != 0) ? $this->convertTime($this->convToOutputCharset($result[0]["pwdlastset"][0], $this->ldapcharset)) : 0;
1461 } else {
1462 $this->pwdlastset = -1;
1463 }
1464 if (!$this->name && !$this->login) {
1465 $this->pwdlastset = -1;
1466 }
1467 $this->badpwdtime = $this->convertTime($this->convToOutputCharset($result[0]["badpasswordtime"][0], $this->ldapcharset));
1468
1469 // FQDN domain
1470 $domain = str_replace('dc=', '', $this->domain);
1471 $domain = str_replace(',', '.', $domain);
1472 $this->domainFQDN = $domain;
1473
1474 // Set ldapUserDn (each user can have a different dn)
1475 //var_dump($result[0]);exit;
1476 $this->ldapUserDN = $result[0]['dn'];
1477
1478 ldap_free_result($this->result);
1479 return 1;
1480 }
1481 }
1482
1483
1484 // helper methods
1485
1491 public function getUserIdentifier()
1492 {
1493 if ($this->serverType == "activedirectory") {
1494 return $this->attr_sambalogin;
1495 } else {
1496 return $this->attr_login;
1497 }
1498 }
1499
1506 public function parseUACF($uacf)
1507 {
1508 //All flags array
1509 $flags = array(
1510 "TRUSTED_TO_AUTH_FOR_DELEGATION" => 16777216,
1511 "PASSWORD_EXPIRED" => 8388608,
1512 "DONT_REQ_PREAUTH" => 4194304,
1513 "USE_DES_KEY_ONLY" => 2097152,
1514 "NOT_DELEGATED" => 1048576,
1515 "TRUSTED_FOR_DELEGATION" => 524288,
1516 "SMARTCARD_REQUIRED" => 262144,
1517 "MNS_LOGON_ACCOUNT" => 131072,
1518 "DONT_EXPIRE_PASSWORD" => 65536,
1519 "SERVER_TRUST_ACCOUNT" => 8192,
1520 "WORKSTATION_TRUST_ACCOUNT" => 4096,
1521 "INTERDOMAIN_TRUST_ACCOUNT" => 2048,
1522 "NORMAL_ACCOUNT" => 512,
1523 "TEMP_DUPLICATE_ACCOUNT" => 256,
1524 "ENCRYPTED_TEXT_PWD_ALLOWED" => 128,
1525 "PASSWD_CANT_CHANGE" => 64,
1526 "PASSWD_NOTREQD" => 32,
1527 "LOCKOUT" => 16,
1528 "HOMEDIR_REQUIRED" => 8,
1529 "ACCOUNTDISABLE" => 2,
1530 "SCRIPT" => 1
1531 );
1532
1533 //Parse flags to text
1534 $retval = array();
1535 //while (list($flag, $val) = each($flags)) {
1536 foreach ($flags as $flag => $val) {
1537 if ($uacf >= $val) {
1538 $uacf -= $val;
1539 $retval[$val] = $flag;
1540 }
1541 }
1542
1543 //Return human friendly flags
1544 return $retval;
1545 }
1546
1553 public function parseSAT($samtype)
1554 {
1555 $stypes = array(
1556 805306368 => "NORMAL_ACCOUNT",
1557 805306369 => "WORKSTATION_TRUST",
1558 805306370 => "INTERDOMAIN_TRUST",
1559 268435456 => "SECURITY_GLOBAL_GROUP",
1560 268435457 => "DISTRIBUTION_GROUP",
1561 536870912 => "SECURITY_LOCAL_GROUP",
1562 536870913 => "DISTRIBUTION_LOCAL_GROUP"
1563 );
1564
1565 $retval = "";
1566 foreach ($stypes as $sat => $val) {
1567 if ($samtype == $sat) {
1568 $retval = $val;
1569 break;
1570 }
1571 }
1572 if (empty($retval)) {
1573 $retval = "UNKNOWN_TYPE_".$samtype;
1574 }
1575
1576 return $retval;
1577 }
1578
1585 public function convertTime($value)
1586 {
1587 $dateLargeInt = $value; // nano secondes since the year 1601 !!!!
1588 if (PHP_INT_SIZE < 8) {
1589 // 32 bit platform
1590 $secsAfterADEpoch = (float) $dateLargeInt / (10000000.); // seconds since 1 jan 1601
1591 } else {
1592 // At least 64 bit platform
1593 $secsAfterADEpoch = (int) $dateLargeInt / (10000000); // seconds since 1 jan 1601
1594 }
1595 $ADToUnixConvertor = ((1970 - 1601) * 365.242190) * 86400; // UNIX start date - AD start date * days * seconds
1596 $unixTimeStamp = intval($secsAfterADEpoch - $ADToUnixConvertor); // Unix time stamp
1597 return $unixTimeStamp;
1598 }
1599
1600
1608 private function convToOutputCharset($str, $pagecodefrom = 'UTF-8')
1609 {
1610 global $conf;
1611 if ($pagecodefrom == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1612 $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');
1613 }
1614 if ($pagecodefrom == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1615 $str = mb_convert_encoding($str, 'ISO-8859-1');
1616 }
1617 return $str;
1618 }
1619
1627 public function convFromOutputCharset($str, $pagecodeto = 'UTF-8')
1628 {
1629 global $conf;
1630 if ($pagecodeto == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1631 $str = mb_convert_encoding($str, 'ISO-8859-1');
1632 }
1633 if ($pagecodeto == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1634 $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');
1635 }
1636 return $str;
1637 }
1638
1639
1646 public function getNextGroupGid($keygroup = 'LDAP_KEY_GROUPS')
1647 {
1648
1649 if (empty($keygroup)) {
1650 $keygroup = 'LDAP_KEY_GROUPS';
1651 }
1652
1653 $search = '(' . getDolGlobalString($keygroup).'=*)';
1654 $result = $this->search($this->groups, $search);
1655 if ($result) {
1656 $c = $result['count'];
1657 $gids = array();
1658 for ($i = 0; $i < $c; $i++) {
1659 $gids[] = (int) $result[$i]['gidnumber'][0];
1660 }
1661 rsort($gids);
1662
1663 return $gids[0] + 1;
1664 }
1665
1666 return 0;
1667 }
1668}
$c
Definition line.php:334
Class to manage LDAP features.
add($dn, $info, $user)
Add an LDAP entry LDAP object connect and bind must have been done.
convertTime($value)
Converts ActiveDirectory time to Unix timestamp.
modify($dn, $info, $user)
Modify an LDAP entry LDAP object connect and bind must have been done.
deleteAttribute($dn, $info, $user)
Delete an LDAP attribute in entry LDAP object connect and bind must have been done.
setVersion()
Set LDAP protocol version.
convToOutputCharset($str, $pagecodefrom='UTF-8')
Convert a string into output/memory charset.
littleEndian($hex)
Converts a little-endian hex-number to one, that 'hexdec' can convert Required by Active Directory.
fetch($user, $filter)
Load all attributes of an LDAP user.
update($dn, $info, $user, $olddn, $newrdn='', $newparent='')
Modify an LDAP entry (to use if dn != olddn) LDAP object connect and bind must have been done.
getObjectSid($ldapUser)
Gets LDAP user SID.
updateAttribute($dn, $info, $user)
Update an LDAP attribute in entry LDAP object connect and bind must have been done.
getUserIdentifier()
Returns the correct user identifier to use, based on the LDAP server type.
getAttribute($dn, $filter)
Returns an array containing attributes and values for first record.
close()
Simply closes the connection set up earlier.
parseSAT($samtype)
SamAccountType value to text.
rename($dn, $newrdn, $newparent, $user, $deleteoldrdn=true)
Rename an LDAP entry LDAP object connect and bind must have been done.
getNextGroupGid($keygroup='LDAP_KEY_GROUPS')
Return available value of group GID.
setSizeLimit()
Set LDAP size limit.
binSIDtoText($binsid)
Returns the textual SID Required by Active Directory.
connectBind()
Connect and bind Use this->server, this->serverPort, this->ldapProtocolVersion, this->serverType,...
setReferrals()
Set LDAP referrals.
search($checkDn, $filter)
Search method with filter this->connection must be defined.
getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter=0, $attributeAsArray=array())
Returns an array containing a details or list of LDAP record(s).
getVersion()
Verify LDAP server version.
dumpContent($dn, $info)
Build an LDAP message.
getAttributeValues($filterrecord, $attribute)
Returns an array containing values for an attribute and for first record matching filterrecord.
parseUACF($uacf)
UserAccountControl Flags to more human understandable form...
__construct()
Constructor.
convFromOutputCharset($str, $pagecodeto='UTF-8')
Convert a string from output/memory charset.
serverPing($host, $port=389, $timeout=1)
Ping a server before ldap_connect for avoid waiting.
bind()
Anonymously binds to the connection.
unbind()
Unbind of LDAP server (close connection).
bindauth($bindDn, $pass)
Binds as an authenticated user, which usually allows for write access.
dump($dn, $info)
Dump an LDAP message to ldapinput.in file.
addAttribute($dn, $info, $user)
Add an LDAP attribute in entry LDAP object connect and bind must have been done.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133