Horde_Ldap_Util::canonicalDN PHP Method

canonicalDN() public static method

DN can either be a string or an array as returned by explodeDN(), which is useful when constructing a DN. The DN array may have be indexed (each array value is a OCL=VALUE pair) or associative (array key is OCL and value is VALUE). It performs the following operations on the given DN: - Removes the leading 'OID.' characters if the type is an OID instead of a name. - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair. - Converts all leading and trailing spaces in values to be \20. - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. $options is a list of name/value pairs, valid options are: - casefold: Controls case folding of attribute type names. Attribute values are not affected by this option. The default is to uppercase. Valid values are: - lower: Lowercase attribute type names. - upper: Uppercase attribute type names. - none: Do not change attribute type names. - reverse: If true, the RDN sequence is reversed. - separator: Separator to use between RDNs. Defaults to comma (','). The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test, because an empty string evaluates to false. Use the "===" operator instead.
public static canonicalDN ( array | string $dn, array $options = [] ) : boolean | string
$dn array | string The DN.
$options array Options to use.
return boolean | string The canonical DN or false if the DN is not valid.
    public static function canonicalDN($dn, array $options = array())
    {
        if ($dn === '') {
            // Empty DN is valid.
            return $dn;
        }
        // Options check.
        $options = array_merge(array('casefold' => 'upper', 'reverse' => false, 'separator' => ','), $options);
        if (!is_array($dn)) {
            // It is not clear to me if the perl implementation splits by the
            // user defined separator or if it just uses this separator to
            // construct the new DN.
            $dn = preg_split('/(?<!\\\\)' . preg_quote($options['separator']) . '/', $dn);
            // Clear wrong splitting (possibly we have split too much).
            $dn = self::_correctDNSplitting($dn, $options['separator']);
        } else {
            // Is array, check if the array is indexed or associative.
            $assoc = false;
            foreach ($dn as $dn_key => $dn_part) {
                if (!is_int($dn_key)) {
                    $assoc = true;
                    break;
                }
            }
            // Convert to indexed, if associative array detected.
            if ($assoc) {
                $newdn = array();
                foreach ($dn as $dn_key => $dn_part) {
                    if (is_array($dn_part)) {
                        // We assume here that the RDN parts are also
                        // associative.
                        ksort($dn_part, SORT_STRING);
                        // Copy array as-is, so we can resolve it later.
                        $newdn[] = $dn_part;
                    } else {
                        $newdn[] = $dn_key . '=' . $dn_part;
                    }
                }
                $dn =& $newdn;
            }
        }
        // Escaping and casefolding.
        foreach ($dn as $pos => $dnval) {
            if (is_array($dnval)) {
                // Subarray detected, this means most probably that we had a
                // multivalued DN part, which must be resolved.
                $dnval_new = '';
                foreach ($dnval as $subkey => $subval) {
                    // Build RDN part.
                    if (!is_int($subkey)) {
                        $subval = $subkey . '=' . $subval;
                    }
                    $subval_processed = self::canonicalDN($subval, $options);
                    if (false === $subval_processed) {
                        return false;
                    }
                    $dnval_new .= $subval_processed . '+';
                }
                // Store RDN part, strip last plus.
                $dn[$pos] = substr($dnval_new, 0, -1);
            } else {
                // Try to split multivalued RDNs into array.
                $rdns = self::splitRDNMultivalue($dnval);
                if (count($rdns) > 1) {
                    // Multivalued RDN was detected. The RDN value is expected
                    // to be correctly split by splitRDNMultivalue(). It's time
                    // to sort the RDN and build the DN.
                    $rdn_string = '';
                    // Sort RDN keys alphabetically.
                    sort($rdns, SORT_STRING);
                    foreach ($rdns as $rdn) {
                        $subval_processed = self::canonicalDN($rdn, $options);
                        if (false === $subval_processed) {
                            return false;
                        }
                        $rdn_string .= $subval_processed . '+';
                    }
                    // Store RDN part, strip last plus.
                    $dn[$pos] = substr($rdn_string, 0, -1);
                } else {
                    // No multivalued RDN. Split at first unescaped "=".
                    $dn_comp = self::splitAttributeString($rdns[0]);
                    if (count($dn_comp) != 2) {
                        throw new Horde_Ldap_Exception('Invalid RDN: ' . $rdns[0]);
                    }
                    // Trim left whitespaces because of "cn=foo, l=bar" syntax
                    // (whitespace after comma).
                    $ocl = ltrim($dn_comp[0]);
                    $val = $dn_comp[1];
                    // Strip 'OID.', otherwise apply casefolding and escaping.
                    if (substr(Horde_String::lower($ocl), 0, 4) == 'oid.') {
                        $ocl = substr($ocl, 4);
                    } else {
                        if ($options['casefold'] == 'upper') {
                            $ocl = Horde_String::upper($ocl);
                        }
                        if ($options['casefold'] == 'lower') {
                            $ocl = Horde_String::lower($ocl);
                        }
                        $ocl = self::escapeDNValue(array($ocl));
                        $ocl = $ocl[0];
                    }
                    // Escaping of DN value.
                    // TODO: if the value is already correctly escaped, we get
                    //       double escaping.
                    $val = self::escapeDNValue(array($val));
                    $val = str_replace('/', '\\/', $val[0]);
                    $dn[$pos] = $ocl . '=' . $val;
                }
            }
        }
        if ($options['reverse']) {
            $dn = array_reverse($dn);
        }
        return implode($options['separator'], $dn);
    }

Usage Example

コード例 #1
0
ファイル: Ldap.php プロジェクト: DSNS-LAB/Dmail
 /**
  * Returns the win32 AD epoch number of days the password may be unchanged.
  *
  * @return integer|boolean  Number of days or false if no limit.
  */
 protected function _getMaxPasswd()
 {
     $dn = Horde_Ldap_Util::explodeDN($this->_params['basedn']);
     $domaindn = array();
     foreach ($dn as $rdn) {
         $attribute = Horde_Ldap_Util::splitAttributeString($rdn);
         if ($attribute[0] == 'DC') {
             $domaindn[] = $rdn;
         }
     }
     $dn = Horde_Ldap_Util::canonicalDN($domaindn);
     $search = $this->_ldap->search($domaindn, 'objectClass=*');
     $entry = $search->shiftEntry();
     try {
         return $entry->getValue('maxPwdAge', 'single');
     } catch (Horde_Ldap_Exception $e) {
         return false;
     }
 }
All Usage Examples Of Horde_Ldap_Util::canonicalDN