欢迎各位兄弟 发布技术文章
这里的技术是共享的
我自己亲自做的
修改一个 工号为 test45 ad_info_ldap_get_entries_and_modify_one_dn_ok6.php
<?php
function _start_with($str, $needle)
{
return strpos($str, $needle) === 0;
}
if (empty($_GET['gh'])) {
// die("请在网址后加上 ?gh=八位数字 ");
}
$host= 'ldaps://192.168.2.2:636';
$port = '636';//一般都是389
$domain = 'aaaaa.com.cn';
$account = 'bbbbbb';
$user = 'bbbbbb@' . $domain; //域用户名
$password = 'qqqqqqqqq'; //域用户密码
$conn = ldap_connect($host);//不要写成ldap_connect($host.':'.$port)的形式
if ($conn) {
//设置参数
ldap_set_option($conn, LDAP_OPT_DEBUG_LEVEL, 7);
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); //声明使用版本3
ldap_set_option($conn, LDAP_OPT_REFERRALS, 0); // Binding to ldap server
ldap_set_option($conn, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
$bd = ldap_bind($conn, $ad_user, $ad_pwd);
$bd = ldap_bind($conn, $user, $password);
$basedn = "OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn";
// $filter = "(objectClass=*)";//选择器
// $filter = "(&(sAMAccountName=史平忠))";//选择器
$filter = "SamAccountName=test45" ; //根据工号 比如 mmmmm739
//$filter="(|(sn=史平忠*)(givenname=史平忠*))";
$justthese = array('sn', 'department', 'company', 'objectsid', 'mail', 'givenName', 'displayName', 'telephoneNumber', 'memberof', 'samaccountname', 'primarygroupid'); //选择要获取的用户属性
// $justthese = array('*'); //选择要获取的用户属性
$justthese = array('SamAccountName','displayName'); //选择要获取的用户属性
//$sr=ldap_search($conn, $basedn,$filter );
$sr = ldap_search($conn, $basedn, $filter, $justthese);
echo "<pre>";
$info = ldap_get_entries($conn, $sr);
// print_r($info);
unset($info['count']);
$new_info = array();
foreach($info as $key=>$value)
{
// unset($info[$key][0]);
// unset($info[$key]['count']);
$new_info[$key]['samaccountname'] = $value['samaccountname'][0];
$new_info[$key]['dn'] = $value['dn'];
$displayname = strrchr($value['displayname'][0],"(");
$displayname = substr($displayname,strpos($displayname,"(")+1,strpos($displayname,")")-1);
$new_info[$key]['displayname'] = $displayname;
}
foreach($new_info as $key=>$value)
{
if(!_start_with($value['dn'],'CN=T')){
unset($new_info[$key]);
}
$currentDn = $value['dn'];
$newParent = $suffix_dn = "OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn";
$newrDn = "CN=".$value['displayname']."(".$value['samaccountname'].")";
// $newRdn = "CN=".$value['displayname']."(".$value['samaccountname'].")";
// 检查新 DN 是否已存在
// $checkDn = ldap_search($conn, $baseDn, "(distinguishedName=$newrDn)");
// if (!$checkDn) {
// die("检查新 DN 失败: " . ldap_error($conn));
// }
// if (ldap_count_entries($ldapConn, $checkDn) > 0) {
// die("新 DN $newrDn 已存在,请选择其他 DN。");
// }
//var_dump($currentDn);
//var_dump($newrDn);
$modifyDn = ldap_rename($conn, $currentDn, $newrDn, $newParent, true);
if (!$modifyDn) {
var_dump(ldap_error($conn));
var_dump(ldap_errno($conn));
ldap_get_option($conn, LDAP_OPT_ERROR_STRING, $extendedError);
var_dump($extendedError);
die("失败!");
}
break;
}
echo "用户 DN 已成功修改为 $newrDn";
// var_dump($new_info);
echo "</pre>";
if ($bd) {
echo 'LDAP 绑定成功'; //相当于登录成功
} else {
echo 'LDAP 绑定失败';
}
} else {
echo '无法连接到AD域服务器';
}
ldap_close($conn);
修改多个 工号为 * ,,,,,,,,,,,,, OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn 下面的所有 ad_info_ldap_get_entries_and_modify_one_dn_ok5.php
<?php
function _start_with($str, $needle)
{
return strpos($str, $needle) === 0;
}
if (empty($_GET['gh'])) {
// die("请在网址后加上 ?gh=八位数字 ");
}
$host= 'ldaps://192.168.2.2:636';
$port = '636';//一般都是389
$domain = 'aaaaa.com.cn';
$account = 'mmmmm739';
$user = 'mmmmm739@' . $domain; //域用户名
$password = 'aaaaa~nnnnnnnnnnnn'; //域用户密码
$conn = ldap_connect($host);//不要写成ldap_connect($host.':'.$port)的形式
if ($conn) {
//设置参数
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); //声明使用版本3
ldap_set_option($conn, LDAP_OPT_REFERRALS, 0); // Binding to ldap server
$bd = ldap_bind($conn, $user, $password);
$basedn = "OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn";
// $filter = "(objectClass=*)";//选择器
// $filter = "(&(sAMAccountName=史平忠))";//选择器
$filter = "SamAccountName=*" ; //根据工号 比如 mmmmm739
//$filter="(|(sn=史平忠*)(givenname=史平忠*))";
$justthese = array('sn', 'department', 'company', 'objectsid', 'mail', 'givenName', 'displayName', 'telephoneNumber', 'memberof', 'samaccountname', 'primarygroupid'); //选择要获取的用户属性
// $justthese = array('*'); //选择要获取的用户属性
$justthese = array('SamAccountName','displayName'); //选择要获取的用户属性
//$sr=ldap_search($conn, $basedn,$filter );
$sr = ldap_search($conn, $basedn, $filter, $justthese);
echo "<pre>";
$info = ldap_get_entries($conn, $sr);
// print_r($info);
unset($info['count']);
print_r($info);
$new_info = array();
foreach($info as $key=>$value)
{
// unset($info[$key][0]);
// unset($info[$key]['count']);
$new_info[$key]['samaccountname'] = $value['samaccountname'][0];
$new_info[$key]['dn'] = $value['dn'];
$displayname = strrchr($value['displayname'][0],"(");
$displayname = substr($displayname,strpos($displayname,"(")+1,strpos($displayname,")")-1);
$new_info[$key]['displayname'] = $displayname;
}
foreach($new_info as $key=>$value)
{
if(!_start_with($value['dn'],'CN=T')){
unset($new_info[$key]);
}
$currentDn = $value['dn'];
$newParent = $suffix_dn = "OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn";
$newrDn = "CN=".$value['displayname']."(".$value['samaccountname'].")";
// $newRdn = "CN=".$value['displayname']."(".$value['samaccountname'].")";
// 检查新 DN 是否已存在
// $checkDn = ldap_search($conn, $baseDn, "(distinguishedName=$newrDn)");
// if (!$checkDn) {
// die("检查新 DN 失败: " . ldap_error($conn));
// }
// if (ldap_count_entries($ldapConn, $checkDn) > 0) {
// die("新 DN $newrDn 已存在,请选择其他 DN。");
// }
//var_dump($currentDn);
//var_dump($newrDn);
$modifyDn = ldap_rename($conn, $currentDn, $newrDn, $newParent, true);
if (!$modifyDn) {
var_dump(ldap_error($conn));
var_dump(ldap_errno($conn));
ldap_get_option($conn, LDAP_OPT_ERROR_STRING, $extendedError);
var_dump($extendedError);
die("失败!");
}
break; //先弄一个暂停一下,防止出错
}
echo "用户 DN 已成功修改为 $newrDn ";
// var_dump($new_info);
echo "</pre>";
if ($bd) {
echo 'LDAP 绑定成功'; //相当于登录成功
} else {
echo 'LDAP 绑定失败';
}
} else {
echo '无法连接到AD域服务器';
}
ldap_close($conn);
php ldap 根据 samaccountname 修改 dn
在 PHP 中通过 LDAP 修改用户条目的 DN(Distinguished Name)需要结合 sAMAccountName
进行搜索,并使用 ldap_rename
函数操作。以下是步骤说明和示例代码:
连接并绑定到 LDAP 服务器
根据 sAMAccountName
搜索用户,获取原 DN
使用 ldap_rename
修改 DN(移动或重命名条目)
关闭连接
<?php
// LDAP 服务器配置
$ldapServer = "ldap://your.ldap.server";
$ldapUser = "admin@example.com";
$ldapPass = "password";
$baseDn = "DC=example,DC=com";
// 目标用户的 sAMAccountName
$username = "johndoe";
// 新 DN 的组成部分(移动或重命名)
$newRdn = "CN=John Updated"; // 新 RDN(相对可分辨名称)
$newParent = "OU=NewOU,DC=example,DC=com"; // 新父级容器
// 1. 连接 LDAP
$ldapConn = ldap_connect($ldapServer);
ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapConn, LDAP_OPT_REFERRALS, 0);
// 2. 管理员绑定
$bind = ldap_bind($ldapConn, $ldapUser, $ldapPass);
if (!$bind) {
die("LDAP 绑定失败: " . ldap_error($ldapConn));
}
// 3. 搜索用户获取原 DN
$filter = "(&(objectClass=user)(sAMAccountName=$username))";
$search = ldap_search($ldapConn, $baseDn, $filter);
$entries = ldap_get_entries($ldapConn, $search);
if ($entries["count"] == 0) {
die("未找到用户: $username");
}
$oldDn = $entries[0]["dn"]; // 原完整 DN
// 4. 修改 DN(移动/重命名)
// 参数说明:链接、原DN、新RDN、新父级、删除旧RDN标记(通常为true)
$success = ldap_rename($ldapConn, $oldDn, $newRdn, $newParent, true);
if (!$success) {
die("修改 DN 失败: " . ldap_error($ldapConn));
}
echo "DN 修改成功!新路径: $newRdn,$newParent";
// 关闭连接
ldap_unbind($ldapConn);
?>
ldap_rename
函数
这是执行 DN 修改的核心函数,参数依次为:
$ldapConn
: LDAP 连接标识符
$oldDn
: 用户原完整 DN
$newRdn
: 新 RDN(如 CN=NewName
)
$newParent
: 新父级容器(如 OU=NewOU,DC=example,DC=com
)
true
: 表示删除旧 RDN(通常保持默认)
权限要求
操作 DN 需要足够的权限(如在 Active Directory 中,账户需对目标容器有“写入”权限)。
错误处理
检查 ldap_rename
返回值,失败时通过 ldap_error
获取错误信息。
移动条目而非重命名
如果仅需移动条目到新容器(不修改 RDN),保持 $newRdn
与原 RDN 一致(如 CN=John Doe
),仅修改 $newParent
。
特殊字符转义
若 DN 包含逗号、斜杠等字符,需使用 ldap_escape
进行转义:
$newRdn = "CN=" . ldap_escape("Doe, John", "", LDAP_ESCAPE_DN);
AD 特定行为
Active Directory 可能要求 newParent
是有效的容器路径,且操作可能需要域管理员权限。
通过上述方法,即可基于 sAMAccountName
定位并修改用户的 DN。
00000057: LdapErr: DSID-0C090F6D, comment: Error in attribute conversion operation, data 0, v3839
针对错误 00000057: LdapErr: DSID-0C090F6D, comment: Error in attribute conversion operation
,以下是逐步排查与解决方案:
此错误通常由 DN 格式不符合 LDAP 规范 引起,例如:
RDN(Relative Distinguished Name)中包含未转义的特殊字符(如 ,
、/
、#
、+
等)。
新的父级容器($newParent
)不存在或路径错误。
尝试修改的 DN 属性不符合目标目录架构(如非法的 CN
或 OU
)。
在构造新 RDN 时,需对特殊字符进行转义。使用 ldap_escape
函数处理名称部分:
// 转义 RDN 中的特殊字符 $newName = "John, Doe"; // 假设新名称包含逗号 $escapedName = ldap_escape($newName, "", LDAP_ESCAPE_DN); // 转义逗号为 "\2C" $newRdn = "CN=" . $escapedName; // 正确格式:CN=John\2C Doe
$newParent
) 是否存在
确保 $newParent
是有效的容器路径,且账户有写入权限。可通过 LDAP 浏览器(如 Apache Directory Studio)手动验证路径是否存在。
RDN 格式: 必须为 属性=值
(如 CN=John
)。
父级路径: 必须为完整 DN,例如 OU=Users,DC=example,DC=com
。
示例:
$newRdn = "CN=John Updated"; // 正确 $newParent = "OU=NewOU,DC=example,DC=com"; // 正确
// 假设原用户名为 "johndoe",新 RDN 为 "John, Updated" $username = "johndoe"; $newName = "John, Updated"; // 转义 RDN 名称部分 $escapedName = ldap_escape($newName, "", LDAP_ESCAPE_DN); $newRdn = "CN=$escapedName"; // CN=John\2C Updated // 新父级容器(需确保存在) $newParent = "OU=NewOU,DC=example,DC=com"; // 调用 ldap_rename $success = ldap_rename($ldapConn, $oldDn, $newRdn, $newParent, true);
输出构造的 DN:检查转义后的 RDN 和父级路径是否符合预期。
echo "尝试修改 DN 到: $newRdn,$newParent";
简化测试:先尝试仅重命名(不移动),验证是否是父级路径问题。
// 保持原父级路径不变 $newParent = null; // 或保持原路径
权限:确保绑定账户对原 DN 和新父级容器有 Write
权限。
架构限制:某些目录可能限制修改 CN
或强制属性唯一性(如避免重复的 sAMAccountName
)。
场景 | 错误示例 | 修复方案 |
---|---|---|
未转义逗号 | CN=John, Doe
| CN=John\2C Doe
|
父级路径不存在 | OU=GhostOU,DC=example,DC=com
| 创建 GhostOU 或修正路径 |
非法属性名 | UID=John (AD 中通常用 CN ) | 使用 CN=John
|
字符 | 转义表示 |
---|---|
,
| \2C
|
#
| \23
|
+
| \2B
|
/
| \2F
|
<
| \3C
|
>
| \3E
|
"
| \22
|
通过以上步骤,可修复 DN 格式
针对错误 00000057: LdapErr: DSID-0C090F6D, comment: Error in attribute conversion operation
的深度解析与解决方案
此错误表明 LDAP 目录服务在尝试修改条目时,无法正确解析或转换 DN 的属性值。以下是分步排查和解决方法:
该错误通常由以下原因引发:
DN 格式非法:RDN(Relative Distinguished Name)或父级路径包含未转义的特殊字符(如 ,
#
/
+
等)。
目标容器路径不存在:$newParent
参数指向的容器(如 OU)未创建或路径错误。
属性命名冲突:尝试修改后的 RDN 属性与目录架构冲突(如重复的 CN
)。
权限不足:绑定的账户无权限修改目标条目或移动条目到新容器。
使用 ldap_escape()
对 RDN 的值部分进行转义,确保符合 LDAP DN 规范。
错误示例:
$newRdn = "CN=John, Doe"; // 未转义逗号
修复代码:
$newName = "John, Doe"; $escapedName = ldap_escape($newName, "", LDAP_ESCAPE_DN); // 转义结果为 "John\2C Doe" $newRdn = "CN=" . $escapedName; // 正确格式:CN=John\2C Doe
$newParent
) 是否存在
确保 $newParent
是有效的容器路径。可通过以下代码检查:
// 检查新父级容器是否存在 $parentSearch = ldap_list($ldapConn, $newParent, "(objectClass=*)", ["dn"]); if (!$parentSearch || ldap_count_entries($ldapConn, $parentSearch) == 0) { die("新父级容器不存在: $newParent"); }
RDN 格式:必须为 属性=值
(如 CN=John
),且属性名符合目录架构(如 Active Directory 通常用 CN
,而非 UID
)。
父级路径:必须为完整 DN(如 OU=Users,DC=example,DC=com
)。
权限检查:确保绑定账户对原条目和新容器有 Write
权限(在 AD 中需检查 ACL)。
唯一性约束:确认新 RDN 的值在目标容器中唯一(如避免重复的 CN
)。
// 输出构造的新 DN 供检查 $proposednewrDn = "$newRdn,$newParent"; echo "调试信息 - 新 DN 构造结果: $proposednewrDn\n"; // 尝试仅重命名(不移动)以隔离问题 $success = ldap_rename($ldapConn, $oldDn, $newRdn, null, true); // $newParent 设为 null if ($success) { echo "重命名成功,问题可能出在父级路径!"; } else { echo "重命名失败,错误原因: " . ldap_error($ldapConn); }
检查项 | 方法 |
---|---|
RDN 转义 | 使用 ldap_escape($value, "", LDAP_ESCAPE_DN)
|
父级路径存在性 | 通过 ldap_list 查询验证 |
权限有效性 | 使用低权限账户模拟操作或检查 AD ACL |
目录架构匹配 | 确认属性名(如 CN /OU )符合目录类型(AD/OpenLDAP) |
若 RDN 包含中文或特殊符号,需确保编码一致(通常 UTF-8):
$newName = "张三_测试"; $escapedName = ldap_escape($newName, "", LDAP_ESCAPE_DN); $newRdn = "CN=" . $escapedName; // CN=张三_测试
禁止修改 CN
:AD 中某些对象(如内置管理员)的 CN
不可修改。
系统保留 RDN:如 CN=Users
无法直接重命名,需通过特殊方法操作。
Active Directory:查看 事件查看器 -> Windows 日志 -> 目录服务
,过滤事件 ID 为 5136
(对象修改事件)。
OpenLDAP:检查 slapd.log
,搜索错误代码 00000057
。
若问题仍无法解决,可改用以下方法:
删除并重建条目:备份属性,删除旧条目,在新路径创建条目(需处理 SID 等唯一标识问题)。
使用 PowerShell 或命令行工具:验证是否为代码逻辑问题:
Get-ADUser -Identity "johndoe" | Move-ADObject -TargetPath "OU=NewOU,DC=example,DC=com"
总结:
错误 00000057
的核心在于 DN 构造不符合目录服务的格式或权限要求。通过逐步验证 RDN 转义、父级路径存在性、账户权限和目录架构,结合服务器日志,可精准定位问题根源。
错误导致的 00000057
问题。若仍失败,需结合服务器日志(如 AD 事件日志)进一步分析。
Naming violation 64 00000057: LdapErr: DSID-0C090F6D, comment: Error in attribute conversion operation, data 0, v3839
根据你提供的代码和错误信息,问题主要出在 DN 格式不符合 LDAP 规范,尤其是 RDN(Relative Distinguished Name)中的特殊字符未转义 和 ldap_rename
函数参数使用不当。以下是具体分析和修复方案:
RDN 中的特殊字符未转义
你构造的 CN
值中可能包含以下字符:
括号 (
和 )
:需要转义为 \28
和 \29
。
逗号 ,
:需要转义为 \2C
。
其他特殊字符如空格、#
、/
等也需要转义。
ldap_rename
参数使用错误
你试图将完整的新 DN($newrDn
)传递给 ldap_rename
的第二个参数,但该函数要求:
第三个参数是新的 RDN(如 CN=NewName
)。
第四个参数是新的父级路径(如 OU=NewOU,DC=example,DC=com
)。
$currentDn = $value['dn']; $displayname = $value['displayname']; $samaccountname = $value['samaccountname']; // 1. 转义 RDN 中的特殊字符(括号、逗号等) $escapedDisplayName = ldap_escape($displayname, "", LDAP_ESCAPE_DN); $escapedSamAccountName = ldap_escape($samaccountname, "", LDAP_ESCAPE_DN); // 2. 构造新的 RDN(仅包含 "CN=..." 部分) $newRdn = "CN=" . $escapedDisplayName . "\\28" . $escapedSamAccountName . "\\29"; // 转义括号为 \28 和 \29 // 3. 新父级路径(确保此路径存在!) $newParent = "OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn"; // 4. 调用 ldap_rename(正确传递 RDN 和父级路径) $modifyDn = ldap_rename($conn, $currentDn, $newRdn, $newParent, true); if (!$modifyDn) { $error = ldap_error($conn); die("修改 DN 失败: $error"); } echo "用户 DN 已成功修改为 $newRdn,$newParent。";
转义特殊字符
使用 ldap_escape
对 displayname
和 samaccountname
中的特殊字符进行转义。
手动转义括号 (
和 )
为 \28
和 \29
(例如 "(user)"
→ "\28user\29"
)。
正确使用 ldap_rename
参数
第三个参数 ($newRdn
):仅包含新的 RDN(如 CN=John\2C Doe
)。
第四个参数 ($newParent
):指向目标父级容器(如 OU=NewOU,...
)。
验证父级路径存在性
在代码中添加检查,确保 $newParent
存在:
// 检查父级路径是否存在 $search = ldap_list($conn, $newParent, "(objectClass=organizationalUnit)", ["dn"]); if (!$search || ldap_count_entries($conn, $search) === 0) { die("父级容器不存在: $newParent"); }
如果仍然失败
检查绑定的账户是否有权限修改目标条目。
使用 ldap_error($conn)
输出详细错误信息。
确保 $newParent
的路径层级正确(如中文 OU 名称可能导致编码问题)。
调试输出
打印构造的 RDN 和完整 DN,手动验证格式:
echo "新 RDN: $newRdn"; echo "完整 DN: $newRdn,$newParent";
假设原 DN 为:CN=张三(user1),OU=OldOU,DC=aaaaa,DC=com,DC=cn
修改后 DN 应为:CN=张三\28user1\29,OU=K88888项目,OU=rrrrrSite,OU=eeeee集团,DC=aaaaa,DC=com,DC=cn
通过以上修复,可解决 00000057
错误。如果问题仍存在,请检查服务器日志或使用 LDAP 浏览器(如 Apache Directory Studio)手动验证操作。