diff --git a/src/includes/class/class.LSattr_html_select_object.php b/src/includes/class/class.LSattr_html_select_object.php
index 29490b67..2a3a66dc 100644
--- a/src/includes/class/class.LSattr_html_select_object.php
+++ b/src/includes/class/class.LSattr_html_select_object.php
@@ -174,8 +174,8 @@ class LSattr_html_select_object extends LSattr_html{
*
* @param mixed $values array|null Array of the input values ()
* @param boolean $fromDNs boolean If true, considered provided values as DNs (default: false)
- * @param boolean $retrieveAttrValues boolean If true, attribute values will be returned instead
- * of selected objects info (default: false)
+ * @param boolean $retrieveAttrValues boolean If true, final attribute values will be returned
+ * instead of selected objects info (default: false)
*
* @author Benjamin Renard
*
@@ -193,139 +193,166 @@ class LSattr_html_select_object extends LSattr_html{
self :: log_warning('getFormValues(): $values is not array');
return false;
}
+ if (!LSsession :: loadLSclass("LSsearch"))
+ return false;
// Retrieve/check selectable objects config
- $objs = array();
+ $objs = [];
$confs = $this -> getSelectableObjectsConfig($objs);
if (!is_array($confs) || empty($confs)) {
self :: log_warning('getFormValues(): invalid selectable objects config');
return false;
}
- $selected_objects = array();
- $unrecognizedValues = array();
- $found_values = array();
+ $selected_objects = [];
+ $found_values = [];
+ $unrecognizedValues = [];
foreach ($confs as $conf) {
+ $common_search_params = [
+ "filter" => $conf['filter'],
+ "attributes" => (
+ $retrieveAttrValues && !in_array($conf['value_attribute'], ["dn", "%{dn}"])?
+ [$conf['value_attribute']]:
+ [$objs[$conf['object_type']]->rdn_attr]
+ ),
+ "displayFormat" => (
+ $conf['display_name_format']?
+ $conf['display_name_format']:
+ $objs[$conf['object_type']] -> getDisplayNameFormat()
+ ),
+ ];
foreach($values as $value) {
- // If we already mark its value as unrecognized, pass
- if (in_array($value, $unrecognizedValues))
+ // Ignore empty value and value already marked as unrecognized
+ if (empty($value) || in_array($value, $unrecognizedValues))
continue;
- // Ignore empty value
- if (empty($value))
- continue;
-
- // Determine value attribute: DN/attribute valued (or force form DNs)
- if(($conf['value_attribute']=='dn') || ($conf['value_attribute']=='%{dn}') || $fromDNs) {
- // Construct resulting list from DN values
- if ($conf['onlyAccessible']) {
- if (!LSsession :: canAccess($conf['object_type'], $value)) {
- self :: log_debug("getFormValues(): ".$conf['object_type']."($value): not accessible, pass");
- continue;
- }
- }
-
- // Load object data (with custom filter if defined)
- if(!$objs[$conf['object_type']] -> loadData($value, $conf['filter'])) {
- self :: log_debug("getFormValues(): ".$conf['object_type']."($value): not found, pass");
+ // Compute search params based on value attribute type (DN or attribute valued) and $fromDNs
+ if($fromDNs || in_array($conf['value_attribute'], ['dn', '%{dn}'])) {
+ if ($conf['onlyAccessible'] && !LSsession :: canAccess($conf['object_type'], $value)) {
+ self :: log_debug(
+ "getFormValues(): object {$conf['object_type']} '$value' is not accessible, pass"
+ );
continue;
}
- self :: log_debug("getFormValues(): ".$conf['object_type']."($value): found");
+ $search_params = array_merge(
+ $common_search_params,
+ ["basedn" => $value, "scope" => "base"]
+ );
+ }
+ else {
+ $filter = Net_LDAP2_Filter::create($conf['value_attribute'], 'equals', $value);
+ $search_params = array_merge(
+ $common_search_params,
+ [
+ "filter" => (
+ $common_search_params["filter"]?
+ LSldap::combineFilters('and', [$common_search_params["filter"], $filter]):
+ $filter
+ ),
+ ]
+ );
+ }
- // Check if it's the first this value match with an object
- if (isset($found_values[$value])) {
- // DN match with multiple object type
- LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name));
- $unrecognizedValues[] = $value;
- unset($selected_objects[$found_values[$value]]);
- break;
- }
- $found_values[$value] = $value;
+ // Search object
+ $LSsearch = new LSsearch(
+ $conf['object_type'],
+ 'LSattr_html_select_object::getFormValues',
+ $search_params,
+ true
+ );
- if ($retrieveAttrValues) {
- // Retrieve attribute value case: $selected_objects[dn] = attribute value
- if(($conf['value_attribute']=='dn') || ($conf['value_attribute']=='%{dn}')) {
- $selected_objects[$value] = $value;
- }
- else {
- $val = $objs[$conf['object_type']] -> getValue($conf['value_attribute']);
- if (!empty($val)) {
- $selected_objects[$value] = $val[0];
- }
- else {
- LSerror :: addErrorCode(
- 'LSattr_html_select_object_06',
- array(
- 'name' => $objs[$conf['object_type']] -> getDisplayName($conf['display_name_format']),
- 'attr' => $this -> name
- )
- );
- }
- }
+ if(!$LSsearch -> run(false)) {
+ self :: log_warning(
+ "getFormValues(): error during search of object(s) {$conf['object_type']} ".
+ "for value '$value', pass"
+ );
+ continue;
+ }
+
+ $entries = $LSsearch -> listEntries();
+ if (!is_array($entries) || empty($entries)) {
+ self :: log_debug(
+ "getFormValues(): value '$value' not found as {$conf['object_type']}, pass"
+ );
+ continue;
+ }
+
+ if (count($entries) > 1) {
+ self :: log_warning(
+ "getFormValues(): ".count($entries)." objects {$conf['object_type']} found ".
+ "for value '$value', pass: ".implode(" / ", array_keys($entries))
+ );
+ if (array_key_exists($value, $selected_objects))
+ unset($selected_objects[$value]);
+ $unrecognizedValues[] = $value;
+ $found_values[$value] = (
+ array_key_exists($value, $found_values)?
+ array_merge($found_values[$value], array_keys($entries)):
+ array_keys($entries)
+ );
+ break;
+ }
+ $entry = $entries[key($entries)];
+ self :: log_debug(
+ "getFormValues(): value '$value' found as {$conf['object_type']}: {$entry->dn}"
+ );
+
+ // Check if it's the first this value match with an object
+ if (array_key_exists($value, $found_values)) {
+ // DN match with multiple object type
+ LSerror :: addErrorCode(
+ 'LSattr_html_select_object_03',
+ ['val' => $value, 'attribute' => $this -> name]
+ );
+ unset($selected_objects[$value]);
+ $unrecognizedValues[] = $value;
+ $found_values[$value][] = $entry->dn;
+ break;
+ }
+ $found_values[$value] = [$entry->dn];
+
+ if ($retrieveAttrValues) {
+ // Retrieve attribute value case: $selected_objects[dn] = attribute value
+ if(($conf['value_attribute']=='dn') || ($conf['value_attribute']=='%{dn}')) {
+ $selected_objects[$value] = $entry->dn;
}
else {
- // General case: $selected_objects[dn] = array(name + object_type)
- $selected_objects[$value] = array(
- 'name' => $objs[$conf['object_type']] -> getDisplayName($conf['display_name_format']),
- 'object_type' => $conf['object_type'],
- );
- self :: log_debug("getFormValues(): ".$conf['object_type']."($value): ".varDump($selected_objects[$value]));
+ $val = ensureIsArray($entry -> get($conf['value_attribute']));
+ if (!empty($val)) {
+ $selected_objects[$value] = $val[0];
+ }
+ else {
+ LSerror :: addErrorCode(
+ 'LSattr_html_select_object_06',
+ array(
+ 'name' => $entry -> displayName,
+ 'attr' => $this -> name
+ )
+ );
+ }
}
}
else {
- // Construct resulting list from attributes values
- $filter = Net_LDAP2_Filter::create($conf['value_attribute'], 'equals', $value);
- if (isset($conf['filter']))
- $filter = LSldap::combineFilters('and', array($filter, $conf['filter']));
- $sparams = array();
- $sparams['onlyAccessible'] = $conf['onlyAccessible'];
- $listobj = $objs[$conf['object_type']] -> listObjectsName(
- $filter,
- NULL,
- $sparams,
- $conf['display_name_format']
+ // General case: $selected_objects[dn] = array(name + object_type)
+ $selected_objects[$value] = array(
+ 'name' => $entry -> displayName,
+ 'object_type' => $conf['object_type'],
+ );
+ self :: log_debug(
+ "getFormValues(): object {$conf['object_type']} info for value '$value': ".
+ varDump($selected_objects[$value])
);
- if (count($listobj)==1) {
- if (isset($found_values[$value])) {
- // Value match with multiple object type
- LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name));
- $unrecognizedValues[] = $value;
- unset($selected_objects[$found_values[$value]]);
- break;
- }
- $dn = key($listobj);
- $selected_objects[$dn] = array(
- 'name' => $listobj[$dn],
- 'object_type' => $conf['object_type'],
- );
- $found_values[$value] = $dn;
- }
- else if(count($listobj) > 1) {
- LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name));
- if (!in_array($value, $unrecognizedValues))
- $unrecognizedValues[] = $value;
- break;
- }
}
}
}
- // Check if all values have been found (or already considered as unrecognized)
- foreach ($values as $value) {
- if (!isset($found_values[$value]) && !in_array($value, $unrecognizedValues)) {
- self :: log_debug("getFormValues(): value '$value' not recognized");
- $unrecognizedValues[] = $value;
- }
- }
-
// Retrieve attribute values case: return forged array values (list of attribute values)
if ($retrieveAttrValues)
return array_values($selected_objects);
// General case
- self :: log_debug("getFormValues(): unrecognizedValues=".varDump($unrecognizedValues));
- $this -> unrecognizedValues = $unrecognizedValues;
-
+ $this -> unrecognizedValues = array_diff($values, array_keys($selected_objects));
+ self :: log_debug("getFormValues(): unrecognizedValues=".varDump($this -> unrecognizedValues));
self :: log_debug("getFormValues(): final values=".varDump($selected_objects));
return $selected_objects;
}
@@ -347,7 +374,7 @@ class LSattr_html_select_object extends LSattr_html{
/**
- * Return array of atttribute values form array of form values
+ * Return array of attribute values form array of form values
*
* @param mixed $values Array of form values
*
diff --git a/src/includes/class/class.LSformElement_select_object.php b/src/includes/class/class.LSformElement_select_object.php
index fddd912b..c8702b76 100644
--- a/src/includes/class/class.LSformElement_select_object.php
+++ b/src/includes/class/class.LSformElement_select_object.php
@@ -140,7 +140,8 @@ class LSformElement_select_object extends LSformElement {
$this -> attr_html -> getLSselectId(),
$select_conf,
boolval($this -> getParam('multiple', 0, 'int')),
- $this -> values
+ $this -> values,
+ false
);
return True;
}
diff --git a/src/includes/class/class.LSldap.php b/src/includes/class/class.LSldap.php
index b1a3a555..31c84627 100644
--- a/src/includes/class/class.LSldap.php
+++ b/src/includes/class/class.LSldap.php
@@ -462,8 +462,17 @@ class LSldap extends LSlog_staticLoggerClass {
*
* @return boolean True if entry exists, false otherwise
*/
- public static function exists($dn) {
- return is_a(self :: getLdapEntry($dn), 'Net_LDAP2_Entry');
+ public static function exists($dn, $filter=null) {
+ $entry = self :: search(
+ $filter?$filter:"(objectClass=*)",
+ $dn,
+ [
+ "scope" => "base",
+ "attronly" => true,
+ "attributes" => ["objectClass"],
+ ]
+ );
+ return boolval($entry);
}
/**
diff --git a/src/includes/class/class.LSldapObject.php b/src/includes/class/class.LSldapObject.php
index ff385a19..22c2cabb 100644
--- a/src/includes/class/class.LSldapObject.php
+++ b/src/includes/class/class.LSldapObject.php
@@ -149,6 +149,23 @@ class LSldapObject extends LSlog_staticLoggerClass {
}
}
+ /**
+ * Check if the specified object exists
+ * @param string $dn Object's DN
+ * @param string|Net_LDAP2_Filter|null $filter Extra LDAP that object must match (optional, default: null)
+ * @return bool
+ */
+ public static function exists($dn, $filter=null) {
+ return LSldap::exists(
+ $dn,
+ (
+ $filter?
+ LSldap::combineFilters("and", [static :: _getObjectFilter(), $filter]):
+ static :: _getObjectFilter()
+ )
+ );
+ }
+
/**
* Load object data from LDAP
*
@@ -901,40 +918,43 @@ class LSldapObject extends LSlog_staticLoggerClass {
}
/**
- * Retourne le filtre correpondants aux objetcClass de l'objet courant
+ * Return LDAP filter string of the current object type
*
* @author Benjamin Renard
*
- * @return Net_LDAP2_Filter le filtre ldap correspondant au type de l'objet
+ * @return Net_LDAP2_Filter LDAP filter as a Net_LDAP2_Filter object, or false in case of error
*/
public function getObjectFilter() {
return self :: _getObjectFilter($this -> type_name);
}
/**
- * Retourne le filtre correpondants aux objetcClass de l'objet
+ * Return object type LDAP filter string
+ *
+ * @param string|null $type Object type (optional, default: called class)
*
* @author Benjamin Renard
*
- * @return Net_LDAP2_Filter|false le filtre ldap correspondant au type de l'objet, ou false
+ * @return Net_LDAP2_Filter|false LDAP filter as a Net_LDAP2_Filter object, or false in case of error
*/
- public static function _getObjectFilter($type) {
- $oc=LSconfig::get("LSobjects.$type.objectclass");
- if(!is_array($oc)) return false;
- $filters=array();
+ public static function _getObjectFilter($type=null) {
+ $type = $type?$type:get_called_class();
+ $oc = LSconfig::get("LSobjects.$type.objectclass");
+ if(!is_array($oc) || !$oc) return false;
+ $filters = [];
foreach ($oc as $class) {
- $filters[]=Net_LDAP2_Filter::create('objectClass','equals',$class);
+ $filters[] = Net_LDAP2_Filter::create('objectClass', 'equals', $class);
}
- $filter=LSconfig::get("LSobjects.$type.filter");
+ $filter = LSconfig::get("LSobjects.$type.filter");
if ($filter) {
- $filters[]=Net_LDAP2_Filter::parse($filter);
+ $filters[] = Net_LDAP2_Filter::parse($filter);
}
- $filter = LSldap::combineFilters('and',$filters);
+ $filter = LSldap::combineFilters('and', $filters);
if ($filter)
return $filter;
- LSerror :: addErrorCode('LSldapObject_30',$type);
+ LSerror :: addErrorCode('LSldapObject_30', $type);
return false;
}
diff --git a/src/includes/class/class.LSselect.php b/src/includes/class/class.LSselect.php
index 4f12b8f5..5f47fb38 100644
--- a/src/includes/class/class.LSselect.php
+++ b/src/includes/class/class.LSselect.php
@@ -51,9 +51,10 @@ class LSselect extends LSlog_staticLoggerClass {
* @param boolean $multiple True if this selection permit to select more than one object, False otherwise (optional,
* default: false)
* @param array|null $current_selected_objects Array of current selected objects (optional, see setSelectedObjects for format specification)
+ * @param bool $check_objects Check selected objects (optional, default: true)
* @return void
*/
- public static function init($id, $LSobjects, $multiple=false, $current_selected_objects=null) {
+ public static function init($id, $LSobjects, $multiple=false, $current_selected_objects=null, $check_objects=true) {
if ( !isset($_SESSION['LSselect']) || !is_array($_SESSION['LSselect']))
$_SESSION['LSselect'] = array();
$_SESSION['LSselect'][$id] = array (
@@ -62,8 +63,11 @@ class LSselect extends LSlog_staticLoggerClass {
'selected_objects' => array(),
);
if (is_array($current_selected_objects))
- self :: setSelectedObjects($id, $current_selected_objects);
- self :: log_debug("Initialized with id=$id: multiple=".($multiple?'yes':'no')." ".count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s).");
+ self :: setSelectedObjects($id, $current_selected_objects, $check_objects);
+ self :: log_debug(
+ "Initialized with id=$id: multiple=".($multiple?'yes':'no')." ".
+ count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s)."
+ );
}
/**
@@ -216,6 +220,7 @@ class LSselect extends LSlog_staticLoggerClass {
* @param array $selected_objects Array of selectable object info with objects's DN
* as key and array of object's info as value. Objects's
* info currently contains only the object type (key=object_type).
+ * @param bool $check_objects Check selected objects (optional, default: true)
*
* @return array|false Array of selectable object info with objects's DN as key
* and array of object's info as value. Objects's info returned
@@ -224,24 +229,37 @@ class LSselect extends LSlog_staticLoggerClass {
*
* @return void
*/
- public static function setSelectedObjects($id, $selected_objects) {
+ public static function setSelectedObjects($id, $selected_objects, $check_objects=true) {
if (!self :: exists($id))
return;
if (!is_array($selected_objects))
return;
- $_SESSION['LSselect'][$id]['selected_objects'] = array();
+ $previously_selected = $_SESSION['LSselect'][$id]['selected_objects'];
+ $_SESSION['LSselect'][$id]['selected_objects'] = [];
foreach($selected_objects as $dn => $info) {
if (!is_array($info) || !isset($info['object_type'])) {
self :: log_warning("setSelectedObjects($id): invalid object info for dn='$dn'");
continue;
}
- if (self :: checkObjectIsSelectable($id, $info['object_type'], $dn))
- $_SESSION['LSselect'][$id]['selected_objects'][$dn] = $info;
- else {
- self :: log_warning("setSelectedObjects($id): object type='".$info['object_type']."' and dn='$dn' is not selectable".varDump($_SESSION['LSselect'][$id]));
+ if (
+ $check_objects
+ && !(
+ in_array($dn, $previously_selected)
+ || self :: checkObjectIsSelectable($id, $info['object_type'], $dn)
+ )
+ ) {
+ self :: log_warning(
+ "setSelectedObjects($id): object type='{$info['object_type']}' and dn='$dn' is not ".
+ "selectable"
+ );
+ continue;
}
+ $_SESSION['LSselect'][$id]['selected_objects'][$dn] = $info;
}
- self :: log_debug("id=$id: updated with ".count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s).");
+ self :: log_debug(
+ "setSelectedObjects($id): updated with ".
+ count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s)."
+ );
}
/**
@@ -250,29 +268,46 @@ class LSselect extends LSlog_staticLoggerClass {
* @param string $id The LSselect ID
* @param string $object_type The object type
* @param string $object_dn The object DN
+ * @param bool $check_exists Check if object exists in LDAP (optional, default: true)
*
* @return boolean True if object is selectable, false otherwise
*/
- public static function checkObjectIsSelectable($id, $object_type, $object_dn) {
+ public static function checkObjectIsSelectable($id, $object_type, $object_dn, $check_exists=true) {
if (!self :: exists($id)) {
- self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): LSselect $id doesn't exists");
+ self :: log_warning(
+ "checkObjectIsSelectable($id, $object_type, $object_dn): LSselect $id doesn't exists"
+ );
return false;
}
if (!array_key_exists($object_type, $_SESSION['LSselect'][$id]['LSobjects'])) {
- self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): object type $object_type not selectabled");
+ self :: log_warning(
+ "checkObjectIsSelectable($id, $object_type, $object_dn): object type $object_type not ".
+ "selectable"
+ );
return false;
}
// Load LSobject type
if ( !LSsession :: loadLSobject($object_type) ) {
- self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): fail to load object type $object_type");
+ self :: log_warning(
+ "checkObjectIsSelectable($id, $object_type, $object_dn): fail to load object type ".
+ $object_type
+ );
return false;
}
- // Instanciate object and load object data from DN
- $object = new $object_type();
- if (!$object -> loadData($object_dn, self :: getConfig($id, "LSobjects.$object_type.filter", null))) {
- self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): object $object_dn not found (or does not match with selection filter)");
+ // Check object exists
+ if (
+ $check_exists
+ && !$object_type :: exists(
+ $object_dn,
+ self :: getConfig($id, "LSobjects.$object_type.filter", null, "string")
+ )
+ ) {
+ self :: log_warning(
+ "checkObjectIsSelectable($id, $object_type, $object_dn): object $object_dn not found ".
+ "(or does not match with selection filter)"
+ );
return false;
}