From 0a3159d502d5321b4609ddf4d8bb91c576bdea7c Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Wed, 15 Mar 2017 20:29:26 +0100
Subject: [PATCH] KeyValueStringParser.php: Function removeSourroundingQuotes()
 renamed to quoteUnwrap(). Ldap.php: New function printfPrepare(). Recode
 parsing and preparation of later sprintf statements. Fix problem with
 ldap_search 'Size Limit reached'. Skip empty entries. OnArray.php: new
 function arrayValueToLower().

---
 .../qfq/qfq/helper/KeyValueStringParser.php   |  4 +-
 extension/qfq/qfq/helper/Ldap.php             | 85 +++++++++++++------
 extension/qfq/qfq/helper/OnArray.php          | 11 ++-
 3 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/extension/qfq/qfq/helper/KeyValueStringParser.php b/extension/qfq/qfq/helper/KeyValueStringParser.php
index c940cd6ff..35c0f5fc7 100644
--- a/extension/qfq/qfq/helper/KeyValueStringParser.php
+++ b/extension/qfq/qfq/helper/KeyValueStringParser.php
@@ -123,7 +123,7 @@ class KeyValueStringParser {
 
             if (count($keyValueArray) === 2) {
                 // "a:1", "a:"
-                $returnValue[$key] = self::removeSourroundingQuotes(trim($keyValueArray[1]));
+                $returnValue[$key] = self::quoteUnwrap(trim($keyValueArray[1]));
             } else {
                 // no Value given: "a"
                 $returnValue[$key] = ($valueMode === KVP_VALUE_GIVEN) ? "" : $key;
@@ -137,7 +137,7 @@ class KeyValueStringParser {
      * @param $string
      * @return string
      */
-    private static function removeSourroundingQuotes($string) {
+    public static function quoteUnwrap($string) {
         $quotes = ['\'', '"'];
 
         if ($string === "" || strlen($string) === 1) {
diff --git a/extension/qfq/qfq/helper/Ldap.php b/extension/qfq/qfq/helper/Ldap.php
index c5c1ef046..ced53b734 100644
--- a/extension/qfq/qfq/helper/Ldap.php
+++ b/extension/qfq/qfq/helper/Ldap.php
@@ -11,6 +11,7 @@ namespace qfq;
 use qfq;
 
 require_once(__DIR__ . '/KeyValueStringParser.php');
+require_once(__DIR__ . '/OnArray.php');
 
 class Ldap {
 
@@ -33,14 +34,29 @@ class Ldap {
             throw new UserFormException("Unable to connect to LDAP server: $ldapServer", ERROR_LDAP_CONNECT);
         }
 
-//        $sr = ldap_search($ds, $ldapBaseDn, $ldapSearch, null, null, $ldapLimit);
-        $sr = ldap_search($ds, $ldapBaseDn, $ldapSearch);
+        $keyArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF], $keyFormat);
+        $valueArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], $valueFormat);
+
+        $attr = array_values(array_unique(array_merge($keyArr, $valueArr)));
+
+        // 'Size Limit errors' are reported, even if it is not a real problem.
+        // Fake all errors at the moment.
+        // TODO: just drop the 'Size Limit errors' and report all others
+        set_error_handler(function () { /* ignore errors */
+        });
+        $sr = ldap_search($ds, $ldapBaseDn, $ldapSearch, $attr, 0, $ldapLimit);
+        restore_error_handler();
+
         $info = ldap_get_entries($ds, $sr);
 
         for ($i = 0; $i < $info["count"]; $i++) {
 
-            $key = $this->printfResult($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF], $info[$i]);
-            $value = $this->printfResult($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], $info[$i]);
+            $key = $this->printfResult($keyFormat, $keyArr, $info[$i]);
+            $value = $this->printfResult($valueFormat, $valueArr, $info[$i]);
+
+            if ($key == '' || $value == '') {
+                continue; // if $key or $value is empty: skip
+            }
 
             $arr[] = [API_TYPEAHEAD_KEY => $key, API_TYPEAHEAD_VALUE => $value];
         }
@@ -51,7 +67,38 @@ class Ldap {
     }
 
     /**
-     * Collects values from $inforElelement and sprintf them  as described in $format.
+     * Very specific function to prepare the later 'printfResult()'.
+     *
+     * @param $fmtComplete
+     * @param $fmtFirst
+     * @return mixed
+     * @throws CodeException
+     * @throws UserFormException
+     */
+    private function printfPrepare($fmtComplete, &$fmtFirst) {
+
+        // Typical $fmtComplete: "'%s / %s / %s', cn, mail. telephonenumber"
+        $arr = KeyValueStringParser::explodeWrapped(',', $fmtComplete);
+
+        if (count($arr) < 2) {
+            throw new UserFormException("Expect a sprintf compatible format string with a least one argument. Got: '" . $fmtComplete . "'", ERROR_MISSING_PRINTF_ARGUMENTS);
+        }
+
+        // unquote and return the part printf-'formatString'
+        $fmtFirst = trim($arr[0], SINGLE_TICK . DOUBLE_TICK);
+
+        array_shift($arr); // remove first entry:
+
+        $arr = OnArray::trimArray($arr); // remove any leading/trailing spaces
+
+        // toLower is important, cause the LDAP attribute names are all lowercase in PHP - if the user specifies in CamelHook , the vars are not found.
+        return OnArray::arrayValueToLower($arr);
+
+    }
+
+    /**
+     * Plays sprintf with supplied arguments. Collect the values of the arguments in the array
+     *  $keyArr to pass them via 'call_user_func_array' to sprintf.
      *
      * @param $format
      * @param $infoElement
@@ -59,31 +106,13 @@ class Ldap {
      * @throws CodeException
      * @throws UserFormException
      */
-    private function printfResult($format, $infoElement) {
-
-        // $format: "'%s / %s / %s', cn, mail, telephonenumber".
-        // keyArr[0]: printf format string
-        // keyArr[1..x]: columnnames
-        $keyArr = KeyValueStringParser::explodeWrapped(',', $format);
-        if (count($keyArr) < 2) {
-            throw new UserFormException("Expect a sprintf compatible format string with a least one argument. Got: '" . $format . "'", ERROR_MISSING_PRINTF_ARGUMENTS);
-        }
+    private function printfResult($format, array $keyArr, $infoElement) {
 
-        $args = array();
-        $args[] = $keyArr[0];
-        array_shift($keyArr);
-        foreach ($keyArr as $arg) {
-            $keyName = trim($arg);
-            $args[] = $infoElement[$keyName][0];
-        }
+        $args = array($format);
 
-//        if(isset($info[$i]["mail"][0])) {
-//            $key = $info[$i]["mail"][0];
-//            if($key===false || $key===null || $key=='') {
-//                continue;
-//            }
-//            $arr[] = [ 'key' => $info[$i]["mail"][0], 'value' => $info[$i]["cn"][0] . ' / ' . $info[$i]["mail"][0] . ' / ' . $info[$i]["telephonenumber"][0]];
-//        }
+        foreach ($keyArr as $key) {
+            $args[] = (isset($infoElement[$key][0])) ? $infoElement[$key][0] : '';
+        }
 
         return call_user_func_array('sprintf', $args);
     }
diff --git a/extension/qfq/qfq/helper/OnArray.php b/extension/qfq/qfq/helper/OnArray.php
index 0da2d0565..7e2806b92 100644
--- a/extension/qfq/qfq/helper/OnArray.php
+++ b/extension/qfq/qfq/helper/OnArray.php
@@ -74,7 +74,7 @@ class OnArray {
      * @param string $character_mask
      * @return array
      */
-    public static function trimArray(array $arr, $character_mask) {
+    public static function trimArray(array $arr, $character_mask = " \t\n\r\0\x0B") {
         foreach ($arr as $key => $item) {
             $arr[$key] = trim($item, $character_mask);
         }
@@ -168,4 +168,13 @@ class OnArray {
 
         return $new;
     }
+
+    public static function arrayValueToLower(array $arr) {
+        $new = array();
+
+        foreach ($arr as $key => $value) {
+            $new[$key] = strtolower($value);
+        }
+        return $new;
+    }
 }
\ No newline at end of file
-- 
GitLab