PHP ldap_add 函数转义 DN 语法中的 ldap 特殊字符

发布于 2024-12-22 00:51:20 字数 317 浏览 0 评论 0原文

我正在尝试将一些用户添加到我的 Ldap DB,但是当我使用一些特殊字符(例如“,.”)时,我收到一些错误(无效的 dn 语法)。我需要一个转义所有字符的函数。我尝试 preg_quote 但在某些情况下会出现一些错误。

提前致谢

代码:

$user = 'Test , Name S.L';

    if(!(ldap_add($ds, "cn=" . $user . ",".LDAP_DN_BASE, $info))) {

            include 'error_new_account.php';

    }

I'm trying to add some users to my Ldap DB but I get some errors (invalid dn syntax) when I use some special characters like ",.". I need a function that escape all characters. I try preg_quote but I get some errors in some cases.

Thanks in advance

Code:

$user = 'Test , Name S.L';

    if(!(ldap_add($ds, "cn=" . $user . ",".LDAP_DN_BASE, $info))) {

            include 'error_new_account.php';

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

落日海湾 2024-12-29 00:51:20

编辑 2013 年 1 月:根据 RFC 4514。感谢 Eugenio< /a> 指出这个问题。

编辑 2014 年:我将此函数添加到 PHP 5.6。下面的代码现在是早期 PHP 版本的类似替代品。

if (!function_exists('ldap_escape')) {
    define('LDAP_ESCAPE_FILTER', 0x01);
    define('LDAP_ESCAPE_DN',     0x02);

    /**
     * @param string $subject The subject string
     * @param string $ignore Set of characters to leave untouched
     * @param int $flags Any combination of LDAP_ESCAPE_* flags to indicate the
     *                   set(s) of characters to escape.
     * @return string
     */
    function ldap_escape($subject, $ignore = '', $flags = 0)
    {
        static $charMaps = array(
            LDAP_ESCAPE_FILTER => array('\\', '*', '(', ')', "\x00"),
            LDAP_ESCAPE_DN     => array('\\', ',', '=', '+', '<', '>', ';', '"', '#'),
        );

        // Pre-process the char maps on first call
        if (!isset($charMaps[0])) {
            $charMaps[0] = array();
            for ($i = 0; $i < 256; $i++) {
                $charMaps[0][chr($i)] = sprintf('\\%02x', $i);;
            }

            for ($i = 0, $l = count($charMaps[LDAP_ESCAPE_FILTER]); $i < $l; $i++) {
                $chr = $charMaps[LDAP_ESCAPE_FILTER][$i];
                unset($charMaps[LDAP_ESCAPE_FILTER][$i]);
                $charMaps[LDAP_ESCAPE_FILTER][$chr] = $charMaps[0][$chr];
            }

            for ($i = 0, $l = count($charMaps[LDAP_ESCAPE_DN]); $i < $l; $i++) {
                $chr = $charMaps[LDAP_ESCAPE_DN][$i];
                unset($charMaps[LDAP_ESCAPE_DN][$i]);
                $charMaps[LDAP_ESCAPE_DN][$chr] = $charMaps[0][$chr];
            }
        }

        // Create the base char map to escape
        $flags = (int)$flags;
        $charMap = array();
        if ($flags & LDAP_ESCAPE_FILTER) {
            $charMap += $charMaps[LDAP_ESCAPE_FILTER];
        }
        if ($flags & LDAP_ESCAPE_DN) {
            $charMap += $charMaps[LDAP_ESCAPE_DN];
        }
        if (!$charMap) {
            $charMap = $charMaps[0];
        }

        // Remove any chars to ignore from the list
        $ignore = (string)$ignore;
        for ($i = 0, $l = strlen($ignore); $i < $l; $i++) {
            unset($charMap[$ignore[$i]]);
        }

        // Do the main replacement
        $result = strtr($subject, $charMap);

        // Encode leading/trailing spaces if LDAP_ESCAPE_DN is passed
        if ($flags & LDAP_ESCAPE_DN) {
            if ($result[0] === ' ') {
                $result = '\\20' . substr($result, 1);
            }
            if ($result[strlen($result) - 1] === ' ') {
                $result = substr($result, 0, -1) . '\\20';
            }
        }

        return $result;
    }
}

所以你会这样做:

$user = 'Test , Name S.L';
$cn = ldap_escape($user, '', LDAP_ESCAPE_DN);
if (!ldap_add($ds, "cn={$cn}," . LDAP_DN_BASE, $info)) {
    include 'error_new_account.php';
}

EDIT Jan 2013: added support for escaping leading/trailing spaces in DN strings, per RFC 4514. Thanks to Eugenio for pointing out this issue.

EDIT 2014: I added this function to PHP 5.6. The code below is now a like-for-like drop-in replacement for earlier PHP versions.

if (!function_exists('ldap_escape')) {
    define('LDAP_ESCAPE_FILTER', 0x01);
    define('LDAP_ESCAPE_DN',     0x02);

    /**
     * @param string $subject The subject string
     * @param string $ignore Set of characters to leave untouched
     * @param int $flags Any combination of LDAP_ESCAPE_* flags to indicate the
     *                   set(s) of characters to escape.
     * @return string
     */
    function ldap_escape($subject, $ignore = '', $flags = 0)
    {
        static $charMaps = array(
            LDAP_ESCAPE_FILTER => array('\\', '*', '(', ')', "\x00"),
            LDAP_ESCAPE_DN     => array('\\', ',', '=', '+', '<', '>', ';', '"', '#'),
        );

        // Pre-process the char maps on first call
        if (!isset($charMaps[0])) {
            $charMaps[0] = array();
            for ($i = 0; $i < 256; $i++) {
                $charMaps[0][chr($i)] = sprintf('\\%02x', $i);;
            }

            for ($i = 0, $l = count($charMaps[LDAP_ESCAPE_FILTER]); $i < $l; $i++) {
                $chr = $charMaps[LDAP_ESCAPE_FILTER][$i];
                unset($charMaps[LDAP_ESCAPE_FILTER][$i]);
                $charMaps[LDAP_ESCAPE_FILTER][$chr] = $charMaps[0][$chr];
            }

            for ($i = 0, $l = count($charMaps[LDAP_ESCAPE_DN]); $i < $l; $i++) {
                $chr = $charMaps[LDAP_ESCAPE_DN][$i];
                unset($charMaps[LDAP_ESCAPE_DN][$i]);
                $charMaps[LDAP_ESCAPE_DN][$chr] = $charMaps[0][$chr];
            }
        }

        // Create the base char map to escape
        $flags = (int)$flags;
        $charMap = array();
        if ($flags & LDAP_ESCAPE_FILTER) {
            $charMap += $charMaps[LDAP_ESCAPE_FILTER];
        }
        if ($flags & LDAP_ESCAPE_DN) {
            $charMap += $charMaps[LDAP_ESCAPE_DN];
        }
        if (!$charMap) {
            $charMap = $charMaps[0];
        }

        // Remove any chars to ignore from the list
        $ignore = (string)$ignore;
        for ($i = 0, $l = strlen($ignore); $i < $l; $i++) {
            unset($charMap[$ignore[$i]]);
        }

        // Do the main replacement
        $result = strtr($subject, $charMap);

        // Encode leading/trailing spaces if LDAP_ESCAPE_DN is passed
        if ($flags & LDAP_ESCAPE_DN) {
            if ($result[0] === ' ') {
                $result = '\\20' . substr($result, 1);
            }
            if ($result[strlen($result) - 1] === ' ') {
                $result = substr($result, 0, -1) . '\\20';
            }
        }

        return $result;
    }
}

So you would do:

$user = 'Test , Name S.L';
$cn = ldap_escape($user, '', LDAP_ESCAPE_DN);
if (!ldap_add($ds, "cn={$cn}," . LDAP_DN_BASE, $info)) {
    include 'error_new_account.php';
}
顾冷 2024-12-29 00:51:20

PHP 5.6 Beta 发布 ldap_escape() 函数最近已经生效,但是,该版本目前还没有准备好用于生产,目前您可以将其用于您的开发目的。

PHP 5.6 Beta released ldap_escape() function recently and it is in effect, However, this version is not production ready at present, you can very use it for your development purposes as of now.

じее 2024-12-29 00:51:20

请注意,如果您还没有使用 PHP 5.6,您可以使用我在下面创建的方法来镜像确切的 PHP 5.6 函数 ldap_escape(),请记住,这是在类中使用的。上面的答案与 ldap_escape 函数的执行方式并不完全相同,因为如果没有给出标志,它不会将所有字符转义为十六进制字符串,因此这更适合插入以面向对象的方式替代早期版本的 PHP。

我记录了每一行,以便更容易理解正在发生的事情。向下滚动查看输出。

方法(与 PHP 5 或更高版本兼容):

/**
 * Escapes the inserted value for LDAP.
 *
 * @param string $value The value to escape
 * @param string $ignore The characters to ignore
 * @param int $flags The PHP flag to use
 *
 * @return bool|string
 */
public function escapeManual($value, $ignore = '*', $flags = 0)
{
    /*
     * If a flag was supplied, we'll send the value
     * off to be escaped using the PHP flag values
     * and return the result.
     */
    if($flags) {
        return $this->escapeWithFlags($value, $ignore, $flags);
    }

    // Convert ignore string into an array
    $ignores = str_split($ignore);

    // Convert the value to a hex string
    $hex = bin2hex($value);

    /*
     * Separate the string, with the hex length of 2,
     * and place a backslash on the end of each section
     */
    $value = chunk_split($hex, 2, "\\");

    /*
     * We'll append a backslash at the front of the string
     * and remove the ending backslash of the string
     */
    $value = "\\" . substr($value, 0, -1);

    // Go through each character to ignore
    foreach($ignores as $charToIgnore)
    {
        // Convert the characterToIgnore to a hex
        $hexed = bin2hex($charToIgnore);

        // Replace the hexed variant with the original character
        $value = str_replace("\\" . $hexed, $charToIgnore, $value);
    }

    // Finally we can return the escaped value
    return $value;
}

/**
 * Escapes the inserted value with flags. Supplying either 1
 * or 2 into the flags parameter will escape only certain values
 *
 *
 * @param string $value The value to escape
 * @param string $ignore The characters to ignore
 * @param int $flags The PHP flag to use
 * @return bool|string
 */
public function escapeWithFlags($value, $ignore = '*', $flags = 0)
{
    // Convert ignore string into an array
    $ignores = str_split($ignore);

    $escapeFilter = ['\\', '*', '(', ')'];
    $escapeDn = ['\\', ',', '=', '+', '<', '>', ';', '"', '#'];

    switch($flags)
    {
        case 1:
            // Int 1 equals to LDAP_ESCAPE_FILTER
            $escapes = $escapeFilter;
            break;
        case 2:
            // Int 2 equals to LDAP_ESCAPE_DN
            $escapes = $escapeDn;
            break;
        case 3:
            // If both LDAP_ESCAPE_FILTER and LDAP_ESCAPE_DN are used
            $escapes = array_merge($escapeFilter, $escapeDn);
            break;
        default:
            // Customize your own default return value
            return false;
    }

    foreach($escapes as $escape)
    {
        // Make sure the escaped value isn't inside the ignore array
        if( ! in_array($escape, $ignores))
        {
            $hexed = chunk_split(bin2hex($escape), 2, "\\");

            $hexed = "\\" . substr($hexed, 0, -1);

            $value = str_replace($escape, $hexed, $value);
        }
    }

    return $value;
}

测试(请注意,LDAP_ESCAPE 常量仅在 PHP 5.6 中可用):

// Value to escape
$value = 'testing=+<>"";:#()*\x00';

$php = ldap_escape($value, $ignore = '*');

$man = $this->escapeManual($value, $ignore = '*');

echo $php; // \74\65\73\74\69\6e\67\3d\2b\3c\3e\22\22\3b\3a\23\28\29*\5c\78\30\30
echo $man; // \74\65\73\74\69\6e\67\3d\2b\3c\3e\22\22\3b\3a\23\28\29*\5c\78\30\30


$php = ldap_escape($value, $ignore = '*', LDAP_ESCAPE_DN);

$man = $this->escapeManual($value, $ignore = '*', LDAP_ESCAPE_DN);

echo $php; // testing\3d\2b\3c\3e\22\22\3b:\23()*\5cx00
echo $man; // testing\3d\2b\3c\3e\22\22\3b:\23()*\5cx00


$php = ldap_escape($value, $ignore = '*', LDAP_ESCAPE_FILTER);

$man = $this->escapeManual($value, $ignore = '*', LDAP_ESCAPE_FILTER);

echo $php; // testing=+<>"";:#\28\29*\5cx00
echo $man; // testing=+<>"";:#\28\29*\5cx00

Github Gist 链接:https://gist.github.com/stevebauman/0db9b5daa414d60fc266

Just a heads up if your not on PHP 5.6 yet, you can mirror the exact PHP 5.6 function ldap_escape() using the methods I created below, keep in mind this is meant for use in a class. The above answer doesn't perform exactly like the ldap_escape function, as in it doesn't escape all characters into a hex string if no flags have been given, so this would be more suitable for a drop in replacement for earlier versions of PHP, in an object oriented way.

I've documented every line for an easier understanding on whats going on. Scroll down for output.

Methods (Compatible with PHP 5 or greater):

/**
 * Escapes the inserted value for LDAP.
 *
 * @param string $value The value to escape
 * @param string $ignore The characters to ignore
 * @param int $flags The PHP flag to use
 *
 * @return bool|string
 */
public function escapeManual($value, $ignore = '*', $flags = 0)
{
    /*
     * If a flag was supplied, we'll send the value
     * off to be escaped using the PHP flag values
     * and return the result.
     */
    if($flags) {
        return $this->escapeWithFlags($value, $ignore, $flags);
    }

    // Convert ignore string into an array
    $ignores = str_split($ignore);

    // Convert the value to a hex string
    $hex = bin2hex($value);

    /*
     * Separate the string, with the hex length of 2,
     * and place a backslash on the end of each section
     */
    $value = chunk_split($hex, 2, "\\");

    /*
     * We'll append a backslash at the front of the string
     * and remove the ending backslash of the string
     */
    $value = "\\" . substr($value, 0, -1);

    // Go through each character to ignore
    foreach($ignores as $charToIgnore)
    {
        // Convert the characterToIgnore to a hex
        $hexed = bin2hex($charToIgnore);

        // Replace the hexed variant with the original character
        $value = str_replace("\\" . $hexed, $charToIgnore, $value);
    }

    // Finally we can return the escaped value
    return $value;
}

/**
 * Escapes the inserted value with flags. Supplying either 1
 * or 2 into the flags parameter will escape only certain values
 *
 *
 * @param string $value The value to escape
 * @param string $ignore The characters to ignore
 * @param int $flags The PHP flag to use
 * @return bool|string
 */
public function escapeWithFlags($value, $ignore = '*', $flags = 0)
{
    // Convert ignore string into an array
    $ignores = str_split($ignore);

    $escapeFilter = ['\\', '*', '(', ')'];
    $escapeDn = ['\\', ',', '=', '+', '<', '>', ';', '"', '#'];

    switch($flags)
    {
        case 1:
            // Int 1 equals to LDAP_ESCAPE_FILTER
            $escapes = $escapeFilter;
            break;
        case 2:
            // Int 2 equals to LDAP_ESCAPE_DN
            $escapes = $escapeDn;
            break;
        case 3:
            // If both LDAP_ESCAPE_FILTER and LDAP_ESCAPE_DN are used
            $escapes = array_merge($escapeFilter, $escapeDn);
            break;
        default:
            // Customize your own default return value
            return false;
    }

    foreach($escapes as $escape)
    {
        // Make sure the escaped value isn't inside the ignore array
        if( ! in_array($escape, $ignores))
        {
            $hexed = chunk_split(bin2hex($escape), 2, "\\");

            $hexed = "\\" . substr($hexed, 0, -1);

            $value = str_replace($escape, $hexed, $value);
        }
    }

    return $value;
}

Tests (be aware that LDAP_ESCAPE constants are only available in PHP 5.6):

// Value to escape
$value = 'testing=+<>"";:#()*\x00';

$php = ldap_escape($value, $ignore = '*');

$man = $this->escapeManual($value, $ignore = '*');

echo $php; // \74\65\73\74\69\6e\67\3d\2b\3c\3e\22\22\3b\3a\23\28\29*\5c\78\30\30
echo $man; // \74\65\73\74\69\6e\67\3d\2b\3c\3e\22\22\3b\3a\23\28\29*\5c\78\30\30


$php = ldap_escape($value, $ignore = '*', LDAP_ESCAPE_DN);

$man = $this->escapeManual($value, $ignore = '*', LDAP_ESCAPE_DN);

echo $php; // testing\3d\2b\3c\3e\22\22\3b:\23()*\5cx00
echo $man; // testing\3d\2b\3c\3e\22\22\3b:\23()*\5cx00


$php = ldap_escape($value, $ignore = '*', LDAP_ESCAPE_FILTER);

$man = $this->escapeManual($value, $ignore = '*', LDAP_ESCAPE_FILTER);

echo $php; // testing=+<>"";:#\28\29*\5cx00
echo $man; // testing=+<>"";:#\28\29*\5cx00

Github Gist link: https://gist.github.com/stevebauman/0db9b5daa414d60fc266

伪装你 2024-12-29 00:51:20

这些字符必须转义为专有名称或相对专有名称的数据的一部分。使用反斜杠 2 个十六进制数字转义字符(与所有 LDAP 中一样),例如 \2a。其他任何内容都不符合标准主体文件。有关可分辨名称的字符串表示形式的更多具体信息,请参阅 RFC4514

Those characters must escaped to be part of the data of a distinguished name or relative distinguished name. Escape the character (as in all LDAP) with a backslash 2 hex digit, such as \2a. Anything else would not be in compliance with the standards body documents. See RFC4514 for more specific information regarding the string representation of distinguished names.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文