Exemple #1
0
 /**
  * Perform a LDAP search and return the result
  *
  * @param   LdapQuery   $query
  * @param   array       $attributes     An array of the required attributes
  * @param   int         $attrsonly      Should be set to 1 if only attribute types are wanted
  * @param   int         $sizelimit      Enables you to limit the count of entries fetched
  * @param   int         $timelimit      Sets the number of seconds how long is spend on the search
  * @param   int         $deref
  *
  * @return  resource|bool               A search result identifier or false on error
  *
  * @throws  LogicException              If the LDAP query search scope is unsupported
  */
 public function ldapSearch(LdapQuery $query, array $attributes = null, $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER)
 {
     $queryString = (string) $query;
     $baseDn = $query->getBase() ?: $this->getDn();
     $scope = $query->getScope();
     if (Logger::getInstance()->getLevel() === Logger::DEBUG) {
         // We're checking the level by ourself to avoid rendering the ldapsearch commandline for nothing
         $starttlsParam = $this->encryption === static::STARTTLS ? ' -ZZ' : '';
         $ldapUrl = ($this->encryption === static::LDAPS ? 'ldaps://' : 'ldap://') . $this->hostname . ($this->port ? ':' . $this->port : '');
         if ($this->bound) {
             $bindParams = ' -D "' . $this->bindDn . '"' . ($this->bindPw ? ' -W' : '');
         }
         if ($deref === LDAP_DEREF_NEVER) {
             $derefName = 'never';
         } elseif ($deref === LDAP_DEREF_ALWAYS) {
             $derefName = 'always';
         } elseif ($deref === LDAP_DEREF_SEARCHING) {
             $derefName = 'search';
         } else {
             // $deref === LDAP_DEREF_FINDING
             $derefName = 'find';
         }
         Logger::debug("Issueing LDAP search. Use '%s' to reproduce.", sprintf('ldapsearch -P 3%s -H "%s"%s -b "%s" -s "%s" -z %u -l %u -a "%s"%s%s%s', $starttlsParam, $ldapUrl, $bindParams, $baseDn, $scope, $sizelimit, $timelimit, $derefName, $attrsonly ? ' -A' : '', $queryString ? ' "' . $queryString . '"' : '', $attributes ? ' "' . join('" "', $attributes) . '"' : ''));
     }
     switch ($scope) {
         case LdapQuery::SCOPE_SUB:
             $function = 'ldap_search';
             break;
         case LdapQuery::SCOPE_ONE:
             $function = 'ldap_list';
             break;
         case LdapQuery::SCOPE_BASE:
             $function = 'ldap_read';
             break;
         default:
             throw new LogicException('LDAP scope %s not supported by ldapSearch', $scope);
     }
     return @$function($this->getConnection(), $baseDn, $queryString, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
 }
 /**
  * Run the given LDAP query and return the resulting entries
  *
  * This utilizes paged search requests as defined in RFC 2696.
  *
  * @param   LdapQuery   $query      The query to fetch results with
  * @param   array       $fields     Request these attributes instead of the ones registered in the given query
  * @param   int         $pageSize   The maximum page size, defaults to self::PAGE_SIZE
  *
  * @return  array
  *
  * @throws  LdapException           In case an error occured while fetching the results
  */
 protected function runPagedQuery(LdapQuery $query, array $fields = null, $pageSize = null)
 {
     if ($pageSize === null) {
         $pageSize = static::PAGE_SIZE;
     }
     $limit = $query->getLimit();
     $offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
     $queryString = (string) $query;
     $base = $query->getBase() ?: $this->rootDn;
     if ($fields === null) {
         $fields = $query->getColumns();
     }
     $ds = $this->getConnection();
     $serverSorting = false;
     //$this->capabilities->hasOid(Capability::LDAP_SERVER_SORT_OID);
     if ($serverSorting && $query->hasOrder()) {
         ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array(array('oid' => LdapCapabilities::LDAP_SERVER_SORT_OID, 'value' => $this->encodeSortRules($query->getOrder()))));
     } elseif ($query->hasOrder()) {
         foreach ($query->getOrder() as $rule) {
             if (!in_array($rule[0], $fields)) {
                 $fields[] = $rule[0];
             }
         }
     }
     $count = 0;
     $cookie = '';
     $entries = array();
     do {
         // Do not request the pagination control as a critical extension, as we want the
         // server to return results even if the paged search request cannot be satisfied
         ldap_control_paged_result($ds, $pageSize, false, $cookie);
         $results = @ldap_search($ds, $base, $queryString, array_values($fields), 0, $serverSorting && $limit ? $offset + $limit : 0);
         if ($results === false) {
             if (ldap_errno($ds) === self::LDAP_NO_SUCH_OBJECT) {
                 break;
             }
             throw new LdapException('LDAP query "%s" (base %s) failed. Error: %s', $queryString, $base, ldap_error($ds));
         } elseif (ldap_count_entries($ds, $results) === 0) {
             if (in_array(ldap_errno($ds), array(static::LDAP_SIZELIMIT_EXCEEDED, static::LDAP_ADMINLIMIT_EXCEEDED))) {
                 Logger::warning('Unable to request more than %u results. Does the server allow paged search requests? (%s)', $count, ldap_error($ds));
             }
             break;
         }
         $entry = ldap_first_entry($ds, $results);
         do {
             $count += 1;
             if (!$serverSorting || $offset === 0 || $offset < $count) {
                 $entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(ldap_get_attributes($ds, $entry), array_flip($fields));
             }
         } while ((!$serverSorting || $limit === 0 || $limit !== count($entries)) && ($entry = ldap_next_entry($ds, $entry)));
         if (false === @ldap_control_paged_result_response($ds, $results, $cookie)) {
             // If the page size is greater than or equal to the sizeLimit value, the server should ignore the
             // control as the request can be satisfied in a single page: https://www.ietf.org/rfc/rfc2696.txt
             // This applies no matter whether paged search requests are permitted or not. You're done once you
             // got everything you were out for.
             if ($serverSorting && count($entries) !== $limit) {
                 // The server does not support pagination, but still returned a response by ignoring the
                 // pagedResultsControl. We output a warning to indicate that the pagination control was ignored.
                 Logger::warning('Unable to request paged LDAP results. Does the server allow paged search requests?');
             }
         }
         ldap_free_result($results);
     } while ($cookie && (!$serverSorting || $limit === 0 || count($entries) < $limit));
     if ($cookie) {
         // A sequence of paged search requests is abandoned by the client sending a search request containing a
         // pagedResultsControl with the size set to zero (0) and the cookie set to the last cookie returned by
         // the server: https://www.ietf.org/rfc/rfc2696.txt
         ldap_control_paged_result($ds, 0, false, $cookie);
         ldap_search($ds, $base, $queryString);
         // Returns no entries, due to the page size
     } else {
         // Reset the paged search request so that subsequent requests succeed
         ldap_control_paged_result($ds, 0);
     }
     if (!$serverSorting && $query->hasOrder()) {
         uasort($entries, array($query, 'compare'));
         if ($limit && $count > $limit) {
             $entries = array_splice($entries, $query->hasOffset() ? $query->getOffset() : 0, $limit);
         }
     }
     return $entries;
 }