From 8957d6f19ee96c07482b8df4a9b45940b004b048 Mon Sep 17 00:00:00 2001 From: Jan Schneider Date: Wed, 15 Sep 2010 14:29:26 +0200 Subject: [PATCH] Cleanup --- framework/Ldap/lib/Horde/Ldap/Util.php | 591 ++++++++++++++++++--------------- 1 file changed, 317 insertions(+), 274 deletions(-) diff --git a/framework/Ldap/lib/Horde/Ldap/Util.php b/framework/Ldap/lib/Horde/Ldap/Util.php index bd7a9c5ee..a222ef59b 100644 --- a/framework/Ldap/lib/Horde/Ldap/Util.php +++ b/framework/Ldap/lib/Horde/Ldap/Util.php @@ -1,100 +1,116 @@ + * @author Jan Schneider + * @copyright 2010 The Horde Project * @copyright 2009 Benedikt Hallinger - * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 - * @version SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $ - * @link http://pear.php.net/package/Horde_Ldap/ - */ - -/** - * Utility Class for Horde_Ldap - * - * This class servers some functionality to the other classes of Horde_Ldap but most of - * the methods can be used separately as well. - * - * @category Net - * @package Horde_Ldap - * @author Benedikt Hallinger - * @license http://www.gnu.org/copyleft/lesser.html LGPL - * @link http://pear.php.net/package/Horde_Ldap2/ + * @license http://www.gnu.org/copyleft/lesser.html LGPL */ class Horde_Ldap_Util { /** * Explodes the given DN into its elements * - * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence - * of Relative Distinguished Names (RDNs), which themselves - * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored. - * - * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to: - * array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' ) - * - * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of - * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded - * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to - * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to: - * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ]; - * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER. - * - * It also performs the following operations on the given DN: - * - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair - * and strings beginning with "#". - * - Removes the leading 'OID.' characters if the type is an OID instead of a name. - * - 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 types names. + * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a + * Distinguished Name is a sequence of Relative Distinguished Names (RDNs), + * which themselves are sets of Attributes. For each RDN a array is + * constructed where the RDN part is stored. + * + * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded + * to: + * + * array(array('OU=Sales', 'CN=J. Smith'), + * 'DC=example', + * 'DC=net') + * + * + * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of + * the BER encoding of the X.500 AttributeValue rather than some LDAP + * string syntax. These values are hex-encoded and prefixed with a #. To + * distinguish such BER values, ldap_explode_dn uses references to the + * actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is + * exploded to: + * + * array(array('1.3.6.1.4.1.1466.0' => "\004\002Hi"), + * array('DC' => 'example', + * array('DC' => 'com')) + * + * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more + * information on BER. + * + * It also performs the following operations on the given DN: + * - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", + * " ", or a hexpair and strings beginning with "#". + * - Removes the leading 'OID.' characters if the type is an OID instead of + * a name. + * - 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 types names. * Attribute values are not affected by this option. * The default is to uppercase. Valid values are: - * lower Lowercase attribute types names. - * upper Uppercase attribute type names. This is the default. - * none Do not change attribute type names. - * reverse If TRUE, the RDN sequence is reversed. - * onlyvalues If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo') - * - - * @param string $dn The DN that should be exploded - * @param array $options Options to use + * - lower: Lowercase attribute types names. + * - upper: Uppercase attribute type names. This is the + * default. + * - none: Do not change attribute type names. + * - reverse: If true, the RDN sequence is reversed. + * - onlyvalues: If true, then only attributes values are returned ('foo' + * instead of 'cn=foo') * - * @static - * @return array Parts of the exploded DN * @todo implement BER + * @todo replace preg_replace() callbacks. + * + * @param string $dn The DN that should be exploded. + * @param array $options Options to use. + * + * @return array Parts of the exploded DN. */ - public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper')) + public static function ldap_explode_dn($dn, array $options = array()) { - if (!isset($options['onlyvalues'])) $options['onlyvalues'] = false; - if (!isset($options['reverse'])) $options['reverse'] = false; - if (!isset($options['casefold'])) $options['casefold'] = 'upper'; + if (!isset($options['onlyvalues'])) { + $options['onlyvalues'] = false; + } + if (!isset($options['reverse'])) { + $options['reverse'] = false; + } + if (!isset($options['casefold'])) { + $options['casefold'] = 'upper'; + } - // Escaping of DN and stripping of "OID." + // Escaping of DN and stripping of "OID.". $dn = self::canonical_dn($dn, array('casefold' => $options['casefold'])); - // splitting the DN + // Splitting the DN. $dn_array = preg_split('/(?<=[^\\\\]),/', $dn); - // clear wrong splitting (possibly we have split too much) - // /!\ Not clear, if this is neccessary here - //$dn_array = self::correct_dn_splitting($dn_array, ','); + // Clear wrong splitting (possibly we have split too much). + // Not clear, if this is neccessary here: + //$dn_array = self::_correct_dn_splitting($dn_array, ','); - // construct subarrays for multivalued RDNs and unescape DN value - // also convert to output format and apply casefolding + // Construct subarrays for multivalued RDNs and unescape DN value, also + // convert to output format and apply casefolding. foreach ($dn_array as $key => $value) { $value_u = self::unescape_dn_value($value); $rdns = self::split_rdn_multival($value_u[0]); + // TODO: nuke code duplication if (count($rdns) > 1) { - // MV RDN! + // Multivalued RDN! foreach ($rdns as $subrdn_k => $subrdn_v) { - // Casefolding - if ($options['casefold'] == 'upper') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $subrdn_v); - if ($options['casefold'] == 'lower') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $subrdn_v); + // Casefolding. + if ($options['casefold'] == 'upper') { + $subrdn_v = preg_replace('/^(\w+=)/e', "Horde_String::upper('\\1')", $subrdn_v); + } + if ($options['casefold'] == 'lower') { + $subrdn_v = preg_replace('/^(\w+=)/e', "Horde_String::upper('\\1')", $subrdn_v); + } if ($options['onlyvalues']) { preg_match('/(.+?)(?", ";", "#", "=" with a special meaning in RFC 2252 - * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair. - * Finally all leading and trailing spaces are converted to sequences of \20. + * Escapes the given VALUES according to RFC 2253 so that they can be + * safely used in LDAP DNs. The characters ",", "+", """, "\", "<", ">", + * ";", "#", "=" with a special meaning in RFC 2252 are preceeded by ba + * backslash. Control characters with an ASCII code < 32 are represented as + * \hexpair. Finally all leading and trailing spaces are converted to + * sequences of \20. * - * @param array $values An array containing the DN values that should be escaped + * @param string|array $values DN values that should be escaped. * - * @static - * @return array The array $values, but escaped + * @return array The escaped values. */ - public static function escape_dn_value($values = array()) + public static function escape_dn_value($values) { - // Parameter validation + // Parameter validation. if (!is_array($values)) { $values = array($values); } foreach ($values as $key => $val) { - // Escaping of filter meta characters - $val = str_replace('\\', '\\\\', $val); - $val = str_replace(',', '\,', $val); - $val = str_replace('+', '\+', $val); - $val = str_replace('"', '\"', $val); - $val = str_replace('<', '\<', $val); - $val = str_replace('>', '\>', $val); - $val = str_replace(';', '\;', $val); - $val = str_replace('#', '\#', $val); - $val = str_replace('=', '\=', $val); - - // ASCII < 32 escaping + // Escaping of filter meta characters. + $val = addcslashes($val, '\\,+"<>;#='); + + // ASCII < 32 escaping. $val = self::asc2hex32($val); // Convert all leading and trailing spaces to sequences of \20. if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) { - $val = $matches[2]; - for ($i = 0; $i < strlen($matches[1]); $i++) { - $val = '\20'.$val; - } - for ($i = 0; $i < strlen($matches[3]); $i++) { - $val = $val.'\20'; - } + $val = str_repeat('\20', strlen($matches[1])) . $matches[2] . str_repeat('\20', strlen($matches[3])); } - if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + if (null === $val) { + // Apply escaped "null" if string is empty. + $val = '\0'; + } $values[$key] = $val; } @@ -191,36 +200,32 @@ class Horde_Ldap_Util } /** - * Undoes the conversion done by escape_dn_value(). + * Unescapes DN values according to RFC 2253. + * + * Reverts the conversion done by escape_dn_value(). * - * Any escape sequence starting with a baskslash - hexpair or special character - - * will be transformed back to the corresponding character. + * Any escape sequence starting with a baskslash - hexpair or special + * character - will be transformed back to the corresponding character. * - * @param array $values Array of DN Values + * @param array $values DN values. * - * @return array Same as $values, but unescaped - * @static + * @return array Unescaped DN values. */ - public static function unescape_dn_value($values = array()) + public static function unescape_dn_value($values) { - // Parameter validation + // Parameter validation. if (!is_array($values)) { $values = array($values); } foreach ($values as $key => $val) { - // strip slashes from special chars - $val = str_replace('\\\\', '\\', $val); - $val = str_replace('\,', ',', $val); - $val = str_replace('\+', '+', $val); - $val = str_replace('\"', '"', $val); - $val = str_replace('\<', '<', $val); - $val = str_replace('\>', '>', $val); - $val = str_replace('\;', ';', $val); - $val = str_replace('\#', '#', $val); - $val = str_replace('\=', '=', $val); - - // Translate hex code into ascii + // Strip slashes from special chars. + $val = str_replace( + array('\\\\', '\,', '\+', '\"', '\<', '\>', '\;', '\#', '\='), + array('\\', ',', '+', '"', '<', '>', ';', '#', '='), + $val); + + // Translate hex code into ascii. $values[$key] = self::hex2asc($val); } @@ -228,77 +233,87 @@ class Horde_Ldap_Util } /** - * Returns the given DN in a canonical form + * Converts a DN into a canonical form. * - * Returns false if DN is not a valid Distinguished Name. - * DN can either be a string or an array - * as returned by ldap_explode_dn, 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). + * DN can either be a string or an array as returned by ldap_explode_dn(), + * 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. This is the default. - * none Do not change attribute type names. - * [NOT IMPLEMENTED] mbcescape If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}. - * reverse If TRUE, the RDN sequence is reversed. - * separator Separator to use between RDNs. Defaults to comma (','). - * - * Note: 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. - * - * @param array|string $dn The DN - * @param array $options Options to use - * - * @static - * @return false|string The canonical DN or FALSE - * @todo implement option mbcescape + * - 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. + * + * @param array|string $dn The DN. + * @param array $options Options to use. + * + * @return boolean|string The canonical DN or false if the DN is not valid. */ - public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ',')) + public static function canonical_dn($dn, $options = array()) { - if ($dn === '') return $dn; // empty DN is valid! - - // options check - if (!isset($options['reverse'])) { - $options['reverse'] = false; - } else { - $options['reverse'] = true; + if ($dn === '') { + // Empty DN is valid. + return $dn; } - if (!isset($options['casefold'])) $options['casefold'] = 'upper'; - if (!isset($options['separator'])) $options['separator'] = ','; + // Options check. + $options['reverse'] = !empty($options['reverse']); + if (!isset($options['casefold'])) { + $options['casefold'] = 'upper'; + } + if (!isset($options['separator'])) { + $options['separator'] = ','; + } 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('/(?<=[^\\\\])'.$options['separator'].'/', $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('/(?<=[^\\\\])' . $options['separator'] . '/', $dn); - // clear wrong splitting (possibly we have split too much) - $dn = self::correct_dn_splitting($dn, $options['separator']); + // Clear wrong splitting (possibly we have split too much). + $dn = self::_correct_dn_splitting($dn, $options['separator']); } else { - // Is array, check, if the array is indexed or associative + // 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 + + // Convert to indexed, if associative array detected. if ($assoc) { $newdn = array(); foreach ($dn as $dn_key => $dn_part) { if (is_array($dn_part)) { - ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative - $newdn[] = $dn_part; // copy array as-is, so we can resolve it later + // 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; } @@ -307,99 +322,116 @@ class Horde_Ldap_Util } } - // Escaping and casefolding + // Escaping and casefolding. foreach ($dn as $pos => $dnval) { if (is_array($dnval)) { - // subarray detected, this means very surely, that we had - // a multivalued dn part, which must be resolved + // 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 + // Build RDN part. if (!is_int($subkey)) { - $subval = $subkey.'='.$subval; + $subval = $subkey . '=' . $subval; } $subval_processed = self::canonical_dn($subval); - if (false === $subval_processed) return false; - $dnval_new .= $subval_processed.'+'; + if (false === $subval_processed) { + return false; + } + $dnval_new .= $subval_processed . '+'; } - $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus + // Store RDN part, strip last plus. + $dn[$pos] = substr($dnval_new, 0, -1); } else { - // try to split multivalued RDNS into array + // Try to split multivalued RDNs into array. $rdns = self::split_rdn_multival($dnval); if (count($rdns) > 1) { - // Multivalued RDN was detected! - // The RDN value is expected to be correctly split by split_rdn_multival(). - // It's time to sort the RDN and build the DN! + // Multivalued RDN was detected. The RDN value is expected + // to be correctly split by split_rdn_multival(). It's time + // to sort the RDN and build the DN. $rdn_string = ''; - sort($rdns, SORT_STRING); // Sort RDN keys alphabetically + // Sort RDN keys alphabetically. + sort($rdns, SORT_STRING); foreach ($rdns as $rdn) { $subval_processed = self::canonical_dn($rdn); - if (false === $subval_processed) return false; - $rdn_string .= $subval_processed.'+'; + if (false === $subval_processed) { + return false; + } + $rdn_string .= $subval_processed . '+'; } - $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus - + // Store RDN part, strip last plus. + $dn[$pos] = substr($rdn_string, 0, -1); } else { - // no multivalued RDN! - // split at first unescaped "=" + // No multivalued RDN. Split at first unescaped "=". $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2); - $ocl = ltrim($dn_comp[0]); // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma) - $val = $dn_comp[1]; + // 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(strtolower($ocl), 0, 4) == 'oid.') { + // 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 = strtoupper($ocl); - if ($options['casefold'] == 'lower') $ocl = strtolower($ocl); + if ($options['casefold'] == 'upper') { + $ocl = strtoupper($ocl); + } + if ($options['casefold'] == 'lower') { + $ocl = strtolower($ocl); + } $ocl = self::escape_dn_value(array($ocl)); $ocl = $ocl[0]; } - // escaping of dn-value + // Escaping of DN value. $val = self::escape_dn_value(array($val)); $val = str_replace('/', '\/', $val[0]); - $dn[$pos] = $ocl.'='.$val; + $dn[$pos] = $ocl . '=' . $val; } } } - if ($options['reverse']) $dn = array_reverse($dn); + if ($options['reverse']) { + $dn = array_reverse($dn); + } + return implode($options['separator'], $dn); } /** - * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. + * Escapes the given values according to RFC 2254 so that they can be + * safely used in LDAP filters. * - * Any control characters with an ACII code < 32 as well as the characters with special meaning in - * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a - * backslash followed by two hex digits representing the hexadecimal value of the character. + * Any control characters with an ACII code < 32 as well as the characters + * with special meaning in LDAP filters "*", "(", ")", and "\" (the + * backslash) are converted into the representation of a backslash followed + * by two hex digits representing the hexadecimal value of the character. * - * @param array $values Array of values to escape + * @param array $values Values to escape. * - * @static - * @return array Array $values, but escaped + * @return array Escaped values. */ - public static function escape_filter_value($values = array()) + public static function escape_filter_value($values) { - // Parameter validation + // Parameter validation. if (!is_array($values)) { $values = array($values); } foreach ($values as $key => $val) { - // Escaping of filter meta characters - $val = str_replace('\\', '\5c', $val); - $val = str_replace('*', '\2a', $val); - $val = str_replace('(', '\28', $val); - $val = str_replace(')', '\29', $val); + // Escaping of filter meta characters. + $val = str_replace(array('\\', '*', '(', ')'), + array('\5c', '\2a', '\28', '\29'), + $val); - // ASCII < 32 escaping + // ASCII < 32 escaping. $val = self::asc2hex32($val); - if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + if (null === $val) { + // Apply escaped "null" if string is empty. + $val = '\0'; + } $values[$key] = $val; } @@ -408,24 +440,26 @@ class Horde_Ldap_Util } /** - * Undoes the conversion done by {@link escape_filter_value()}. + * Unescapes the given values according to RFC 2254. * - * Converts any sequences of a backslash followed by two hex digits into the corresponding character. + * Reverses the conversion done by {@link escape_filter_value()}. * - * @param array $values Array of values to escape + * Converts any sequences of a backslash followed by two hex digits into + * the corresponding character. * - * @static - * @return array Array $values, but unescaped + * @param array $values Values to unescape. + * + * @return array Unescaped values. */ public static function unescape_filter_value($values = array()) { - // Parameter validation + // Parameter validation. if (!is_array($values)) { $values = array($values); } foreach ($values as $key => $value) { - // Translate hex code into ascii + // Translate hex code into ascii. $values[$key] = self::hex2asc($value); } @@ -433,12 +467,11 @@ class Horde_Ldap_Util } /** - * Converts all ASCII chars < 32 to "\HEX" + * Converts all ASCII chars < 32 to "\HEX". * - * @param string $string String to convert + * @param string $string String to convert. * - * @static - * @return string + * @return string Hexadecimal representation of $string. */ public static function asc2hex32($string) { @@ -446,72 +479,77 @@ class Horde_Ldap_Util $char = substr($string, $i, 1); if (ord($char) < 32) { $hex = dechex(ord($char)); - if (strlen($hex) == 1) $hex = '0'.$hex; - $string = str_replace($char, '\\'.$hex, $string); + if (strlen($hex) == 1) { + $hex = '0' . $hex; + } + $string = str_replace($char, '\\' . $hex, $string); } } return $string; } /** - * Converts all Hex expressions ("\HEX") to their original ASCII characters - * - * @param string $string String to convert + * Converts all hexadecimal expressions ("\HEX") to their original ASCII + * characters. * - * @static * @author beni@php.net, heavily based on work from DavidSmith@byu.net - * @return string + * + * @param string $string String to convert. + * + * @return string ASCII representation of $string. */ public static function hex2asc($string) { - $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string); - return $string; + return preg_replace('/\\\([0-9A-Fa-f]{2})/e', "chr(hexdec('\\1'))", $string); } /** - * Split an multivalued RDN value into an Array + * Splits a multivalued RDN value into an array. * - * A RDN can contain multiple values, spearated by a plus sign. - * This function returns each separate ocl=value pair of the RDN part. + * A RDN can contain multiple values, spearated by a plus sign. This method + * returns each separate ocl=value pair of the RDN part. * - * If no multivalued RDN is detected, an array containing only - * the original rdn part is returned. + * If no multivalued RDN is detected, an array containing only the original + * RDN part is returned. * * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to: * array([0] => 'OU=Sales', [1] => 'CN=J. Smith') * - * The method trys to be smart if it encounters unescaped "+" characters, but may fail, - * so ensure escaped "+"es in attr names and attr values. + * The method tries to be smart if it encounters unescaped "+" characters, + * but may fail, so better ensure escaped "+" in attribute names and + * values. * - * [BUG] If you have a multivalued RDN with unescaped plus characters - * and there is a unescaped plus sign at the end of an value followed by an - * attribute name containing an unescaped plus, then you will get wrong splitting: + * [BUG] If you have a multivalued RDN with unescaped plus characters and + * there is a unescaped plus sign at the end of an value followed by + * an attribute name containing an unescaped plus, then you will get + * wrong splitting: * $rdn = 'OU=Sales+C+N=J. Smith'; * returns: * array('OU=Sales+C', 'N=J. Smith'); - * The "C+" is treaten as value of the first pair instead as attr name of the second pair. - * To prevent this, escape correctly. + * The "C+" is treaten as the value of the first pair instead of as + * the attribute name of the second pair. To prevent this, escape + * correctly. * - * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar) + * @param string $rdn Part of a (multivalued) escaped RDN (e.g. ou=foo or + * ou=foo+cn=bar) * - * @static - * @return array Array with the components of the multivalued RDN or Error + * @return array The components of the multivalued RDN. */ public static function split_rdn_multival($rdn) { $rdns = preg_split('/(? $dn_value) { - $dn_value = $dn[$key]; // refresh value (foreach caches!) - // if the dn_value is not in attr=value format, then we had an - // unescaped separator character inside the attr name or the value. - // We assume, that it was the attribute value. - // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class - // must remain independent from the other classes or connections. + // Refresh value (foreach caches!) + $dn_value = $dn[$key]; + // If $dn_value is not in attr=value format, we had an unescaped + // separator character inside the attr name or the value. We assume + // that it was the attribute value. + + // TODO: To solve this, we might ask the schema. The + // Horde_Ldap_Util class must remain independent from the + // other classes or connections though. if (!preg_match('/.+(?