big performance improvment (developed and tested on an install with > 2000 users)

This commit is contained in:
Ralf Becker 2006-09-15 16:19:39 +00:00
parent b064db8a7b
commit fb62796694
2 changed files with 154 additions and 143 deletions

View File

@ -144,7 +144,7 @@ class accounts extends accounts_backend
*/
function search($param)
{
//echo "<p>accounts::search(".print_r($param,True).")</p>\n";
//echo "<p>accounts::search(".print_r($param,True).") start: ".microtime()."</p>\n";
$this->setup_cache();
$account_search = &$this->cache['account_search'];
@ -154,7 +154,7 @@ class accounts extends accounts_backend
{
$this->total = $account_search[$serial]['total'];
}
elseif (method_exists('accounts_','search')) // implements its on search function ==> use it
elseif (method_exists('accounts_backend','search')) // implements its on search function ==> use it
{
$account_search[$serial]['data'] = parent::search($param);
$account_search[$serial]['total'] = $this->total;
@ -232,6 +232,7 @@ class accounts extends accounts_backend
}
}
//echo "<p>accounts::search('$serial')=<pre>".print_r($account_search[$serial]['data'],True).")</pre>\n";
//echo "<p>accounts::search() end: ".microtime()."</p>\n";
return $account_search[$serial]['data'];
}
@ -568,9 +569,12 @@ class accounts extends accounts_backend
if($type == 'g')
{
$accounts['groups'][$id] = $id;
foreach($this->members($id,true) as $id)
if ($use != 'groups')
{
$accounts['accounts'][$id] = $id;
foreach($this->members($id,true) as $id)
{
$accounts['accounts'][$id] = $id;
}
}
}
else
@ -690,8 +694,8 @@ class accounts extends accounts_backend
{
case 'xmlrpc':
$xml_functions = array(
'get_list' => array(
'function' => 'get_list',
'search' => array(
'function' => 'search',
'signature' => array(array(xmlrpcStruct)),
'docstring' => lang('Returns a full list of accounts on the system. Warning: This is return can be quite large')
),
@ -752,7 +756,7 @@ class accounts extends accounts_backend
*/
function save_session_cache()
{
if ($this->use_session_cache && // are we supposed to use a session-cache
if (// is somehow not longer set! $this->use_session_cache && // are we supposed to use a session-cache
$GLOBALS['egw_info']['accounts']['session_cache_setup'] && // is it already setup
// is the account-class ready (startup !)
is_object($GLOBALS['egw']->session))
@ -795,44 +799,18 @@ class accounts extends accounts_backend
*/
function get_list($_type='both',$start = null,$sort = '', $order = '', $query = '', $offset = null,$query_type='')
{
//echo "<p>accounts::get_list(".print_r($_type,True).",start='$start',sort='$sort',order='$order',query='$query',offset='$offset')</p>\n";
$this->setup_cache();
$account_list = &$this->cache['account_list'];
// For XML-RPC
if (is_array($_type))
if (is_array($_type)) // XML-RPC
{
$p = $_type;
$_type = $p['type'];
$start = $p['start'];
$order = $p['order'];
$query = $p['query'];
$offset = $p['offset'];
$query_type = $p['query_type'];
return $this->search($_type);
}
else
{
$p = array(
'type' => $_type,
'start' => $start,
'order' => $order,
'query' => $query,
'offset' => $offset,
'query_type' => $query_type ,
);
}
$serial = serialize($p);
if (isset($account_list[$serial]))
{
$this->total = $account_list[$serial]['total'];
}
else
{
$account_list[$serial]['data'] = parent::get_list($_type,$start,$sort,$order,$query,$offset,$query_type);
$account_list[$serial]['total'] = $this->total;
}
return $account_list[$serial]['data'];
return $this->search(array(
'type' => $_type,
'start' => $start,
'order' => $order,
'query' => $query,
'offset' => $offset,
'query_type' => $query_type ,
));
}
/**

View File

@ -499,128 +499,161 @@ class accounts_backend
}
/**
* Searches users and/or groups
*
* ToDo: implement a search like accounts::search
* Searches / lists accounts: users and/or groups
*
* @param string $_type
* @param int $start=null
* @param string $sort=''
* @param string $order=''
* @param string $query
* @param int $offset=null
* @param string $query_type
* @return array
* @param array with the following keys:
* @param $param['type'] string/int 'accounts', 'groups', 'owngroups' (groups the user is a member of), 'both'
* or integer group-id for a list of members of that group
* @param $param['start'] int first account to return (returns offset or max_matches entries) or all if not set
* @param $param['sort'] string column to sort after, default account_lid if unset
* @param $param['order'] string 'ASC' or 'DESC', default 'DESC' if not set
* @param $param['query'] string to search for, no search if unset or empty
* @param $param['query_type'] string:
* 'all' - query all fields for containing $param[query]
* 'start' - query all fields starting with $param[query]
* 'exact' - query all fields for exact $param[query]
* 'lid','firstname','lastname','email' - query only the given field for containing $param[query]
* @param $param['offset'] int - number of matches to return if start given, default use the value in the prefs
* @return array with uid / data pairs, data is an array with account_id, account_lid, account_firstname,
* account_lastname, person_id (id of the linked addressbook entry), account_status, account_expires, account_primary_group
*/
function get_list($_type='both', $start = null,$sort = '', $order = '', $query = '', $offset = null, $query_type='')
function search($param)
{
//print "\$_type=$_type, \$start=$start , \$sort=$sort, \$order=$order, \$query=$query, \$offset=$offset, \$query_type=$query_type<br>";
$query = ldap::quote(strtolower($query));
if($_type != 'groups')
//echo "<p>accounts_backend::search(".print_r($param,true)."): ".microtime()."</p>\n";
$account_search = &$this->cache['account_search'];
// check if the query is cached
$serial = serialize($param);
if (isset($account_search[$serial]))
{
$filter = "(&(uidnumber=*)(objectclass=posixaccount)";
if (!empty($query) && $query != '*')
$this->total = $account_search[$serial]['total'];
return $account_search[$serial]['data'];
}
// if it's a limited query, check if the unlimited query is cached
$start = $param['start'];
if (!($maxmatchs = $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs'])) $maxmatchs = 15;
if (!($offset = $param['offset'])) $offset = $maxmatchs;
unset($param['start']);
unset($param['offset']);
$unl_serial = serialize($param);
if (isset($account_search[$unl_serial]))
{
$this->total = $account_search[$unl_serial]['total'];
$sortedAccounts = $account_search[$unl_serial]['data'];
}
else // we need to run the unlimited query
{
$query = ldap::quote(strtolower($param['query']));
if($param['type'] != 'groups')
{
switch($query_type)
$filter = "(&(objectclass=posixaccount)";
if (!empty($query) && $query != '*')
{
case 'all':
default:
$query = '*'.$query;
// fall-through
case 'start':
$query .= '*';
// fall-through
case 'exact':
$filter .= "(|(uid=$query)(sn=$query)(cn=$query)(givenname=$query)(mail=$query))";
break;
case 'firstname':
case 'lastname':
case 'lid':
case 'email':
$to_ldap = array(
'firstname' => 'givenname',
'lastname' => 'sn',
'lid' => 'uid',
'email' => 'mail',
switch($param['query_type'])
{
case 'all':
default:
$query = '*'.$query;
// fall-through
case 'start':
$query .= '*';
// fall-through
case 'exact':
$filter .= "(|(uid=$query)(sn=$query)(cn=$query)(givenname=$query)(mail=$query))";
break;
case 'firstname':
case 'lastname':
case 'lid':
case 'email':
$to_ldap = array(
'firstname' => 'givenname',
'lastname' => 'sn',
'lid' => 'uid',
'email' => 'mail',
);
$filter .= '('.$to_ldap[$param['query_type']].'=*'.$query.'*)';
break;
}
}
if (is_numeric($param['type'])) // return only group-members
{
if (!($members = $this->members($param['type']))) return array();
//echo "<p>accounts_backend::search() after members($param[type]): ".microtime()."</p>\n";
$filter .= '(|(uid='.implode(')(uid=',$members).'))';
}
$filter .= ')';
$sri = ldap_search($this->ds, $this->user_context, $filter,array('uid','uidNumber','givenname','sn','mail','shadowExpire'));
//echo "<p>ldap_search(,$this->user_context,'$filter',) ".($sri ? '' : ldap_error($this->ds)).microtime()."</p>\n";
$allValues = ldap_get_entries($this->ds, $sri);
$utc_diff = date('Z');
while (list($null,$allVals) = @each($allValues))
{
settype($allVals,'array');
$test = @$allVals['uid'][0];
if (!$GLOBALS['egw_info']['server']['global_denied_users'][$test] && $allVals['uid'][0])
{
$accounts[] = Array(
'account_id' => $allVals['uidnumber'][0],
'account_lid' => $GLOBALS['egw']->translation->convert($allVals['uid'][0],'utf-8'),
'account_type' => 'u',
'account_firstname' => $GLOBALS['egw']->translation->convert($allVals['givenname'][0],'utf-8'),
'account_lastname' => $GLOBALS['egw']->translation->convert($allVals['sn'][0],'utf-8'),
'account_status' => isset($allVals['shadowexpire'][0]) && $allVals['shadowexpire'][0]*24*3600-$utc_diff < time() ? false : 'A',
'account_email' => $allVals['mail'][0],
);
$filter .= '('.$to_ldap[$query_type].'=*'.$query.'*)';
break;
}
}
}
$filter .= ')';
$sri = ldap_search($this->ds, $this->user_context, $filter);
$allValues = ldap_get_entries($this->ds, $sri);
$utc_diff = date('Z');
while (list($null,$allVals) = @each($allValues))
if ($param['type'] == 'groups' || $param['type'] == 'both')
{
settype($allVals,'array');
$test = @$allVals['uid'][0];
if (!$GLOBALS['egw_info']['server']['global_denied_users'][$test] && $allVals['uid'][0])
if(empty($query) || $query == '*')
{
$accounts[] = Array(
'account_id' => $allVals['uidnumber'][0],
'account_lid' => $GLOBALS['egw']->translation->convert($allVals['uid'][0],'utf-8'),
'account_type' => 'u',
'account_firstname' => $GLOBALS['egw']->translation->convert($allVals['givenname'][0],'utf-8'),
'account_lastname' => $GLOBALS['egw']->translation->convert($allVals['sn'][0],'utf-8'),
'account_status' => isset($allVals['shadowexpire'][0]) && $allVals['shadowexpire'][0]*24*3600-$utc_diff < time() ? false : 'A',
'account_email' => $allVals['mail'][0],
);
$filter = '(objectclass=posixgroup)';
}
}
}
if ($_type != 'accounts')
{
if(empty($query) || $query == '*')
{
$filter = '(&(gidnumber=*)(objectclass=posixgroup))';
}
else
{
$filter = "(&(gidnumber=*)(objectclass=posixgroup)(|(cn=*$query*)))";
}
$sri = ldap_search($this->ds, $this->group_context, $filter);
$allValues = ldap_get_entries($this->ds, $sri);
while (list($null,$allVals) = @each($allValues))
{
settype($allVals,'array');
$test = $allVals['cn'][0];
if (!$GLOBALS['egw_info']['server']['global_denied_groups'][$test] && $allVals['cn'][0])
else
{
$accounts[] = Array(
'account_id' => -$allVals['gidnumber'][0],
'account_lid' => $GLOBALS['egw']->translation->convert($allVals['cn'][0],'utf-8'),
'account_type' => 'g',
'account_firstname' => $GLOBALS['egw']->translation->convert($allVals['cn'][0],'utf-8'),
'account_lastname' => lang('Group'),
'account_status' => 'A',
);
$filter = "(&(objectclass=posixgroup)(cn=*$query*))";
}
$sri = ldap_search($this->ds, $this->group_context, $filter,array('cn','gidNumber'));
$allValues = ldap_get_entries($this->ds, $sri);
while (list($null,$allVals) = @each($allValues))
{
settype($allVals,'array');
$test = $allVals['cn'][0];
if (!$GLOBALS['egw_info']['server']['global_denied_groups'][$test] && $allVals['cn'][0])
{
$accounts[] = Array(
'account_id' => -$allVals['gidnumber'][0],
'account_lid' => $GLOBALS['egw']->translation->convert($allVals['cn'][0],'utf-8'),
'account_type' => 'g',
'account_firstname' => $GLOBALS['egw']->translation->convert($allVals['cn'][0],'utf-8'),
'account_lastname' => lang('Group'),
'account_status' => 'A',
);
}
}
}
// sort the array
$arrayFunctions =& CreateObject('phpgwapi.arrayfunctions');
if(empty($param['order']))
{
$param['order'] = 'account_lid';
}
$account_search[$unl_serial]['data'] = $sortedAccounts = $arrayFunctions->arfsort($accounts,explode(',',$param['order']),$param['sort']);
$account_search[$unl_serial]['total'] = $this->total = count($accounts);
}
// sort the array
$arrayFunctions =& CreateObject('phpgwapi.arrayfunctions');
if(empty($order))
{
$order = 'account_lid';
}
$sortedAccounts = $arrayFunctions->arfsort($accounts,explode(',',$order),$sort);
$this->total = count($accounts);
//echo "<p>accounts_backend::search() found $this->total: ".microtime()."</p>\n";
// return only the wanted accounts
if (is_array($sortedAccounts))
{
reset($sortedAccounts);
if(is_numeric($start) && is_numeric($offset))
{
return array_slice($sortedAccounts, $start, $offset);
}
elseif(is_numeric($start))
{
if (!($maxmatchs = $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs'])) $maxmatchs = 15;
return array_slice($sortedAccounts, $start, $maxmatchs);
$account_search[$serial]['total'] = $this->total;
return $account_search[$serial]['data'] = array_slice($sortedAccounts, $start, $offset);
}
else
{