From bca8a84a1619357d9005bcf61fd1823f4a4c4265 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come@opensides.be>
Date: Tue, 17 Apr 2018 17:32:07 +0200
Subject: [PATCH] :sparkles: feat(simpleplugin) Use as many attributes as
 needed to build a unique DN

issue #5817
---
 include/class_Combinations.inc              | 88 +++++++++++++++++++++
 include/simpleplugin/class_simplePlugin.inc | 27 ++++---
 2 files changed, 106 insertions(+), 9 deletions(-)
 create mode 100644 include/class_Combinations.inc

diff --git a/include/class_Combinations.inc b/include/class_Combinations.inc
new file mode 100644
index 000000000..d0ef2ac59
--- /dev/null
+++ b/include/class_Combinations.inc
@@ -0,0 +1,88 @@
+<?php
+/*
+  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
+  Copyright (C) 2018  FusionDirectory
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/*!brief Iterator that returns all combinations of $size element from $input array
+ */
+class Combinations implements Iterator
+{
+  protected $current  = NULL;
+  protected $input    = NULL;
+  protected $n        = 0;
+  protected $size     = 0;
+  protected $pos      = 0;
+
+  function __construct($input, $size)
+  {
+    $this->input = array_values($input);
+    $this->n = count($this->input);
+    $this->size = $size;
+    $this->rewind();
+  }
+
+  function key()
+  {
+    return $this->pos;
+  }
+
+  function current()
+  {
+    $r = array();
+    for ($i = 0; $i < $this->size; $i++) {
+      $r[] = $this->input[$this->current[$i]];
+    }
+    return $r;
+  }
+
+  function next()
+  {
+    if ($this->_next()) {
+      $this->pos++;
+    } else {
+      $this->pos = -1;
+    }
+  }
+
+  function rewind()
+  {
+    $this->current  = range(0, $this->size);
+    $this->pos      = 0;
+  }
+
+  function valid()
+  {
+    return ($this->pos >= 0);
+  }
+
+  protected function _next()
+  {
+    $i = $this->size - 1;
+    while (($i >= 0) && ($this->current[$i] == $this->n - $this->size + $i)) {
+      $i--;
+    }
+    if ($i < 0) {
+      return FALSE;
+    }
+    $this->current[$i]++;
+    while ($i++ < $this->size - 1) {
+      $this->current[$i] = $this->current[$i - 1] + 1;
+    }
+    return TRUE;
+  }
+}
diff --git a/include/simpleplugin/class_simplePlugin.inc b/include/simpleplugin/class_simplePlugin.inc
index d95c17b62..8017282ac 100644
--- a/include/simpleplugin/class_simplePlugin.inc
+++ b/include/simpleplugin/class_simplePlugin.inc
@@ -1813,19 +1813,28 @@ class simplePlugin
       return $dn;
     }
 
-    /* Look for additional attributes */
+    /* Build DN with multiple attributes */
+    $usableAttributes = array();
     foreach ($this->attributes as $attr) {
       if (($attr == $attribute) || ($this->$attr == '') || is_array($this->$attr)) {
         continue;
       }
-
-      $dn = $attribute.'='.ldap_escape_dn($this->$attribute).'+'.$attr.'='.ldap_escape_dn($this->$attr).','.$base;
-      if ($dn == $this->orig_dn) {
-        return $dn;
-      }
-      $ldap->cat($dn, array('dn'));
-      if (!$ldap->fetch()) {
-        return $dn;
+      $usableAttributes[] = $attr;
+    }
+    for ($i = 2; $i < count($usableAttributes); $i++) {
+      foreach (new Combinations($usableAttributes, $i) as $attrs) {
+        $dn = $attribute.'='.ldap_escape_dn($this->$attribute);
+        foreach ($attrs as $attr) {
+          $dn .= '+'.$attr.'='.ldap_escape_dn($this->$attr);
+        }
+        $dn .= ','.$base;
+        if ($dn == $this->orig_dn) {
+          return $dn;
+        }
+        $ldap->cat($dn, array('dn'));
+        if (!$ldap->fetch()) {
+          return $dn;
+        }
       }
     }
 
-- 
GitLab