mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-17 07:49:06 +01:00
1928 lines
57 KiB
PHP
1928 lines
57 KiB
PHP
<?php
|
|
/*******************************************************************************
|
|
* Copyright (C) 2007 Easter-eggs
|
|
* http://ldapsaisie.labs.libre-entreprise.org
|
|
*
|
|
* Author: See AUTHORS file in top-level directory.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
******************************************************************************/
|
|
|
|
LSsession :: loadLSclass('LSlog_staticLoggerClass');
|
|
|
|
/**
|
|
* Object LSsearch
|
|
*
|
|
* @author Benjamin Renard <brenard@easter-eggs.com>
|
|
*/
|
|
class LSsearch extends LSlog_staticLoggerClass {
|
|
|
|
// The LdapObject type of search
|
|
private $LSobject=NULL;
|
|
|
|
// The configuration of search
|
|
private $config;
|
|
|
|
// The context of search
|
|
private $context;
|
|
|
|
// The parameters of the search
|
|
private $params=array (
|
|
// Search params
|
|
'filter' => NULL,
|
|
'pattern' => NULL,
|
|
'predefinedFilter' => false,
|
|
'basedn' => NULL,
|
|
'subDn' => NULL,
|
|
'scope' => NULL,
|
|
'sizelimit' => 0,
|
|
'attronly' => false, // If true, only attribute names are returned
|
|
'approx' => false,
|
|
'recursive' => false,
|
|
'attributes' => array(),
|
|
// Display params
|
|
'onlyAccessible' => NULL,
|
|
'sortDirection' => NULL,
|
|
'sortBy' => NULL,
|
|
'sortlimit' => 0,
|
|
'displaySubDn' => NULL,
|
|
'displayFormat' => NULL,
|
|
'nbObjectsByPage' => NB_LSOBJECT_LIST,
|
|
'nbObjectsByPageChoices' => NULL,
|
|
'customInfos' => array(),
|
|
'withoutCache' => false,
|
|
'extraDisplayedColumns' => false,
|
|
);
|
|
|
|
// The cache of search parameters
|
|
private $_searchParams = NULL;
|
|
|
|
// The result of the search
|
|
private $result=NULL;
|
|
|
|
// Caches
|
|
private $_canCopy=NULL;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param[in] $LSobject string The LdapObject type of search
|
|
* @param[in] $context string Context of search (LSrelation / LSldapObject/ ...)
|
|
* @param[in] $params array Parameters of search
|
|
* @param[in] $purgeParams boolean If params in session have to be purged
|
|
*
|
|
**/
|
|
public function __construct($LSobject,$context,$params=null,$purgeParams=false) {
|
|
if (!LSsession :: loadLSobject($LSobject)) {
|
|
return;
|
|
}
|
|
$this -> LSobject = $LSobject;
|
|
|
|
$this -> loadConfig();
|
|
|
|
if (isset($_REQUEST['LSsearchPurgeSession'])) {
|
|
$this -> purgeSession();
|
|
}
|
|
|
|
$this -> context = $context;
|
|
|
|
if (!$purgeParams) {
|
|
if (! $this -> loadParamsFromSession()) {
|
|
$this -> loadDefaultParameters();
|
|
}
|
|
}
|
|
else {
|
|
$this -> purgeParams($LSobject);
|
|
$this -> loadDefaultParameters();
|
|
}
|
|
|
|
if (is_array($params)) {
|
|
$this -> setParams($params);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Allow conversion of LSsearch to string
|
|
*
|
|
* @retval string The string representation of the LSsearch
|
|
*/
|
|
public function __toString() {
|
|
$search_params = $this -> formatSearchParams();
|
|
return "<LSsearch of ".$this -> LSobject." (context=".$this -> context.")".($search_params?" $search_params":"").">";
|
|
}
|
|
|
|
/**
|
|
* Load configuration from LSconfig
|
|
*
|
|
* @retval void
|
|
*/
|
|
private function loadConfig() {
|
|
$this -> config = LSconfig::get("LSobjects.".$this -> LSobject.".LSsearch");
|
|
if (isset($this -> config['predefinedFilters']) && is_array($this -> config['predefinedFilters'])) {
|
|
foreach($this -> config['predefinedFilters'] as $filter => $label) {
|
|
if(!LSldap::isValidFilter($filter)) {
|
|
LSerror::addErrorCode('LSsearch_15',array('label' => $label, 'filter' => $filter, 'type' => $this -> LSobject));
|
|
unset($this -> config['predefinedFilters'][$key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load default search parameters from configuration
|
|
*
|
|
* @retval boolean True on success or False
|
|
*/
|
|
private function loadDefaultParameters() {
|
|
if (isset($this -> config['params']) && is_array($this -> config['params'])) {
|
|
self :: log_debug('Load default parameters (from object type configuration)');
|
|
return $this -> setParams($this -> config['params']);
|
|
}
|
|
else
|
|
self :: log_trace('loadDefaultParameters(): no parameters found in object type configuration');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Load search parameters from session
|
|
*
|
|
* @retval boolean True if params has been loaded from session or False
|
|
*/
|
|
private function loadParamsFromSession() {
|
|
if (isset($_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context]) && is_array($_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context])) {
|
|
self :: log_debug('Load params from session for context '.$this -> context);
|
|
$params = $_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context];
|
|
|
|
if ($params['filter']) {
|
|
$params['filter'] = Net_LDAP2_Filter::parse($params['filter']);
|
|
}
|
|
|
|
$this -> params = $params;
|
|
return true;
|
|
}
|
|
else
|
|
self :: log_trace("loadParamsFromSession(): no params in session for context ".$this -> context);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Save search parameters in session
|
|
*
|
|
* @retval void
|
|
*/
|
|
private function saveParamsInSession() {
|
|
self :: log_debug('Save context params session '.$this -> context);
|
|
$params = $this -> params;
|
|
if ($params['filter'] instanceof Net_LDAP2_Filter) {
|
|
$params['filter'] = $params['filter'] -> asString();
|
|
}
|
|
|
|
foreach ($params as $param => $value) {
|
|
if ( !isset($_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context][$param]) || $_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context][$param]!=$value) {
|
|
self :: log_trace("$param => ".varDump($value));
|
|
$_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context][$param]=$value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Purge parameters in session
|
|
*
|
|
* @param[in] $LSobject string The LSobject type
|
|
*
|
|
* @retval void
|
|
*/
|
|
public static function purgeParams($LSobject) {
|
|
unset($_SESSION['LSsession']['LSsearch'][$LSobject]['params']);
|
|
}
|
|
|
|
/**
|
|
* Purge cache
|
|
*
|
|
* @retval void
|
|
*/
|
|
public static function purgeCache($LSobject) {
|
|
unset($_SESSION['LSsession']['LSsearch'][$LSobject]);
|
|
}
|
|
|
|
/**
|
|
* Purge session
|
|
*
|
|
* @retval void
|
|
*/
|
|
private function purgeSession() {
|
|
unset($_SESSION['LSsession']['LSsearch']);
|
|
}
|
|
|
|
/**
|
|
* Define one search parameter
|
|
*
|
|
* @param[in] $param string The parameter name
|
|
* @param[in] $value mixed The parameter value
|
|
*
|
|
* @retval boolean True on success or False
|
|
*/
|
|
public function setParam($param,$value) {
|
|
return $this -> setParams(array($param => $value));
|
|
}
|
|
|
|
/**
|
|
* Define search parameters
|
|
*
|
|
* @param[in] $params array Parameters of search
|
|
*
|
|
* @retval boolean True on success or False
|
|
*/
|
|
public function setParams($params) {
|
|
$OK=true;
|
|
|
|
// Filter
|
|
if (isset($params['filter'])) {
|
|
if (is_string($params['filter'])) {
|
|
$filter = Net_LDAP2_Filter::parse($params['filter']);
|
|
if (!LSerror::isLdapError($filter)) {
|
|
$this -> params['filter'] = $filter;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_01',$params['filter']);
|
|
$OK=false;
|
|
}
|
|
}
|
|
elseif($params['filter'] instanceof Net_LDAP2_Filter) {
|
|
$this -> params['filter'] =& $params['filter'];
|
|
}
|
|
}
|
|
|
|
// Approx
|
|
if (isset($params['approx'])) {
|
|
if (is_bool($params['approx']) || $params['approx']==0 || $params['approx']==1) {
|
|
$this -> params['approx'] = (bool)$params['approx'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_05','approx');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Without Cache
|
|
if (isset($params['withoutCache'])) {
|
|
if (is_bool($params['withoutCache']) || $params['withoutCache']==0 || $params['withoutCache']==1) {
|
|
$this -> params['withoutCache'] = (bool)$params['withoutCache'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_05','withoutCache');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Patterm
|
|
if (isset($params['pattern'])) {
|
|
if ($params['pattern']=="") {
|
|
$this -> params['pattern'] = NULL;
|
|
}
|
|
elseif ($this -> isValidPattern($params['pattern'])) {
|
|
$this -> params['pattern'] = $params['pattern'];
|
|
}
|
|
}
|
|
|
|
|
|
// BaseDN
|
|
if (isset($params['basedn']) && is_string($params['basedn'])) {
|
|
if (isCompatibleDNs(LSsession :: getRootDn(),$params['basedn'])) {
|
|
$this -> params['basedn'] = $params['basedn'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_02',$params['basedn']);
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// subDn
|
|
if (isset($params['subDn']) && is_string($params['subDn'])) {
|
|
if (LSsession :: validSubDnLdapServer($params['subDn'])) {
|
|
$this -> params['subDn'] = $params['subDn'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','subDn');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Scope
|
|
if (isset($params['scope']) && is_string($params['scope'])) {
|
|
if (in_array($params['scope'],array('sub','one','base'))) {
|
|
$this -> params['scope'] = $params['scope'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','scope');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// nbObjectsByPage
|
|
if (isset($params['nbObjectsByPage'])) {
|
|
if (((int)$params['nbObjectsByPage'])>=1 ) {
|
|
$this -> params['nbObjectsByPage'] = (int)$params['nbObjectsByPage'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','nbObjectsByPage');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// nbObjectsByPageChoices
|
|
if (isset($params['nbObjectsByPageChoices'])) {
|
|
if (is_array($params['nbObjectsByPageChoices'])) {
|
|
$choices = array();
|
|
$choiceError = false;
|
|
foreach($params['nbObjectsByPageChoices'] as $choice) {
|
|
if (is_int($choice) && !in_array($choice, $choices)) {
|
|
$choices[] = $choice;
|
|
}
|
|
else {
|
|
$choiceError = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!empty($choices) && !$choiceError) {
|
|
$this -> params['nbObjectsByPageChoices'] = $choices;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','nbObjectsByPageChoices');
|
|
$OK = false;
|
|
}
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','nbObjectsByPageChoices');
|
|
$OK = false;
|
|
}
|
|
}
|
|
|
|
// Extra Columns
|
|
if (isset($params['extraDisplayedColumns'])) {
|
|
$this -> params['extraDisplayedColumns']=(bool)$params['extraDisplayedColumns'];
|
|
}
|
|
|
|
// Sort Limit
|
|
if (isset($params['sortlimit'])) {
|
|
if (is_int($params['sortlimit']) && $params['sortlimit']>=0 ) {
|
|
$this -> params['sortlimit'] = $params['sortlimit'];
|
|
}
|
|
elseif ((int)$params['sortlimit'] > 0) {
|
|
$this -> params['sortlimit'] = (int)$params['sortlimit'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','sortlimit');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Sort Direction
|
|
if (isset($params['sortDirection']) && is_string($params['sortDirection'])) {
|
|
if (in_array($params['sortDirection'],array('ASC','DESC'))) {
|
|
$this -> params['sortDirection'] = $params['sortDirection'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','sortDirection');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Sort By
|
|
if (isset($params['sortBy']) && is_string($params['sortBy'])) {
|
|
if (in_array($params['sortBy'],array('displayName','subDn')) || ($this ->extraDisplayedColumns && isset($this ->extraDisplayedColumns[$params['sortBy']]))) {
|
|
if ($this -> params['sortBy'] == $params['sortBy']) {
|
|
$this -> toggleSortDirection();
|
|
}
|
|
else {
|
|
$this -> params['sortBy'] = $params['sortBy'];
|
|
if (!isset($params['sortDirection']) || !is_string($params['sortDirection'])) {
|
|
$this -> params['sortDirection'] = 'ASC';
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','sortBy');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Size Limit
|
|
if (isset($params['sizelimit'])) {
|
|
if (((int)$params['sizelimit']) >= 0) {
|
|
$this -> params['sizelimit'] = $params['sizelimit'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_04');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Attronly
|
|
if (isset($params['attronly'])) {
|
|
if (is_bool($params['attronly']) || $params['attronly']==0 || $params['attronly']==1) {
|
|
$this -> params['attronly'] = (bool)$params['attronly'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_05','attronly');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Recursive
|
|
if (isset($params['recursive'])) {
|
|
if (is_bool($params['recursive']) || $params['recursive']==0 || $params['recursive']==1) {
|
|
$this -> params['recursive'] = (bool)$params['recursive'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_05','recursive');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// displaySubDn
|
|
if (isset($params['displaySubDn'])) {
|
|
if (! LSsession :: isSubDnLSobject($this -> LSobject) ) {
|
|
if (is_bool($params['displaySubDn']) || $params['displaySubDn']==0 || $params['displaySubDn']==1) {
|
|
$this -> params['displaySubDn'] = (bool)$params['displaySubDn'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_05','displaySubDn');
|
|
$OK=false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Attributes
|
|
if (isset($params['attributes'])) {
|
|
if (is_string($params['attributes'])) {
|
|
$this -> params['attributes'] = array($params['attributes']);
|
|
}
|
|
elseif (is_array($params['attributes'])) {
|
|
$this -> params['attributes']=array();
|
|
foreach ($params['attributes'] as $attr) {
|
|
if (is_string($attr)) {
|
|
if (LSconfig::get("LSobjects.".$this -> LSobject.".attrs.$attr")) {;
|
|
$this -> params['attributes'][] = $attr;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_11',$attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_06');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// predefinedFilter
|
|
if (isset($params['predefinedFilter'])) {
|
|
if (is_string($params['predefinedFilter'])) {
|
|
if (empty($params['predefinedFilter'])) {
|
|
$this->params['predefinedFilter']=false;
|
|
}
|
|
elseif(is_array($this -> config['predefinedFilters'])) {
|
|
if(isset($this->config['predefinedFilters'][$params['predefinedFilter']])) {
|
|
$this -> params['predefinedFilter'] = $params['predefinedFilter'];
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','predefinedFilter');
|
|
$OK=false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','predefinedFilter');
|
|
$OK=false;
|
|
}
|
|
}
|
|
|
|
// Display Format
|
|
if (isset($params['displayFormat']) && is_string($params['displayFormat'])) {
|
|
$this -> params['displayFormat'] = $params['displayFormat'];
|
|
}
|
|
|
|
// Custom Infos
|
|
if (isset($params['customInfos']) && is_array($params['customInfos'])) {
|
|
foreach($params['customInfos'] as $name => $data) {
|
|
if(is_array($data['function']) && is_string($data['function'][0])) {
|
|
LSsession::loadLSclass($data['function'][0]);
|
|
}
|
|
if (is_callable($data['function'])) {
|
|
$this -> params['customInfos'][$name] = array (
|
|
'function' => &$data['function'],
|
|
'args' => (isset($data['args'])?$data['args']:null),
|
|
'cache' => (isset($data['cache'])?boolval($data['cache']):true),
|
|
);
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_14',$name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only Accessible objects
|
|
if (isset($params['onlyAccessible'])) {
|
|
$this -> params['onlyAccessible'] = (bool)$params['onlyAccessible'];
|
|
}
|
|
|
|
$this -> saveParamsInSession();
|
|
return $OK;
|
|
}
|
|
|
|
/**
|
|
* Return true only if the form is submited
|
|
*
|
|
* @retval boolean True only if the is submited
|
|
**/
|
|
private function formIsSubmited() {
|
|
return isset($_REQUEST['LSsearch_submit']);
|
|
}
|
|
|
|
/**
|
|
* Define search parameters by reading request data ($_REQUEST)
|
|
*
|
|
* @retval boolean True if all parameters found in request data are handled, False otherwise
|
|
*/
|
|
public function setParamsFromRequest() {
|
|
$allowedParams = array(
|
|
'pattern', 'approx', 'recursive', 'extraDisplayedColumns', 'nbObjectsByPage',
|
|
'attributes', 'sortBy', 'sortDirection', 'withoutCache', 'predefinedFilter',
|
|
// Following parameters are allowed from request but need additional checks
|
|
'filter', 'basedn', 'subDn', 'scope', 'attributes', 'displayFormat',
|
|
);
|
|
$data = array();
|
|
|
|
foreach($_REQUEST as $key => $value) {
|
|
if (!in_array($key, $allowedParams))
|
|
continue;
|
|
switch($key) {
|
|
case 'filter':
|
|
// Parse filter to extract attribute name and check if user have read access on it
|
|
// FIXME: Net_LDAP2_Filter could only permit to extract attribute name from a simple
|
|
// filter (without sub-filters), so we currently only access this type of filter.
|
|
$filter = Net_LDAP2_Filter::parse($value);
|
|
if (Net_LDAP2::isError($filter)) {
|
|
LSerror :: addErrorCode('LSsearch_03', 'filter');
|
|
return;
|
|
}
|
|
$filter_parts = $filter -> getComponents();
|
|
if (!is_array($filter_parts) || !LSsession :: canAccess($this -> LSobject, null, 'r', $filter_parts[0])) {
|
|
LSerror :: addErrorCode('LSsearch_03', 'filter');
|
|
return;
|
|
}
|
|
return;
|
|
break;
|
|
|
|
case 'basedn':
|
|
case 'subDn':
|
|
case 'scope':
|
|
// These parameters could only be used if combined with onlyAccessible==True
|
|
$data['onlyAccessible'] = True;
|
|
break;
|
|
|
|
case 'attributes':
|
|
foreach(ensureIsArray($value) as $attr) {
|
|
if (!is_string($attr)) {
|
|
LSerror :: addErrorCode('LSsearch_06');
|
|
return;
|
|
}
|
|
if (!LSsession :: canAccess($this -> LSobject, null, 'r', $attr)) {
|
|
LSerror :: addErrorCode('LSsearch_11', $attr);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'displayFormat':
|
|
if (!LSsession :: canComputeLSformat($value, $this -> LSobject)) {
|
|
LSerror :: addErrorCode('LSsearch_11', 'displayFormat');
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
$data[$key] = $value;
|
|
}
|
|
|
|
if (self::formIsSubmited()) {
|
|
// Recursive
|
|
if (is_null($data['recursive'])) {
|
|
$data['recursive']=false;
|
|
}
|
|
else {
|
|
$data['recursive']=true;
|
|
}
|
|
|
|
// Approx
|
|
if (is_null($data['approx'])) {
|
|
$data['approx']=false;
|
|
}
|
|
else {
|
|
$data['approx']=true;
|
|
}
|
|
|
|
if (isset($data['ajax']) && !isset($data['pattern'])) {
|
|
$data['pattern']="";
|
|
}
|
|
}
|
|
|
|
return (empty($data)?true:$this -> setParams($data));
|
|
}
|
|
|
|
/**
|
|
* Toggle the sort direction
|
|
*
|
|
* @retval void
|
|
**/
|
|
private function toggleSortDirection() {
|
|
if ($this -> params['sortDirection']=="ASC") {
|
|
$this -> params['sortDirection'] = "DESC";
|
|
}
|
|
else {
|
|
$this -> params['sortDirection'] = "ASC";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make a filter object with a pattern of search
|
|
*
|
|
* @param[in] $pattern The pattern of search. If is null, the pattern in params will be used.
|
|
*
|
|
* @retval mixed Net_LDAP2_Filter on success or False
|
|
*/
|
|
public function getFilterFromPattern($pattern=NULL) {
|
|
if ($pattern==NULL) {
|
|
$pattern=$this -> params['pattern'];
|
|
}
|
|
if ($this -> isValidPattern($pattern)) {
|
|
$attrsConfig=LSconfig::get("LSobjects.".$this -> LSobject.".LSsearch.attrs");
|
|
$attrsList=array();
|
|
if (!is_array($attrsConfig)) {
|
|
foreach(LSconfig::get("LSobjects.".$this -> LSobject.".attrs") as $attr => $config) {
|
|
$attrsList[$attr]=array();
|
|
}
|
|
}
|
|
else {
|
|
foreach($attrsConfig as $key => $val) {
|
|
if(is_int($key)) {
|
|
$attrsList[$val]=array();
|
|
}
|
|
else {
|
|
$attrsList[$key]=$val;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($attrsList)) {
|
|
LSerror :: addErrorCode('LSsearch_07');
|
|
return;
|
|
}
|
|
|
|
$filters=array();
|
|
foreach ($attrsList as $attr => $opts) {
|
|
if ($this -> params['approx']) {
|
|
if (isset($opts['approxLSformat'])) {
|
|
$filter=Net_LDAP2_Filter::parse(getFData($opts['approxLSformat'],array('name'=>$attr,'pattern'=>$pattern)));
|
|
}
|
|
else {
|
|
$filter=Net_LDAP2_Filter::create($attr,'approx',$pattern);
|
|
}
|
|
}
|
|
else {
|
|
if (isset($opts['searchLSformat'])) {
|
|
$filter=Net_LDAP2_Filter::parse(getFData($opts['searchLSformat'],array('name'=>$attr,'pattern'=>$pattern)));
|
|
}
|
|
else {
|
|
$filter=Net_LDAP2_Filter::create($attr,'contains',$pattern);
|
|
}
|
|
}
|
|
|
|
if (!Net_LDAP2::isError($filter)) {
|
|
$filters[]=$filter;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_08',array('attr' => $attr,'pattern' => $pattern));
|
|
return;
|
|
}
|
|
}
|
|
if(!empty($filters)) {
|
|
$filter=LSldap::combineFilters('or',$filters);
|
|
if ($filter) {
|
|
return $filter;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_09');
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_10');
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Check if search pattern is valid
|
|
*
|
|
* @param[in] $pattern string The pattern
|
|
*
|
|
* @retval boolean True if pattern is valid or False
|
|
**/
|
|
public function isValidPattern($pattern) {
|
|
if (is_string($pattern) && $pattern!= "") {
|
|
$regex = (isset($this -> config['validPatternRegex'])?$this -> config['validPatternRegex']:'/^[\w \-\_\\\'\"^\[\]\(\)\{\}\=\+\£\%\$\€\.\:\;\,\?\/\@]+$/iu');
|
|
if (preg_match($regex, $pattern))
|
|
return True;
|
|
}
|
|
LSerror :: addErrorCode('LSsearch_17');
|
|
return False;
|
|
}
|
|
|
|
/**
|
|
* Check if cache is enabled
|
|
*
|
|
* @retval boolean True if cache is enabled or False
|
|
**/
|
|
public function cacheIsEnabled() {
|
|
if (isset($this -> config['cache'])) {
|
|
$conf=$this -> config['cache'];
|
|
if (is_bool($conf) || $conf==0 || $conf==1) {
|
|
return (bool)$conf;
|
|
}
|
|
else {
|
|
LSerror :: addErrorCode('LSsearch_03','cache');
|
|
}
|
|
}
|
|
return LSsession :: cacheSearch();
|
|
}
|
|
|
|
/**
|
|
* Methode for parameters value access
|
|
*
|
|
* @param[in] $key string The parameter name
|
|
*
|
|
* @retval mixed The parameter value or NULL
|
|
**/
|
|
public function getParam($key) {
|
|
if(in_array($key,array_keys($this -> params))) {
|
|
if ($key == 'nbObjectsByPageChoices' && !is_array($this -> params['nbObjectsByPageChoices'])) {
|
|
return (isset($GLOBALS['NB_LSOBJECT_LIST_CHOICES']) && is_array($GLOBALS['NB_LSOBJECT_LIST_CHOICES'])?$GLOBALS['NB_LSOBJECT_LIST_CHOICES']:range(NB_LSOBJECT_LIST, NB_LSOBJECT_LIST*4, NB_LSOBJECT_LIST));
|
|
}
|
|
return $this -> params[$key];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Return hidden fileds to add in search form
|
|
*
|
|
* @retval array The hield fields whith their values
|
|
**/
|
|
public function getHiddenFieldForm() {
|
|
return array (
|
|
'LSobject' => $this -> LSobject
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Generate an array with search parameters, only parameters whitch have to be
|
|
* passed to Net_LDAP2 for the LDAP search. This array will be store in
|
|
* $this -> _searchParams private variable.
|
|
*
|
|
* @retval void
|
|
**/
|
|
private function generateSearchParams() {
|
|
// Base
|
|
$retval = array(
|
|
'filter' => $this -> params['filter'],
|
|
'basedn' => $this -> params['basedn'],
|
|
'scope' => $this -> params['scope'],
|
|
'sizelimit' => $this -> params['sizelimit'],
|
|
'attronly' => $this -> params['attronly'],
|
|
'attributes' => $this -> params['attributes']
|
|
);
|
|
|
|
// Pattern
|
|
if (!is_null($this -> params['pattern'])) {
|
|
$filter=$this ->getFilterFromPattern();
|
|
if (is_null($retval['filter'])) {
|
|
$retval['filter']=$filter;
|
|
}
|
|
else {
|
|
$retval['filter']=LSldap::combineFilters('and',array($retval['filter'],$filter));
|
|
}
|
|
}
|
|
|
|
// predefinedFilter
|
|
if (is_string($this -> params['predefinedFilter'])) {
|
|
if (!is_null($retval['filter'])) {
|
|
$filter=LSldap::combineFilters('and',array($this -> params['predefinedFilter'],$retval['filter']));
|
|
if ($filter) {
|
|
$retval['filter']=$filter;
|
|
}
|
|
}
|
|
else {
|
|
$retval['filter']=$this -> params['predefinedFilter'];
|
|
}
|
|
}
|
|
|
|
// Filter
|
|
$objFilter=LSldapObject::_getObjectFilter($this -> LSobject);
|
|
if ($objFilter) {
|
|
if (!is_null($retval['filter'])) {
|
|
$filter=LSldap::combineFilters('and',array($objFilter,$retval['filter']));
|
|
if ($filter) {
|
|
$retval['filter']=$filter;
|
|
}
|
|
}
|
|
else {
|
|
$retval['filter']=$objFilter;
|
|
}
|
|
}
|
|
|
|
// Recursive
|
|
if (is_null($retval['basedn'])) {
|
|
if (!is_null($this -> params['subDn'])) {
|
|
if ($this -> params['recursive']) {
|
|
$retval['basedn'] = $this -> params['subDn'];
|
|
}
|
|
else {
|
|
$retval['basedn'] = LSconfig::get("LSobjects.".$this -> LSobject.".container_dn").','.$this -> params['subDn'];
|
|
}
|
|
}
|
|
else {
|
|
if ($this -> params['recursive']) {
|
|
$retval['basedn'] = LSsession :: getTopDn();
|
|
}
|
|
else {
|
|
$retval['basedn'] = LSconfig::get("LSobjects.".$this -> LSobject.".container_dn").','.LSsession :: getTopDn();
|
|
}
|
|
}
|
|
}
|
|
if ($this -> params['recursive'] || !isset($retval['scope'])) {
|
|
$retval['scope'] = 'sub';
|
|
}
|
|
|
|
if (is_null($this -> params['displayFormat'])) {
|
|
$this -> params['displayFormat']=LSconfig::get("LSobjects.".$this -> LSobject.".display_name_format");
|
|
}
|
|
|
|
// Display Format
|
|
$attrs=getFieldInFormat($this -> params['displayFormat']);
|
|
if(is_array($retval['attributes'])) {
|
|
$retval['attributes']=array_merge($attrs,$retval['attributes']);
|
|
}
|
|
else {
|
|
$retval['attributes']=$attrs;
|
|
}
|
|
|
|
// Extra Columns
|
|
if ($this -> params['extraDisplayedColumns'] && is_array($this -> config['extraDisplayedColumns'])) {
|
|
foreach ($this -> config['extraDisplayedColumns'] as $id => $conf) {
|
|
$attrs=array();
|
|
if (isset($conf['LSformat'])) {
|
|
$attrs=getFieldInFormat($conf['LSformat']);
|
|
if (isset($conf['alternativeLSformats'])) {
|
|
if(is_array($conf['alternativeLSformats'])) {
|
|
foreach ($conf['alternativeLSformats'] as $format) {
|
|
$attrs = array_merge($attrs, getFieldInFormat($format));
|
|
}
|
|
}
|
|
else {
|
|
$attrs = array_merge($attrs, getFieldInFormat($conf['alternativeLSformats']));
|
|
}
|
|
}
|
|
if(isset($conf['formaterLSformat'])) {
|
|
$attrs=array_unique(array_merge($attrs,getFieldInFormat($conf['formaterLSformat'])));
|
|
if(($key = array_search('val', $attrs)) !== false) {
|
|
unset($attrs[$key]);
|
|
}
|
|
}
|
|
}
|
|
if(isset($conf['additionalAttrs'])) {
|
|
$attrs=array_unique(array_merge($attrs,(is_array($conf['additionalAttrs'])?$conf['additionalAttrs']:array($conf['additionalAttrs']))));
|
|
}
|
|
if(is_array($retval['attributes'])) {
|
|
$retval['attributes']=array_merge($attrs,$retval['attributes']);
|
|
}
|
|
else {
|
|
$retval['attributes']=$attrs;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_array($retval['attributes'])) {
|
|
$retval['attributes']=array_unique($retval['attributes']);
|
|
}
|
|
|
|
$this -> _searchParams = $retval;
|
|
}
|
|
|
|
/**
|
|
* Format search parameters for logging
|
|
*
|
|
* @retval string|null Formated search parameters is defined, or null if not
|
|
**/
|
|
private function formatSearchParams() {
|
|
if (!$this -> _searchParams)
|
|
return;
|
|
if ($this -> _searchParams['filter'] instanceof Net_LDAP2_Filter)
|
|
$return = "filter=".$this -> _searchParams['filter']->asString();
|
|
else
|
|
$return = "without filter";
|
|
$return .= ", on basedn '".$this -> _searchParams['basedn']."'";
|
|
$return .= " (scope: ".($this -> _searchParams['scope']?$this -> _searchParams['scope']:'default');
|
|
if ($this -> _searchParams['attronly'])
|
|
$return .= ", attrs only)";
|
|
else
|
|
$return .= ", attrs: ".(
|
|
(is_array($this -> _searchParams['attributes']) && $this -> _searchParams['attributes'])?
|
|
implode(',', $this -> _searchParams['attributes']):
|
|
'all'
|
|
).")";
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Get search attributes
|
|
*
|
|
* @retval array The attributes asked in this search
|
|
**/
|
|
public function getAttributes() {
|
|
if (!$this -> _searchParams)
|
|
$this -> generateSearchParams();
|
|
return $this -> _searchParams['attributes'];
|
|
}
|
|
|
|
/**
|
|
* Run the search
|
|
*
|
|
* @param[in] $cache boolean Define if the cache can be used
|
|
*
|
|
* @retval boolean True on success or False
|
|
*/
|
|
public function run($cache=true) {
|
|
$this -> generateSearchParams();
|
|
self :: log_debug($this." -> run(".($cache?'with cache':'without cache').")");
|
|
|
|
if( $cache && (!isset($_REQUEST['refresh'])) && (!$this -> params['withoutCache']) ) {
|
|
self :: log_debug($this.' -> run(): Cache enabled');
|
|
$this -> result = $this -> getResultFromCache();
|
|
if ($this -> result)
|
|
self :: log_debug($this.' -> run(): result retreived from cache');
|
|
else
|
|
self :: log_debug($this.' -> run(): result not found in cache');
|
|
}
|
|
else {
|
|
self :: log_debug($this.' -> run(): Cache disabled');
|
|
$this -> setParam('withoutCache', false);
|
|
}
|
|
|
|
if (!$this -> result) {
|
|
$this -> result=array(
|
|
'sortBy' => NULL,
|
|
'sortDirection' => NULL
|
|
);
|
|
|
|
// Search in LDAP
|
|
$list = LSldap :: search(
|
|
$this -> _searchParams['filter'],
|
|
$this -> _searchParams['basedn'],
|
|
$this -> _searchParams
|
|
);
|
|
|
|
// Check result
|
|
if ($list === false) {
|
|
LSerror :: addErrorCode('LSsearch_12');
|
|
return;
|
|
}
|
|
|
|
// Handle onlyAccessible parameter
|
|
if ($this -> getParam('onlyAccessible') && LSsession :: getLSuserObjectDn()) {
|
|
self :: log_debug($this.' -> run(): Filter on only accessible object');
|
|
$this -> result['list'] = array();
|
|
|
|
// Check user rights on objets
|
|
foreach($list as $id => $obj) {
|
|
if (LSsession :: canAccess($this -> LSobject, $obj['dn'])) {
|
|
$this -> result['list'][] = $obj;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
$this -> result['list'] = $list;
|
|
$this -> addResultToCache();
|
|
}
|
|
|
|
self :: log_debug($this.' -> run(): '.$this -> total. " object(s) found");
|
|
|
|
$this -> doSort();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Return an hash corresponding to the parameters of the search
|
|
*
|
|
* @param[in] $searchParams array An optional search params array
|
|
* @param[in] $onlyAccessible boolean An optional onlyAccessible boolean flag
|
|
*
|
|
* @retval string The hash of the parameters of the search
|
|
**/
|
|
public function getHash($searchParams=null, $onlyAccessible=null) {
|
|
if (is_null($searchParams)) {
|
|
$searchParams = $this -> _searchParams;
|
|
}
|
|
if (!$searchParams)
|
|
return false;
|
|
if ($searchParams['filter'] instanceof Net_LDAP_Filter) {
|
|
$searchParams['filter'] = $searchParams['filter'] -> asString();
|
|
}
|
|
$to_hash = print_r($searchParams, true);
|
|
if (is_null($onlyAccessible)) {
|
|
$onlyAccessible = ($this -> getParam('onlyAccessible') && LSsession :: getLSuserObjectDn());
|
|
}
|
|
$to_hash .= '-onlyAccessible='.intval($onlyAccessible);
|
|
return hash('md5', print_r($searchParams, true));
|
|
}
|
|
|
|
/**
|
|
* Add the result of the search to cache of the session
|
|
*
|
|
* @retval void
|
|
**/
|
|
public function addResultToCache() {
|
|
if ($this -> cacheIsEnabled()) {
|
|
$hash = $this->getHash();
|
|
self :: log_trace("addResultToCache(): Save result in cache with hash '$hash'.");
|
|
$_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash]=$this->result;
|
|
}
|
|
else
|
|
self :: log_trace('addResultToCache(): cache is disabled.');
|
|
}
|
|
|
|
/**
|
|
* Get the result of the search from cache of the session
|
|
*
|
|
* @retval array | False The array of the result of the search or False
|
|
**/
|
|
private function getResultFromCache() {
|
|
if ($this -> cacheIsEnabled()) {
|
|
$hash=$this->getHash();
|
|
if (isset($_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash])) {
|
|
self :: log_trace('getResultFromCache(): result found in cache.');
|
|
return $_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash];
|
|
}
|
|
self :: log_trace('getResultFromCache(): result not found in cache.');
|
|
}
|
|
else
|
|
self :: log_trace('getResultFromCache(): cache is disabled.');
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Get page informations to display
|
|
*
|
|
* @param[in] $page integer The number of the page
|
|
*
|
|
* @retval array The information of the page
|
|
**/
|
|
public function getPage($page=1) {
|
|
if (!LSsession::loadLSclass('LSsearchEntry')) {
|
|
LSerror::addErrorCode('LSsession_05',$this -> LSobject);
|
|
return;
|
|
}
|
|
$page = (int)$page;
|
|
if ($page < 1)
|
|
$page = 1;
|
|
|
|
$retval = array(
|
|
'nb' => $page,
|
|
'nbPages' => 1,
|
|
'list' => array(),
|
|
'total' => $this -> total
|
|
);
|
|
|
|
if ($retval['total'] > 0) {
|
|
if (!$this->params['nbObjectsByPage']) {
|
|
$this->params['nbObjectsByPage'] = NB_LSOBJECT_LIST;
|
|
}
|
|
$retval['nbPages'] = ceil($retval['total'] / $this->params['nbObjectsByPage']);
|
|
|
|
$sortTable=$this -> getSortTable();
|
|
|
|
$list = array_slice(
|
|
$sortTable,
|
|
(($page - 1) * $this->params['nbObjectsByPage']),
|
|
$this->params['nbObjectsByPage']
|
|
);
|
|
|
|
foreach ($list as $key => $id) {
|
|
$retval['list'][] = new LSsearchEntry(
|
|
$this,
|
|
$this -> LSobject,
|
|
$this -> params,
|
|
$this -> result['list'],
|
|
$id
|
|
);
|
|
}
|
|
}
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* Get search entries
|
|
*
|
|
* @retval array The entries
|
|
**/
|
|
public function getSearchEntries() {
|
|
if (!LSsession::loadLSclass('LSsearchEntry')) {
|
|
LSerror::addErrorCode('LSsession_05',$this -> LSobject);
|
|
return;
|
|
}
|
|
$retval=array();
|
|
if ($this -> total>0) {
|
|
$sortTable=$this -> getSortTable();
|
|
|
|
foreach ($sortTable as $key => $id) {
|
|
$retval[] = new LSsearchEntry(
|
|
$this,
|
|
$this -> LSobject,
|
|
$this -> params,
|
|
$this -> result['list'],
|
|
$id
|
|
);
|
|
}
|
|
}
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* Access to information of this object
|
|
*
|
|
* @param[in] $key string The key of the info
|
|
*
|
|
* @retval mixed The info
|
|
**/
|
|
public function __get($key) {
|
|
$params = array (
|
|
'basedn',
|
|
'sortBy',
|
|
'sortDirection',
|
|
'attributes',
|
|
);
|
|
if ($key=='LSobject') {
|
|
return $this -> LSobject;
|
|
}
|
|
elseif (in_array($key,$params)) {
|
|
return $this -> params[$key];
|
|
}
|
|
elseif ($key=='label_objectName') {
|
|
return LSldapObject::getLabel($this -> LSobject);
|
|
}
|
|
elseif ($key=='label_level') {
|
|
return LSsession :: getSubDnLabel();
|
|
}
|
|
elseif ($key=='label_actions') {
|
|
return _('Actions');
|
|
}
|
|
elseif ($key=='label_no_result') {
|
|
return _("This search didn't get any result.");
|
|
}
|
|
elseif ($key=='sort') {
|
|
if (isset($this -> params['sortlimit']) && ($this -> params['sortlimit']>0)) {
|
|
return ($this -> total < $this -> params['sortlimit']);
|
|
}
|
|
return true;
|
|
}
|
|
elseif ($key=='sortlimit') {
|
|
return $this -> params['sortlimit'];
|
|
}
|
|
elseif ($key=='total') {
|
|
return count($this -> result['list']);
|
|
}
|
|
elseif ($key=='label_total') {
|
|
return $this -> total." ".$this -> label_objectName;
|
|
}
|
|
elseif ($key=='displaySubDn') {
|
|
if (LSsession :: subDnIsEnabled()) {
|
|
if (!is_null($this -> params[$key])) {
|
|
return $this -> params[$key];
|
|
}
|
|
else {
|
|
return (! LSsession :: isSubDnLSobject($this -> LSobject) );
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
elseif ($key=='canCopy') {
|
|
if (!is_null($this -> _canCopy))
|
|
return $this -> _canCopy;
|
|
$this -> _canCopy = LSsession :: canCreate($this -> LSobject);
|
|
return $this -> _canCopy;
|
|
}
|
|
elseif ($key=='predefinedFilters') {
|
|
$retval=array();
|
|
if (is_array($this -> config['predefinedFilters'])) {
|
|
foreach($this -> config['predefinedFilters'] as $filter => $label) {
|
|
$retval[$filter]=__($label);
|
|
}
|
|
}
|
|
return $retval;
|
|
}
|
|
elseif ($key=='extraDisplayedColumns') {
|
|
if ($this->params['extraDisplayedColumns'] && is_array($this -> config['extraDisplayedColumns'])) {
|
|
return $this -> config['extraDisplayedColumns'];
|
|
}
|
|
else {
|
|
return False;
|
|
}
|
|
}
|
|
elseif ($key=='visibleExtraDisplayedColumns') {
|
|
if ($this->params['extraDisplayedColumns'] && is_array($this -> config['extraDisplayedColumns'])) {
|
|
$ret=array();
|
|
foreach($this->config['extraDisplayedColumns'] as $col => $conf) {
|
|
if (isset($conf['visibleTo']) && !LSsession :: isLSprofiles($this -> basedn, $conf['visibleTo'])) {
|
|
continue;
|
|
}
|
|
$ret[$col]=$conf;
|
|
}
|
|
return $ret;
|
|
}
|
|
}
|
|
elseif ($key == 'hash') {
|
|
return $this -> getHash();
|
|
}
|
|
else {
|
|
throw new Exception("Incorrect property '$key'!");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function use with uasort to sort two entry
|
|
*
|
|
* @param[in] $a array One line of result
|
|
* @param[in] $b array One line of result
|
|
*
|
|
* @retval int Value for uasort
|
|
**/
|
|
private function _sortTwoEntry(&$a,&$b) {
|
|
$sortBy = $this -> params['sortBy'];
|
|
$sortDirection = $this -> params['sortDirection'];
|
|
if ($sortDirection=='ASC') {
|
|
$dir = 1;
|
|
}
|
|
else {
|
|
$dir = -1;
|
|
}
|
|
$oa = new LSsearchEntry($this, $this -> LSobject, $this -> params, $this -> result['list'], $a);
|
|
$va = $oa->$sortBy;
|
|
$ob = new LSsearchEntry($this, $this -> LSobject, $this -> params, $this -> result['list'], $b);
|
|
$vb = $ob->$sortBy;
|
|
|
|
if ($va == $vb) return 0;
|
|
|
|
$val = strnatcmp(strtolower($va), strtolower($vb));
|
|
return $val*$dir;
|
|
}
|
|
|
|
/**
|
|
* Function to run after using the result. It's update the cache
|
|
*
|
|
* IT'S FUNCTION IS VERY IMPORTANT !!!
|
|
*
|
|
* @retval void
|
|
**/
|
|
public function afterUsingResult() {
|
|
$this -> addResultToCache();
|
|
}
|
|
|
|
/**
|
|
* Redirect user to object view if the search have only one result
|
|
*
|
|
* @retval boolean True only if user have been redirected
|
|
**/
|
|
public function redirectWhenOnlyOneResult() {
|
|
if ($this -> total == 1 && $this -> result && self::formIsSubmited()) {
|
|
LSurl :: redirect('object/'.$this -> LSobject.'/'.urlencode($this -> result['list'][0]['dn']));
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Run the sort if it's enabled and if the result is not in the cache
|
|
*
|
|
* @retval boolean True on success or false
|
|
**/
|
|
private function doSort() {
|
|
if (!$this -> sort) {
|
|
self :: log_debug('doSort(): sort is disabled');
|
|
return true;
|
|
}
|
|
if (is_null($this -> params['sortBy'])) {
|
|
return;
|
|
}
|
|
if (is_null($this -> params['sortDirection'])) {
|
|
$this -> params['sortDirection']='ASC';
|
|
}
|
|
|
|
if ($this->total==0) {
|
|
return true;
|
|
}
|
|
|
|
if (isset($this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']])) {
|
|
self :: log_debug('doSort(): from cache');
|
|
return true;
|
|
}
|
|
|
|
self :: log_debug('doSort(): sort by "'.$this -> params['sortBy'].'" (order: '.$this -> params['sortDirection']).")";
|
|
|
|
$this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']]=range(0,($this -> total-1));
|
|
|
|
if (!LSsession :: loadLSClass('LSsearchEntry')) {
|
|
LSerror::addErrorCode('LSsession_05','LSsearchEntry');
|
|
return;
|
|
}
|
|
|
|
if (!uasort(
|
|
$this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']],
|
|
array($this,'_sortTwoEntry')
|
|
)) {
|
|
LSerror :: addErrorCode('LSsearch_13');
|
|
return;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the id of table rows in the result sorted according to criteria
|
|
* defined in the parameters
|
|
*
|
|
* @retval array The Table of id lines of results sorted
|
|
**/
|
|
public function getSortTable() {
|
|
if (isset($this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']])) {
|
|
return $this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']];
|
|
}
|
|
return range(0,($this -> total-1));
|
|
}
|
|
|
|
/**
|
|
* List LSsearchEntry objects
|
|
*
|
|
* @retval Array DN associate with name
|
|
**/
|
|
public function listEntries() {
|
|
if (!LSsession::loadLSclass('LSsearchEntry')) {
|
|
LSerror::addErrorCode('LSsession_05',$this -> LSobject);
|
|
return;
|
|
}
|
|
|
|
$retval=array();
|
|
|
|
if ($this -> total>0) {
|
|
$sortTable = $this -> getSortTable();
|
|
|
|
foreach ($sortTable as $key => $id) {
|
|
$entry = new LSsearchEntry(
|
|
$this,
|
|
$this -> LSobject,
|
|
$this -> params,
|
|
$this -> result['list'],
|
|
$id
|
|
);
|
|
$retval[$entry -> dn] = $entry;
|
|
}
|
|
}
|
|
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* List objects name
|
|
*
|
|
* @retval Array DN associate with name
|
|
**/
|
|
public function listObjectsName() {
|
|
$entries = $this -> listEntries();
|
|
if (!is_array($entries))
|
|
return;
|
|
$retval = array();
|
|
foreach($entries as $entry)
|
|
$retval[$entry -> dn] = $entry -> displayName;
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* List LSldapObjects
|
|
*
|
|
* @retval Array of LSldapObjects
|
|
**/
|
|
public function listObjects() {
|
|
$retval=array();
|
|
|
|
if ($this -> total>0) {
|
|
$sortTable=$this -> getSortTable();
|
|
|
|
$c=0;
|
|
foreach ($sortTable as $key => $id) {
|
|
$retval[$c]=new $this -> LSobject();
|
|
$retval[$c] -> loadData($this -> result['list'][$id]['dn']);
|
|
$c++;
|
|
}
|
|
}
|
|
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* List objects dn
|
|
*
|
|
* @retval Array of DN
|
|
**/
|
|
public function listObjectsDn() {
|
|
$retval=array();
|
|
|
|
if ($this -> total>0) {
|
|
$sortTable=$this -> getSortTable();
|
|
|
|
$c=0;
|
|
foreach ($sortTable as $key => $id) {
|
|
$retval[$c] = $this -> result['list'][$id]['dn'];
|
|
$c++;
|
|
}
|
|
}
|
|
|
|
return $retval;
|
|
}
|
|
|
|
/**
|
|
* CLI search command
|
|
*
|
|
* @param[in] $command_args array Command arguments :
|
|
* - Positional arguments :
|
|
* - LSobject type
|
|
* - patterns
|
|
* - Optional arguments :
|
|
* - -f|--filter : LDAP filter string
|
|
* - -b|--basedn : LDAP base DN
|
|
* - -s|--scope : LDAP search scope (sub, one, base)
|
|
* - -l|--limit : search result size limit
|
|
* - -a|--approx : approximative search on provided pattern
|
|
* - -r|--recursive : recursive search
|
|
* - --sort-by : Sort by specific attribute/column
|
|
* - -R|--reverse : reverse search result
|
|
* - --sort-limit : Sort limit (in number of objects found)
|
|
* - --display-subdn : Display subDn in result
|
|
* - --display-format : Display format of objectName
|
|
* - -N|--nb-obj-by-page : number of object by page
|
|
* - -W|--without-cache : Disable cache
|
|
* - -e|--extra-columns : Display extra columns
|
|
* - -p|--page : page number to show (starting by 1, default: first one)
|
|
*
|
|
* @retval boolean True on succes, false otherwise
|
|
**/
|
|
public static function cli_search($command_args) {
|
|
$objType = null;
|
|
$patterns = array();
|
|
$params = array(
|
|
'sortDirection' => 'ASC',
|
|
'extraDisplayedColumns' => false,
|
|
);
|
|
$page_nb = 1;
|
|
$all = false;
|
|
$json = false;
|
|
$pretty = false;
|
|
for ($i=0; $i < count($command_args); $i++) {
|
|
switch ($command_args[$i]) {
|
|
case '-f':
|
|
case '--filter':
|
|
$params['filter'] = $command_args[++$i];
|
|
break;
|
|
case '-b':
|
|
case '--basedn':
|
|
$params['basedn'] = $command_args[++$i];
|
|
break;
|
|
case '-s':
|
|
case '--scope':
|
|
$params['scope'] = $command_args[++$i];
|
|
break;
|
|
case '-s':
|
|
case '--scope':
|
|
$params['scope'] = $command_args[++$i];
|
|
break;
|
|
case '-l':
|
|
case '--limit':
|
|
$params['sizelimit'] = intval($command_args[++$i]);
|
|
break;
|
|
case '-a':
|
|
case '--approx':
|
|
$params['approx'] = true;
|
|
break;
|
|
case '-r':
|
|
case '--recursive':
|
|
$params['recursive'] = true;
|
|
break;
|
|
case '--sort-by':
|
|
$params['sortBy'] = $command_args[++$i];
|
|
break;
|
|
case '-R':
|
|
case '--reverse':
|
|
$params['sortDirection'] = 'DESC';
|
|
break;
|
|
case '--sort-limit':
|
|
$params['sortlimit'] = intval($command_args[++$i]);
|
|
break;
|
|
case '--sort-limit':
|
|
$params['sortlimit'] = intval($command_args[++$i]);
|
|
break;
|
|
case '--display-subdn':
|
|
$params['displaySubDn'] = true;
|
|
break;
|
|
case '--display-format':
|
|
$params['displayFormat'] = boolval($command_args[++$i]);
|
|
break;
|
|
case '-N':
|
|
case '--nb-obj-by-page':
|
|
$params['nbObjectsByPage'] = intval($command_args[++$i]);
|
|
break;
|
|
case '-W':
|
|
case '--without-cache':
|
|
$params['withoutCache'] = True;
|
|
break;
|
|
case '-e':
|
|
case '--extra-columns':
|
|
$params['extraDisplayedColumns'] = True;
|
|
break;
|
|
case '-p':
|
|
case '--page':
|
|
$page_nb = intval($command_args[++$i]);
|
|
break;
|
|
case '--all':
|
|
$all = true;
|
|
break;
|
|
case '-j':
|
|
case '--json':
|
|
$json = true;
|
|
break;
|
|
case '--pretty':
|
|
$pretty = true;
|
|
break;
|
|
default:
|
|
if (is_null($objType)) {
|
|
$objType = $command_args[$i];
|
|
}
|
|
elseif (substr($command_args[$i], 0, 1) == '-') {
|
|
LScli :: usage("Invalid parameter '".$command_args[$i]."'");
|
|
}
|
|
else {
|
|
$patterns[] = $command_args[$i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_null($objType))
|
|
LScli :: usage('You must provide LSobject type.');
|
|
|
|
// Load Console Table lib
|
|
$console_table_path = LSconfig :: get('ConsoleTable', 'Console/Table.php', 'string');
|
|
if (!LSsession :: includeFile($console_table_path, true))
|
|
self :: log_fatal('Fail to load ConsoleTable library.');
|
|
|
|
if (!empty($patterns))
|
|
$params['pattern'] = implode(' ', $patterns);
|
|
|
|
$search = new LSsearch($objType, 'CLI', array(), true);
|
|
|
|
// Set search params
|
|
self :: log_debug('Search parameters : '.varDump($params));
|
|
if (!$search -> setParams($params))
|
|
self :: log_fatal('Fail to set search parameters.');
|
|
|
|
// Run search
|
|
if (!$search -> run())
|
|
self :: log_fatal('Fail to run search.');
|
|
|
|
|
|
if ($all) {
|
|
$entries = $search -> listEntries();
|
|
if (!is_array($entries))
|
|
self :: log_fatal("Fail to retreive search result");
|
|
}
|
|
else {
|
|
// Retrieve page
|
|
$page = $search -> getPage($page_nb);
|
|
/*
|
|
* $page = array(
|
|
* 'nb' => $page,
|
|
* 'nbPages' => 1,
|
|
* 'list' => array(),
|
|
* 'total' => $this -> total
|
|
* );
|
|
*/
|
|
|
|
// Check page
|
|
if (!is_array($page) || $page_nb > $page['nbPages'])
|
|
self :: log_fatal("Fail to retreive page #$page_nb.");
|
|
}
|
|
|
|
// Handle JSON output
|
|
if ($json) {
|
|
$export = array(
|
|
'objects' => array(),
|
|
'total' => $search -> total,
|
|
);
|
|
if (!$all) {
|
|
$export['page'] = $page['nb'];
|
|
$export['nbPages'] = $page['nbPages'];
|
|
}
|
|
foreach(($all?$entries:$page['list']) as $obj) {
|
|
$export['objects'][$obj -> dn] = array(
|
|
'name' => $obj -> displayName,
|
|
);
|
|
if ($search -> displaySubDn)
|
|
$export['objects'][$obj -> dn][$search -> label_level] = $obj -> subDn;
|
|
if ($search -> extraDisplayedColumns) {
|
|
foreach ($search -> visibleExtraDisplayedColumns as $cid => $conf) {
|
|
$export['objects'][$obj -> dn][$conf['label']] = $obj -> $cid;
|
|
}
|
|
}
|
|
}
|
|
$output = json_encode($export, ($pretty?JSON_PRETTY_PRINT:0));
|
|
if ($output === false) {
|
|
self :: log_error("Fail to encode data as JSON");
|
|
exit(1);
|
|
}
|
|
echo $output;
|
|
exit(0);
|
|
}
|
|
|
|
if (empty($all?$entries:$page['list'])) {
|
|
echo "No $objType object found.\n";
|
|
exit(0);
|
|
}
|
|
|
|
// Create result table with its header
|
|
$tbl = new Console_Table();
|
|
$headers = array('DN', 'Name');
|
|
if ($search -> displaySubDn)
|
|
$headers[] = $search -> label_level;
|
|
if ($search -> extraDisplayedColumns) {
|
|
foreach ($search -> visibleExtraDisplayedColumns as $cid => $conf) {
|
|
$headers[] = $conf['label'];
|
|
}
|
|
}
|
|
$tbl->setHeaders($headers);
|
|
|
|
// Add one line for each object found (in page)
|
|
foreach($all?$entries:$page['list'] as $obj) {
|
|
$row = array(
|
|
$obj -> dn,
|
|
$obj -> displayName,
|
|
);
|
|
if ($search -> displaySubDn)
|
|
$row[] = $obj -> subDn;
|
|
if ($search -> extraDisplayedColumns) {
|
|
foreach ($search -> visibleExtraDisplayedColumns as $cid => $conf) {
|
|
$row[] = $obj -> $cid;
|
|
}
|
|
}
|
|
$tbl->addRow($row);
|
|
}
|
|
echo $tbl->getTable();
|
|
if ($all)
|
|
echo "Total: ".$search -> total."\n";
|
|
else
|
|
echo "Page ".($page['nb'])." on ".$page['nbPages']." / Total: ".$search -> total."\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Args autocompleter for CLI command search
|
|
*
|
|
* @param[in] $command_args array List of already typed words of the command
|
|
* @param[in] $comp_word_num int The command word number to autocomplete
|
|
* @param[in] $comp_word string The command word to autocomplete
|
|
* @param[in] $opts array List of global available options
|
|
*
|
|
* @retval array List of available options for the word to autocomplete
|
|
**/
|
|
public static function cli_search_args_autocompleter($command_args, $comp_word_num, $comp_word, $opts) {
|
|
$command_opts = array (
|
|
'-f', '--filter',
|
|
'-b', '--basedn',
|
|
'-s', '--scope',
|
|
'-l', '--limit',
|
|
'-a', '--approx',
|
|
'-r', '--recursive',
|
|
'--sort-by',
|
|
'-R', '--reverse',
|
|
'--sort-limit',
|
|
'--display-subdn',
|
|
'--display-format',
|
|
'-N', '--nb-obj-by-page',
|
|
'-W', '--without-cache',
|
|
'-e', '--extra-columns',
|
|
'-p', '--page',
|
|
'--all',
|
|
'-j', '--json', '--pretty',
|
|
);
|
|
|
|
// Detect positional args
|
|
$objType = null;
|
|
$objType_arg_num = null;
|
|
$patterns = array();
|
|
$extra_columns = false;
|
|
for ($i=0; $i < count($command_args); $i++) {
|
|
if (!in_array($command_args[$i], $command_opts) || in_array($command_args[$i], $opts)) {
|
|
// If object type not defined
|
|
if (is_null($objType)) {
|
|
// Check object type exists
|
|
$objTypes = LScli :: autocomplete_LSobject_types($command_args[$i]);
|
|
|
|
// Load it if exist and not trying to complete it
|
|
if (in_array($command_args[$i], $objTypes) && $i != $comp_word_num) {
|
|
LSsession :: loadLSobject($command_args[$i], false);
|
|
}
|
|
|
|
// Defined it
|
|
$objType = $command_args[$i];
|
|
$objType_arg_num = $i;
|
|
}
|
|
else
|
|
$patterns[] = $command_args[$i];
|
|
}
|
|
else {
|
|
switch ($command_args[$i]) {
|
|
case '-s':
|
|
case '--scope':
|
|
case '-f':
|
|
case '--filter':
|
|
case '-b':
|
|
case '--basedn':
|
|
case '-l':
|
|
case '--limit':
|
|
case '--sort-limit':
|
|
case '-N':
|
|
case '--nb-obj-by-page':
|
|
case '-p':
|
|
case '--page':
|
|
case '--sort-by':
|
|
// This args accept options => increase $i
|
|
$i++;
|
|
break;
|
|
case '-e':
|
|
case '--extra-columns':
|
|
$extra_columns = true;
|
|
LSlog :: debug('Extra columns enabled');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle completion of args value
|
|
LSlog :: debug("Last complete word = '".$command_args[$comp_word_num-1]."'");
|
|
switch ($command_args[$comp_word_num-1]) {
|
|
case '-s':
|
|
case '--scope':
|
|
return LScli :: autocomplete_opts(array('sub', 'one', 'base'), $comp_word);
|
|
case '-f':
|
|
case '--filter':
|
|
case '-b':
|
|
case '--basedn':
|
|
// This args need string value that can't be autocomplete: stop autocompletion
|
|
return array();
|
|
case '-l':
|
|
case '--limit':
|
|
case '--sort-limit':
|
|
case '-N':
|
|
case '--nb-obj-by-page':
|
|
case '-p':
|
|
case '--page':
|
|
return LScli :: autocomplete_int($comp_word);
|
|
case '--sort-by':
|
|
$bys = array('displayName', 'subDn');
|
|
if ($objType && $extra_columns) {
|
|
$extraDisplayedColumns = LSconfig::get("LSobjects.$objType.LSsearch.extraDisplayedColumns", array());
|
|
if (is_array($extraDisplayedColumns))
|
|
$bys = array_merge($bys, array_keys($extraDisplayedColumns));
|
|
}
|
|
LSlog :: debug('Available sort-bys clauses: '.implode(', ', $bys));
|
|
return LScli :: autocomplete_opts($bys, $comp_word);
|
|
}
|
|
$opts = array_merge($opts, $command_opts);
|
|
|
|
// If objType not already choiced (or currently autocomplete), add LSobject types to available options
|
|
if (!$objType || $objType_arg_num == $comp_word_num)
|
|
$opts = array_merge($opts, LScli :: autocomplete_LSobject_types($comp_word));
|
|
|
|
return LScli :: autocomplete_opts($opts, $comp_word);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Error Codes
|
|
**/
|
|
LSerror :: defineError('LSsearch_01',
|
|
___("LSsearch : Invalid filter : %{filter}.")
|
|
);
|
|
LSerror :: defineError('LSsearch_02',
|
|
___("LSsearch : Invalid basedn : %{basedn}.")
|
|
);
|
|
LSerror :: defineError('LSsearch_03',
|
|
___("LSsearch : Invalid value for %{param} parameter.")
|
|
);
|
|
LSerror :: defineError('LSsearch_04',
|
|
___("LSsearch : Invalid size limit. Must be an integer greater or equal to 0.")
|
|
);
|
|
LSerror :: defineError('LSsearch_05',
|
|
___("LSsearch : Invalid parameter %{attr}. Must be an boolean.")
|
|
);
|
|
LSerror :: defineError('LSsearch_06',
|
|
___("LSsearch : Invalid parameter attributes. Must be an string or an array of strings.")
|
|
);
|
|
LSerror :: defineError('LSsearch_07',
|
|
___("LSsearch : Can't build attributes list for make filter.")
|
|
);
|
|
LSerror :: defineError('LSsearch_08',
|
|
___("LSsearch : Error building filter with attribute '%{attr}' and pattern '%{pattern}'")
|
|
);
|
|
LSerror :: defineError('LSsearch_09',
|
|
___("LSsearch : Error combining filters.")
|
|
);
|
|
LSerror :: defineError('LSsearch_10',
|
|
___("LSsearch : Invalid pattern.")
|
|
);
|
|
LSerror :: defineError('LSsearch_11',
|
|
___("LSsearch : Invalid attribute %{attr} in parameters.")
|
|
);
|
|
LSerror :: defineError('LSsearch_12',
|
|
___("LSsearch : Error during the search.")
|
|
);
|
|
LSerror :: defineError('LSsearch_13',
|
|
___("LSsearch : Error sorting the search.")
|
|
);
|
|
LSerror :: defineError('LSsearch_14',
|
|
___("LSsearch : The function of the custum information %{name} is not callable.")
|
|
);
|
|
LSerror :: defineError('LSsearch_15',
|
|
___("LSsearch : Invalid predefinedFilter for LSobject type %{type} : %{label} (filter : %{filter}).")
|
|
);
|
|
LSerror :: defineError('LSsearch_16',
|
|
___("LSsearch : Error during execution of the custom action %{customAction}.")
|
|
);
|
|
LSerror :: defineError('LSsearch_17',
|
|
___("LSsearch : Invalid search pattern.")
|
|
);
|
|
|
|
// LScli
|
|
LScli :: add_command(
|
|
'search',
|
|
array('LSsearch', 'cli_search'),
|
|
'Search LSobject',
|
|
'[object type] [pattern1] [pattern2 ...]',
|
|
array(
|
|
' - Positional arguments :',
|
|
' - LSobject type',
|
|
' - patterns',
|
|
'',
|
|
' - Optional arguments :',
|
|
' - -f|--filter : LDAP filter string',
|
|
' - -b|--basedn : LDAP base DN',
|
|
' - -s|--scope : LDAP search scope (sub, one, base)',
|
|
' - -l|--limit : search result size limit',
|
|
' - -a|--approx : approximative search on provided pattern',
|
|
' - -r|--recursive : recursive search',
|
|
' - --sort-by : Sort by specific attribute/column',
|
|
' - -R|--reverse : reverse search result',
|
|
' - --sort-limit : Sort limit (in number of objects found)',
|
|
' - --display-subdn : Display subDn in result',
|
|
' - --display-format : Display format of objectName',
|
|
' - -N|--nb-obj-by-page : number of object by page',
|
|
' - -W|--without-cache : Disable cache',
|
|
' - -e|--extra-columns : Display extra columns',
|
|
' - -p|--page : page number to show (starting by 1, default: first one)',
|
|
' - --all : list all matching objects (no pagination)',
|
|
' - -j|--json : JSON output',
|
|
' - --pretty : prettify the JSON output',
|
|
),
|
|
true,
|
|
array('LSsearch', 'cli_search_args_autocompleter')
|
|
);
|