2011-12-19 32 views
12

私のLdap DBにいくつかのユーザーを追加しようとしていますが、 "、。"のような特殊文字を使用するとエラーが発生します。すべての文字をエスケープする関数が必要です。私はpreg_quoteを試してみますが、場合によってはエラーが発生します。事前にPHPのldap_add関数がDN構文のldap特殊文字をエスケープする

おかげで

コード:

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

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

      include 'error_new_account.php'; 

    } 

答えて

25

EDIT 2013年1月:RFC 4514ごとに、DN文字列のリーディング/末尾のスペースをエスケープするためのサポートを追加しました。この問題を指摘してくれたEugenioに感謝します。

EDIT 2014:I added this function to 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'; 
} 
+0

ありがとう、素敵な機能。 – Sbml

+0

@daverandomあなたはスペースにもエスケープするために文字に追加する必要があります(属性値の最初または最後の文字の場合)。 また、#記号は属性値の最初の文字である場合にのみエスケープする必要があります。 http://www-03.ibm.com/systems/i/software/ldap/underdn.html – Eugenio

+0

@Eugenio興味深いことに、それが標準LDAPかIBM固有のものかどうかは分かりますか?私は決してその前のどこかの規定を見たことがありません。 DAP/LDAPの標準ドキュメントは非常に長く、非常に抽象的です。そのような情報はほとんど見つけられません。現時点で私は手間をかけています。S – DaveRandom

1

これらの文字は、識別名または相対識別名のデータの一部であることをエスケープしなければなりません。バックスラッシュ2桁の数字(たとえば、\2a)を使用して文字を(すべてのLDAPのように)エスケープします。他のものは、標準化団体の文書に従わないであろう。識別名の文字列表現に関する詳細は、RFC4514を参照してください。

2

PHP 5.6ベータ最近ldap_escape()機能をリリースし、それが有効であるが、しかし、このバージョンでは、あなたが非常に今のようあなたの開発目的のためにそれを使用することができ、現在では準備ができて、生産ではありません。

2

あなたがまだPHP 5.6を使用していない場合は、PHP 5.6の正確な機能ldap_escape()を以下の方法でミラーリングできます。これはクラスで使用するためのものです。上記の答えは、フラグが与えられていなければすべての文字を16進文字列にエスケープしないので、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の要旨リンク:https://gist.github.com/stevebauman/0db9b5daa414d60fc266

関連する問題