From 12e6c16a2dbeaf374614ea4f99fc610ce813e7a1 Mon Sep 17 00:00:00 2001
From: Thibault Dockx <thibault.dockx@fusiondirectory.org>
Date: Tue, 4 Mar 2025 16:23:00 +0000
Subject: [PATCH] :sparkles: (ldap) - basic ldap class

Basic ldap class with error suppression allowed.
---
 include/class_ldap.inc | 104 ++++++++++++-----------------------------
 1 file changed, 29 insertions(+), 75 deletions(-)

diff --git a/include/class_ldap.inc b/include/class_ldap.inc
index 8fab363eb..a86fe3825 100755
--- a/include/class_ldap.inc
+++ b/include/class_ldap.inc
@@ -129,8 +129,8 @@ class LDAP
     global $config;
 
     $ldap = new LDAP($binddn, $pass, $server,
-        isset($config->current['LDAPFOLLOWREFERRALS']) && $config->current['LDAPFOLLOWREFERRALS'] == 'TRUE',
-        isset($config->current['LDAPTLS']) && $config->current['LDAPTLS'] == 'TRUE');
+      isset($config->current['LDAPFOLLOWREFERRALS']) && $config->current['LDAPFOLLOWREFERRALS'] == 'TRUE',
+      isset($config->current['LDAPTLS']) && $config->current['LDAPTLS'] == 'TRUE');
 
     /* Sadly we've no proper return values here. Use the error message instead. */
     if (!$ldap->success()) {
@@ -327,7 +327,7 @@ class LDAP
    *
    * \param string $scope Scope of the search: subtree/base/one
    */
-  function search($srp, $filter, $attrs = [], $scope = 'subtree', array $controls = NULL)
+  function search ($srp, $filter, $attrs = [], $scope = 'subtree', array $controls = NULL)
   {
     if ($this->hascon) {
       if ($this->reconnect) {
@@ -336,68 +336,51 @@ class LDAP
 
       $startTime = microtime(TRUE);
       $this->clearResult($srp);
-
-      switch (strtolower((string)$scope)) {
+      switch (strtolower((string) $scope)) {
         case 'base':
           if (isset($controls)) {
-            $this->sr[$srp] = ldap_read($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
+            $this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
           } else {
-            $this->sr[$srp] = ldap_read($this->cid, $this->basedn, $filter, $attrs);
+            $this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs);
           }
           break;
-
         case 'one':
           if (isset($controls)) {
-            $this->sr[$srp] = ldap_list($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
+            $this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
           } else {
-            $this->sr[$srp] = ldap_list($this->cid, $this->basedn, $filter, $attrs);
+            $this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs);
           }
           break;
-
         case 'subtree':
         default:
           if (isset($controls)) {
-            $this->sr[$srp] = ldap_search($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
+            $this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
           } else {
-            $this->sr[$srp] = ldap_search($this->cid, $this->basedn, $filter, $attrs);
+            $this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs);
           }
           break;
       }
-
-      // Check if the LDAP operation was successful
-      if ($this->sr[$srp] === false) {
-        // If it failed, log the error and handle it properly
-        $this->error = ldap_error($this->cid);
-        logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'LDAP search error');
-        $this->resetResult($srp);
-        $this->hasres[$srp] = FALSE; // Indicate that there was no result
-        return false; // Return false to indicate the search failed
-      }
-
+      $this->error = @ldap_error($this->cid);
       $this->resetResult($srp);
       $this->hasres[$srp] = TRUE;
 
-      // Check if query took longer than specified in max_ldap_query_time
+      /* Check if query took longer as specified in max_ldap_query_time */
       $diff = microtime(TRUE) - $startTime;
       if ($this->max_ldap_query_time && ($diff > $this->max_ldap_query_time)) {
         $warning = new FusionDirectoryWarning(htmlescape(sprintf(_('LDAP performance is poor: last query took about %.2fs!'), $diff)));
         $warning->display();
       }
 
-      // Log the LDAP operation
       $this->log("LDAP operation: time=".$diff." operation=search('".$this->basedn."', '$filter')");
       logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'search(base="'.$this->basedn.'",scope="'.$scope.'",filter="'.$filter.'")');
-
       return $this->sr[$srp];
     } else {
-      // Handle case where the connection is not established
       $this->error = "Could not connect to LDAP server";
       logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'search(base="'.$this->basedn.'",scope="'.$scope.'",filter="'.$filter.'")');
-      return false;
+      return "";
     }
   }
 
-
   /*!
    * \brief Parse last result
    *
@@ -445,53 +428,24 @@ class LDAP
    *
    * \param string $filter Initialized at "(objectclass=*)"
    */
-  function cat($srp, $dn, $attrs = ["*"], $filter = "(objectclass=*)") {
+  function cat ($srp, $dn, $attrs = ["*"], $filter = "(objectclass=*)")
+  {
     if ($this->hascon) {
       if ($this->reconnect) {
         $this->connect();
       }
 
       $this->clearResult($srp);
-
-      // Use @ to suppress any warnings or errors from ldap_read
       $this->sr[$srp] = @ldap_read($this->cid, $dn, $filter, $attrs);
-
-      // Check if ldap_read() failed, but do not log as an error if the DN is missing
-      if ($this->sr[$srp] === false) {
-        // Get the LDAP error message
-        $this->error = ldap_error($this->cid);
-
-        // Check if the error is "No such object", which means the DN does not exist
-        if (strpos($this->error, 'No such object') !== false) {
-          // Expected behavior: DN not found
-          logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
-            'No such object for dn="'.$dn.'" - Expected absence');
-          return null; // Return null to gracefully handle the expected absence of the DN
-        } else {
-          // If the error is not "No such object", log it as a real error
-          logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
-            'LDAP read failed for dn="'.$dn.'", filter="'.$filter.'" Error: '.$this->error);
-          return false; // Return false to indicate an unexpected error
-        }
-      }
-
-      // If no error, reset the result and mark as having results
-      $this->error = ldap_error($this->cid); // Capture any last error
+      $this->error    = @ldap_error($this->cid);
       $this->resetResult($srp);
-      $this->hasres[$srp] = true;
-
-      // Log the successful operation
-      logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, 'No error',
-        'cat(dn="'.$dn.'", filter="'.$filter.'")');
-
-      // Return the LDAP result
+      $this->hasres[$srp] = TRUE;
+      logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'cat(dn="'.$dn.'",filter="'.$filter.'")');
       return $this->sr[$srp];
     } else {
-      // Handle the case when there's no connection
       $this->error = "Could not connect to LDAP server";
-      logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error,
-        'cat(dn="'.$dn.'", filter="'.$filter.'")');
-      return false; // Return false instead of an empty string
+      logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'cat(dn="'.$dn.'",filter="'.$filter.'")');
+      return "";
     }
   }
 
@@ -839,7 +793,7 @@ class LDAP
 
     $str = "";
     if (isset($attrs['objectClass'])
-      && preg_match("/^objectClass: value #([0-9]*) invalid per syntax$/", (string) $this->get_additional_error(), $m)) {
+        && preg_match("/^objectClass: value #([0-9]*) invalid per syntax$/", (string) $this->get_additional_error(), $m)) {
       $ocs = $attrs['objectClass'];
       if (!is_array($ocs)) {
         $ocs = [$ocs];
@@ -978,7 +932,7 @@ class LDAP
       if (!$this->dn_exists($cdn)) {
         $type   = preg_replace('/^([^=]+)=.*$/', '\\1', (string) $cdn);
         $param  = preg_replace('/^[^=]+=([^,]+).*$/', '\\1', (string) $cdn);
-        $param  = preg_replace(['/\\\\,/','/\\\\"/'], [',','"'], (string) $param);
+        $param  = preg_replace(['/\\\\,/','/\\\\"/'], [',','"'], $param);
 
         $na = [];
 
@@ -1141,7 +1095,7 @@ class LDAP
   {
     $ret    = [];
     $url    = preg_replace('!\?\?.*$!', '', (string) $url);
-    $server = preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', (string) $url);
+    $server = preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
 
     if ($referrals === NULL) {
       $referrals = $this->referrals;
@@ -1253,7 +1207,7 @@ class LDAP
       } else {
         if ($line !== NULL) {
           if (preg_match('/^#/', $line)
-            || (preg_match('/^version:/', $line) && empty($entry))) {
+              || (preg_match('/^version:/', $line) && empty($entry))) {
             /* Ignore comment */
             /* Ignore version number */
           } else {
@@ -1533,13 +1487,13 @@ class LDAP
 
     /* Remove ' and " if needed */
     $value = preg_replace('/^[\'"]/', '', (string) $value);
-    $value = preg_replace('/[\'"] *$/', '', (string) $value);
+    $value = preg_replace('/[\'"] *$/', '', $value);
 
     /* Convert to array if $ is inside... */
-    if (preg_match('/\$/', (string) $value)) {
-      $container = preg_split('/\s*\$\s*/', (string) $value);
+    if (preg_match('/\$/', $value)) {
+      $container = preg_split('/\s*\$\s*/', $value);
     } else {
-      $container = rtrim((string) $value);
+      $container = rtrim($value);
     }
 
     return $container;
@@ -1597,4 +1551,4 @@ class LDAP
     logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $attrs[0]['namingcontexts'], 'get_naming_contexts');
     return $attrs[0]['namingcontexts'];
   }
-}
+}
\ No newline at end of file
-- 
GitLab