<?php
/**
- * File containing the Horde_Ldap_Util interface class.
+ * Utility Class for Horde_Ldap
*
- * PHP version 5
+ * 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
+ * @category Horde
+ * @package Ldap
* @author Benedikt Hallinger <beni@php.net>
+ * @author Jan Schneider <jan@horde.org>
+ * @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 <beni@php.net>
- * @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:
- * <kbd>array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' )</kbd>
- *
- * [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:
+ * <code>
+ * array(array('OU=Sales', 'CN=J. Smith'),
+ * 'DC=example',
+ * 'DC=net')
+ * </code>
+ *
+ * [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:
+ * <code>
+ * array(array('1.3.6.1.4.1.1466.0' => "\004\002Hi"),
+ * array('DC' => 'example',
+ * array('DC' => 'com'))
+ * <code>
+ * 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('/(.+?)(?<!\\\\)=(.+)/', $subrdn_v, $matches);
$dn_array[$key] = $rdns;
} else {
- // normal RDN
-
- // Casefolding
- if ($options['casefold'] == 'upper') $value = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $value);
- if ($options['casefold'] == 'lower') $value = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $value);
+ // Singlevalued RDN.
+ // Casefolding.
+ if ($options['casefold'] == 'upper') {
+ $value = preg_replace('/^(\w+=)/e', "Horde_String::upper('\\1')", $value);
+ }
+ if ($options['casefold'] == 'lower') {
+ $value = preg_replace('/^(\w+=)/e', "Horde_String::upper('\\1')", $value);
+ }
if ($options['onlyvalues']) {
preg_match('/(.+?)(?<!\\\\)=(.+)/', $value, $matches);
if ($options['reverse']) {
return array_reverse($dn_array);
- } else {
- return $dn_array;
}
+
+ return $dn_array;
}
/**
- * Escapes a DN value according to RFC 2253
+ * Escapes DN values according to RFC 2253.
*
- * 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.
+ * 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;
}
}
/**
- * 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);
}
}
/**
- * 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;
}
}
}
- // 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;
}
}
/**
- * 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);
}
}
/**
- * 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)
{
$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:
* <kbd>array([0] => 'OU=Sales', [1] => 'CN=J. Smith')</kbd>
*
- * 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('/(?<!\\\\)\+/', $rdn);
- $rdns = self::correct_dn_splitting($rdns, '+');
+ $rdns = self::_correct_dn_splitting($rdns, '+');
return array_values($rdns);
}
/**
- * Splits a attribute=value syntax into an array
+ * Splits a attribute=value syntax into an array.
*
* The split will occur at the first unescaped '=' character.
*
- * @param string $attr Attribute and Value Syntax
+ * @param string $attr An attribute-value string.
*
- * @return array Indexed array: 0=attribute name, 1=attribute value
+ * @return array Indexed array: 0=attribute name, 1=attribute value.
*/
public static function split_attribute_string($attr)
{
}
/**
- * Corrects splitting of dn parts
+ * Corrects splitting of DN parts.
*
- * @param array $dn Raw DN array
- * @param array $separator Separator that was used when splitting
+ * @param array $dn Raw DN array.
+ * @param array $separator Separator that was used when splitting.
*
- * @return array Corrected array
- * @access protected
+ * @return array Corrected array.
*/
- protected static function correct_dn_splitting($dn = array(), $separator = ',')
+ protected static function _correct_dn_splitting($dn = array(),
+ $separator = ',')
{
foreach ($dn as $key => $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('/.+(?<!\\\\)=.+/', $dn_value)) {
unset($dn[$key]);
- if (array_key_exists($key-1, $dn)) {
- $dn[$key-1] = $dn[$key-1].$separator.$dn_value; // append to previous attr value
+ if (array_key_exists($key - 1, $dn)) {
+ // Append to previous attribute value.
+ $dn[$key - 1] = $dn[$key - 1] . $separator . $dn_value;
} else {
- $dn[$key+1] = $dn_value.$separator.$dn[$key+1]; // first element: prepend to next attr name
+ // First element: prepend to next attribute name.
+ $dn[$key + 1] = $dn_value . $separator . $dn[$key + 1];
}
}
}
return array_values($dn);
}
-}
\ No newline at end of file
+}