LDAP: implement userCount action. This required to (finally) clean up and refactor the search method, which will have a positive performance impact on paged search.
This commit is contained in:
parent
bc1235d325
commit
b669e1a3c1
|
@ -634,6 +634,10 @@ class Access extends LDAPUtility {
|
|||
return $this->search($filter, $this->connection->ldapBaseUsers, $attr, $limit, $offset);
|
||||
}
|
||||
|
||||
public function countUsers($filter, $attr = array('dn'), $limit = null, $offset = null) {
|
||||
return $this->count($filter, $this->connection->ldapBaseGroups, $attr, $limit, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search, optimized for Groups
|
||||
* @param $filter the LDAP filter for the search
|
||||
|
@ -647,61 +651,68 @@ class Access extends LDAPUtility {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search
|
||||
* @brief prepares and executes an LDAP search operation
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @returns array with the search result
|
||||
*
|
||||
* Executes an LDAP search
|
||||
* @param $limit optional, maximum results to be counted
|
||||
* @param $offset optional, a starting point
|
||||
* @returns array with the search result as first value and pagedSearchOK as
|
||||
* second | false if not successful
|
||||
*/
|
||||
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
private function executeSearch($filter, $base, &$attr = null, $limit = null, $offset = null) {
|
||||
if(!is_null($attr) && !is_array($attr)) {
|
||||
$attr = array(mb_strtolower($attr, 'UTF-8'));
|
||||
}
|
||||
|
||||
// See if we have a resource, in case not cancel with message
|
||||
$link_resource = $this->connection->getConnectionResource();
|
||||
if(!$this->ldap->isResource($link_resource)) {
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
if(!$this->ldap->isResource($cr)) {
|
||||
// Seems like we didn't find any resource.
|
||||
// Return an empty array just like before.
|
||||
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
|
||||
return array();
|
||||
return false;
|
||||
}
|
||||
|
||||
//check wether paged search should be attempted
|
||||
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset);
|
||||
|
||||
$linkResources = array_pad(array(), count($base), $link_resource);
|
||||
$linkResources = array_pad(array(), count($base), $cr);
|
||||
$sr = $this->ldap->search($linkResources, $base, $filter, $attr);
|
||||
$error = $this->ldap->errno($link_resource);
|
||||
$error = $this->ldap->errno($cr);
|
||||
if(!is_array($sr) || $error !== 0) {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'Error when searching: '.$this->ldap->error($link_resource).
|
||||
' code '.$this->ldap->errno($link_resource),
|
||||
'Error when searching: '.$this->ldap->error($cr).
|
||||
' code '.$this->ldap->errno($cr),
|
||||
\OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
|
||||
return array();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do the server-side sorting
|
||||
foreach(array_reverse($attr) as $sortAttr){
|
||||
foreach($sr as $searchResource) {
|
||||
$this->ldap->sort($link_resource, $searchResource, $sortAttr);
|
||||
}
|
||||
}
|
||||
return array($sr, $pagedSearchOK);
|
||||
}
|
||||
|
||||
$findings = array();
|
||||
foreach($sr as $key => $res) {
|
||||
$findings = array_merge($findings, $this->ldap->getEntries($link_resource, $res ));
|
||||
}
|
||||
/**
|
||||
* @brief processes an LDAP paged search operation
|
||||
* @param $sr the array containing the LDAP search resources
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $iFoundItems number of results in the search operation
|
||||
* @param $limit maximum results to be counted
|
||||
* @param $offset a starting point
|
||||
* @param $pagedSearchOK whether a paged search has been executed
|
||||
* @param $skipHandling required for paged search when cookies to
|
||||
* prior results need to be gained
|
||||
* @returns array with the search result as first value and pagedSearchOK as
|
||||
* second | false if not successful
|
||||
*/
|
||||
private function processPagedSearchStatus($sr, $filter, $base, $iFoundItems, $limit, $offset, $pagedSearchOK, $skipHandling) {
|
||||
if($pagedSearchOK) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO);
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
foreach($sr as $key => $res) {
|
||||
$cookie = null;
|
||||
if($this->ldap->controlPagedResultResponse($link_resource, $res, $cookie)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO);
|
||||
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) {
|
||||
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +724,7 @@ class Access extends LDAPUtility {
|
|||
// if count is bigger, then the server does not support
|
||||
// paged search. Instead, he did a normal search. We set a
|
||||
// flag here, so the callee knows how to deal with it.
|
||||
if($findings['count'] <= $limit) {
|
||||
if($iFoundItems <= $limit) {
|
||||
$this->pagedSearchedSuccessful = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -721,6 +732,86 @@ class Access extends LDAPUtility {
|
|||
\OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search, but counts the results only
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @param $limit optional, maximum results to be counted
|
||||
* @param $offset optional, a starting point
|
||||
* @param $skipHandling indicates whether the pages search operation is
|
||||
* completed
|
||||
* @returns int | false if the search could not be initialized
|
||||
*
|
||||
*/
|
||||
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), \OCP\Util::DEBUG);
|
||||
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||
if($search === false) {
|
||||
return false;
|
||||
}
|
||||
list($sr, $pagedSearchOK) = $search;
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
$counter = 0;
|
||||
foreach($sr as $key => $res) {
|
||||
$count = $this->ldap->countEntries($cr, $res);
|
||||
if($count !== false) {
|
||||
$counter += $count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, $counter, $limit,
|
||||
$offset, $pagedSearchOK, $skipHandling);
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @returns array with the search result
|
||||
*
|
||||
* Executes an LDAP search
|
||||
*/
|
||||
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||
if($search === false) {
|
||||
return array();
|
||||
}
|
||||
list($sr, $pagedSearchOK) = $search;
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
|
||||
if($skipHandling) {
|
||||
//i.e. result do not need to be fetched, we just need the cookie
|
||||
//thus pass 1 or any other value as $iFoundItems because it is not
|
||||
//used
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
|
||||
$offset, $pagedSearchOK,
|
||||
$skipHandling);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the server-side sorting
|
||||
foreach(array_reverse($attr) as $sortAttr){
|
||||
foreach($sr as $searchResource) {
|
||||
$this->ldap->sort($cr, $searchResource, $sortAttr);
|
||||
}
|
||||
}
|
||||
|
||||
$findings = array();
|
||||
foreach($sr as $key => $res) {
|
||||
$findings = array_merge($findings, $this->ldap->getEntries($cr , $res ));
|
||||
}
|
||||
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, $findings['count'],
|
||||
$limit, $offset, $pagedSearchOK,
|
||||
$skipHandling);
|
||||
|
||||
// if we're here, probably no connection resource is returned.
|
||||
// to make ownCloud behave nicely, we simply give back an empty array.
|
||||
|
|
|
@ -363,7 +363,8 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
return (bool)((OC_USER_BACKEND_CHECK_PASSWORD
|
||||
| OC_USER_BACKEND_GET_HOME
|
||||
| OC_USER_BACKEND_GET_DISPLAYNAME
|
||||
| OC_USER_BACKEND_PROVIDE_AVATAR)
|
||||
| OC_USER_BACKEND_PROVIDE_AVATAR
|
||||
| OC_USER_BACKEND_COUNT_USERS)
|
||||
& $actions);
|
||||
}
|
||||
|
||||
|
@ -373,4 +374,17 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
public function hasUserListings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* counts the users in LDAP
|
||||
*
|
||||
* @return int | bool
|
||||
*/
|
||||
public function countUsers() {
|
||||
$o = $this->access->connection->ldapLoginFilter;
|
||||
$filter = \OCP\Util::mb_str_replace(
|
||||
'%uid', '*', $this->access->connection->ldapLoginFilter, 'UTF-8');
|
||||
$entries = $this->access->countUsers($filter);
|
||||
return $entries;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,4 +210,19 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
|||
return $this->refBackend->hasUserListings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Count the number of users
|
||||
* @returns int | bool
|
||||
*/
|
||||
public function countUsers() {
|
||||
$users = false;
|
||||
foreach($this->backends as $backend) {
|
||||
$backendUsers = $backend->countUsers();
|
||||
if ($backendUsers !== false) {
|
||||
$users += $backendUsers;
|
||||
}
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue