Esempio n. 1
0
 /**
  * Execute LDAP search
  *
  * @param string $base_dn    Base DN to use for searching
  * @param string $filter     Filter string to query
  * @param string $scope      The LDAP scope (list|sub|base)
  * @param array  $attrs      List of entry attributes to read
  * @param array  $prop       Hash array with query configuration properties:
  *   - sort:   array of sort attributes (has to be in sync with the VLV index)
  *   - search: search string used for VLV controls
  * @param bool   $count_only Set to true if only entry count is requested
  *
  * @return mixed Net_LDAP3_Result object or number of entries (if $count_only=true) or False on failure
  */
 public function search($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $attrs = array('dn'), $props = array(), $count_only = false)
 {
     if (!$this->conn) {
         $this->_debug("No active connection for " . __CLASS__ . "::" . __FUNCTION__);
         return false;
     }
     // make sure attributes list is not empty
     if (empty($attrs)) {
         $attrs = array('dn');
     }
     // make sure filter is not empty
     if (empty($filter)) {
         $filter = '(objectclass=*)';
     }
     $this->_debug("C: Search base dn: [{$base_dn}] scope [{$scope}] with filter [{$filter}]");
     $function = self::scope_to_function($scope, $ns_function);
     if (!$count_only && ($sort = $this->find_vlv($base_dn, $filter, $scope, $props['sort']))) {
         // when using VLV, we get the total count by...
         // ...either reading numSubOrdinates attribute
         if (($sub_filter = $this->config_get('numsub_filter')) && ($result_count = @$ns_function($this->conn, $base_dn, $sub_filter, array('numSubOrdinates'), 0, 0, 0))) {
             $counts = ldap_get_entries($this->conn, $result_count);
             for ($vlv_count = $j = 0; $j < $counts['count']; $j++) {
                 $vlv_count += $counts[$j]['numsubordinates'][0];
             }
             $this->_debug("D: total numsubordinates = " . $vlv_count);
         } else {
             if (!function_exists('ldap_parse_virtuallist_control')) {
                 // @FIXME: this search will ignore $props['search']
                 $vlv_count = $this->search($base_dn, $filter, $scope, array('dn'), $props, true);
             }
         }
         $this->vlv_active = $this->_vlv_set_controls($sort, $this->list_page, $this->page_size, $this->_vlv_search($sort, $props['search']));
     } else {
         $this->vlv_active = false;
     }
     $sizelimit = (int) $this->config['sizelimit'];
     $timelimit = (int) $this->config['timelimit'];
     $phplimit = (int) @ini_get('max_execution_time');
     // set LDAP time limit to be (one second) less than PHP time limit
     // otherwise we have no chance to log the error below
     if ($phplimit && $timelimit >= $phplimit) {
         $timelimit = $phplimit - 1;
     }
     $this->_debug("Using function {$function} on scope {$scope} (\$ns_function is {$ns_function})");
     if ($this->vlv_active) {
         if (!empty($this->additional_filter)) {
             $filter = "(&" . $filter . $this->additional_filter . ")";
             $this->_debug("C: (With VLV) Setting a filter (with additional filter) of " . $filter);
         } else {
             $this->_debug("C: (With VLV) Setting a filter (without additional filter) of " . $filter);
         }
     } else {
         if (!empty($this->additional_filter)) {
             $filter = "(&" . $filter . $this->additional_filter . ")";
         }
         $this->_debug("C: (Without VLV) Setting a filter of " . $filter);
     }
     $this->_debug("Executing search with return attributes: " . var_export($attrs, true));
     $ldap_result = @$function($this->conn, $base_dn, $filter, $attrs, 0, $sizelimit, $timelimit);
     if (!$ldap_result) {
         $this->_warning("LDAP: {$function} failed for dn={$base_dn}. " . ldap_error($this->conn));
         return false;
     }
     // when running on a patched PHP we can use the extended functions
     // to retrieve the total count from the LDAP search result
     if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) {
         if (ldap_parse_result($this->conn, $ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) {
             ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $vlv_count, $vresult);
             $this->_debug("S: VLV result: last_offset={$last_offset}; content_count={$vlv_count}");
         } else {
             $this->_debug("S: " . ($errmsg ? $errmsg : ldap_error($this->conn)));
         }
     } else {
         $this->_debug("S: " . ldap_count_entries($this->conn, $ldap_result) . " record(s) found");
     }
     $result = new Net_LDAP3_Result($this->conn, $base_dn, $filter, $scope, $ldap_result);
     if (isset($last_offset)) {
         $result->set('offset', $last_offset);
     }
     if (isset($vlv_count)) {
         $result->set('count', $vlv_count);
     }
     $result->set('vlv', $this->vlv_active);
     return $count_only ? $result->count() : $result;
 }
 /**
  * Execute the LDAP search based on the stored credentials
  */
 private function _exec_search($count = false)
 {
     if ($this->ready) {
         $filter = $this->filter ? $this->filter : '(objectclass=*)';
         $function = $this->_scope2func($this->prop['scope'], $ns_function);
         $this->_debug("C: Search [{$filter}][dn: {$this->base_dn}]");
         // when using VLV, we get the total count by...
         if (!$count && $function != 'ldap_read' && $this->prop['vlv'] && !$this->group_id) {
             // ...either reading numSubOrdinates attribute
             if ($this->prop['numsub_filter'] && ($result_count = @$ns_function($this->conn, $this->base_dn, $this->prop['numsub_filter'], array('numSubOrdinates'), 0, 0, 0))) {
                 $counts = ldap_get_entries($this->conn, $result_count);
                 for ($this->vlv_count = $j = 0; $j < $counts['count']; $j++) {
                     $this->vlv_count += $counts[$j]['numsubordinates'][0];
                 }
                 $this->_debug("D: total numsubordinates = " . $this->vlv_count);
             } else {
                 if (!function_exists('ldap_parse_virtuallist_control')) {
                     // ...or by fetching all records dn and count them
                     $this->vlv_count = $this->_exec_search(true);
                 }
             }
             $this->vlv_active = $this->_vlv_set_controls($this->prop, $this->list_page, $this->page_size);
         }
         // only fetch dn for count (should keep the payload low)
         $attrs = $count ? array('dn') : array_values($this->fieldmap);
         if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter, $attrs, 0, (int) $this->prop['sizelimit'], (int) $this->prop['timelimit'])) {
             // when running on a patched PHP we can use the extended functions to retrieve the total count from the LDAP search result
             if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) {
                 if (ldap_parse_result($this->conn, $this->ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) {
                     ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $this->vlv_count, $vresult);
                     $this->_debug("S: VLV result: last_offset={$last_offset}; content_count={$this->vlv_count}");
                 } else {
                     $this->_debug("S: " . ($errmsg ? $errmsg : ldap_error($this->conn)));
                 }
             }
             $entries_count = ldap_count_entries($this->conn, $this->ldap_result);
             $this->_debug("S: {$entries_count} record(s)");
             return $count ? $entries_count : true;
         } else {
             $this->_debug("S: " . ldap_error($this->conn));
         }
     }
     return false;
 }
 /**
  * Execute the LDAP search based on the stored credentials
  *
  * @param string $base_dn  The base DN to query
  * @param string $filter   The LDAP filter for search
  * @param string $scope    The LDAP scope (list|sub|base)
  * @param array  $attrs    List of entry attributes to read
  * @param array  $prop     Hash array with query configuration properties:
  *   - sort: array of sort attributes (has to be in sync with the VLV index)
  *   - search: search string used for VLV controls
  * @param boolean $count_only Set to true if only entry count is requested
  *
  * @return mixed  rcube_ldap_result object or number of entries (if count_only=true) or false on error
  */
 public function search($base_dn, $filter = '', $scope = 'sub', $attrs = array('dn'), $prop = array(), $count_only = false)
 {
     if (!$this->conn) {
         return false;
     }
     if (empty($filter)) {
         $filter = '(objectclass=*)';
     }
     $this->_debug("C: Search {$base_dn} for {$filter}");
     $function = self::scope2func($scope, $ns_function);
     // find available VLV index for this query
     if (!$count_only && ($vlv_sort = $this->_find_vlv($base_dn, $filter, $scope, $prop['sort']))) {
         // when using VLV, we get the total count by...
         // ...either reading numSubOrdinates attribute
         if (($sub_filter = $this->config['numsub_filter']) && ($result_count = @$ns_function($this->conn, $base_dn, $sub_filter, array('numSubOrdinates'), 0, 0, 0))) {
             $counts = ldap_get_entries($this->conn, $result_count);
             for ($vlv_count = $j = 0; $j < $counts['count']; $j++) {
                 $vlv_count += $counts[$j]['numsubordinates'][0];
             }
             $this->_debug("D: total numsubordinates = " . $vlv_count);
         } else {
             if (!function_exists('ldap_parse_virtuallist_control')) {
                 $vlv_count = $this->search($base_dn, $filter, $scope, array('dn'), $prop, true);
             }
         }
         $this->vlv_active = $this->_vlv_set_controls($vlv_sort, $this->list_page, $this->page_size, $prop['search']);
     } else {
         $this->vlv_active = false;
     }
     // only fetch dn for count (should keep the payload low)
     if ($ldap_result = @$function($this->conn, $base_dn, $filter, $attrs, 0, (int) $this->config['sizelimit'], (int) $this->config['timelimit'])) {
         // when running on a patched PHP we can use the extended functions
         // to retrieve the total count from the LDAP search result
         if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) {
             if (ldap_parse_result($this->conn, $ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) {
                 ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $vlv_count, $vresult);
                 $this->_debug("S: VLV result: last_offset={$last_offset}; content_count={$vlv_count}");
             } else {
                 $this->_debug("S: " . ($errmsg ? $errmsg : ldap_error($this->conn)));
             }
         } else {
             if ($this->debug) {
                 $this->_debug("S: " . ldap_count_entries($this->conn, $ldap_result) . " record(s) found");
             }
         }
         $this->result = new rcube_ldap_result($this->conn, $ldap_result, $base_dn, $filter, $vlv_count);
         return $count_only ? $this->result->count() : $this->result;
     } else {
         $this->_debug("S: " . ldap_error($this->conn));
     }
     return false;
 }