PHP 大会日本 2024

LDAP 函数

目录

添加注释

用户贡献的注释 34 条注释

idbobby at rambler dot ru
14 年前
首先,对于我的英语表示歉意。
这里有两个函数可以检查组成员资格,以及其他一些对使用 LDAP(在此示例中为 Active Directory)有用的函数。

index.php
---------

<?php

$user
= 'bob';
$password = 'zhlob';
$host = 'myldap';
$domain = 'mydomain.ex';
$basedn = 'dc=mydomain,dc=ex';
$group = 'SomeGroup';

$ad = ldap_connect("ldap://{$host}.{$domain}") or die('无法连接到LDAP服务器。');
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
@
ldap_bind($ad, "{$user}@{$domain}", $password) or die('无法绑定到AD。');
$userdn = getDN($ad, $user, $basedn);
if (
checkGroupEx($ad, $userdn, getDN($ad, $group, $basedn))) {
//if (checkGroup($ad, $userdn, getDN($ad, $group, $basedn))) {
echo "您已授权为 ".getCN($userdn);
} else {
echo
'授权失败';
}
ldap_unbind($ad);

/*
* 此函数在LDAP树中搜索($ad - LDAP链接标识符)
* 通过samaccountname指定的条目并返回其DN或在失败时返回空
* 字符串。
*/
function getDN($ad, $samaccountname, $basedn) {
$attributes = array('dn');
$result = ldap_search($ad, $basedn,
"(samaccountname={$samaccountname})", $attributes);
if (
$result === FALSE) { return ''; }
$entries = ldap_get_entries($ad, $result);
if (
$entries['count']>0) { return $entries[0]['dn']; }
else { return
''; };
}

/*
* 此函数从给定的DN中检索并返回CN
*/
function getCN($dn) {
preg_match('/[^,]*/', $dn, $matchs, PREG_OFFSET_CAPTURE, 3);
return
$matchs[0][0];
}

/*
* 此函数检查用户的组成员资格,仅在
* 指定的组中搜索(非递归)。
*/
function checkGroup($ad, $userdn, $groupdn) {
$attributes = array('members');
$result = ldap_read($ad, $userdn, "(memberof={$groupdn})", $attributes);
if (
$result === FALSE) { return FALSE; };
$entries = ldap_get_entries($ad, $result);
return (
$entries['count'] > 0);
}

/*
* 此函数检查用户的组成员资格,在
* 指定的组及其成员组中搜索(递归)。
*/
function checkGroupEx($ad, $userdn, $groupdn) {
$attributes = array('memberof');
$result = ldap_read($ad, $userdn, '(objectclass=*)', $attributes);
if (
$result === FALSE) { return FALSE; };
$entries = ldap_get_entries($ad, $result);
if (
$entries['count'] <= 0) { return FALSE; };
if (empty(
$entries[0]['memberof'])) { return FALSE; } else {
for (
$i = 0; $i < $entries[0]['memberof']['count']; $i++) {
if (
$entries[0]['memberof'][$i] == $groupdn) { return TRUE; }
elseif (
checkGroupEx($ad, $entries[0]['memberof'][$i], $groupdn)) { return TRUE; };
};
};
return
FALSE;
}

?>
oscar dot php at linaresdigital dot com
9年前
关于accountExpires、pwdLastSet、lastLogon和badPasswordTime Active Directory字段存在很多混淆。

它们都使用“间隔”日期/时间格式,其值表示自1601年1月1日(UTC)以来的100纳秒间隔数(值为0或0x7FFFFFFFFFFFFFFF,9223372036854775807,表示帐户永不过期):https://msdn.microsoft.com/en-us/library/ms675098(v=vs.85).aspx

因此,如果您需要将其从UNIX时间戳转换为/从UNIX时间戳转换,您可以轻松计算出差异:

<?php
$datetime1
= new DateTime('1601-01-01');
$datetime2 = new DateTime('1970-01-01');
$interval = $datetime1->diff($datetime2);
echo (
$interval->days * 24 * 60 * 60) . " 秒\n";
?>

这两个日期之间的差值为11644473600秒。不要依赖浮点计算或其他可能计算错误的数字(包括时区或类似内容)。

现在您可以从LDAP字段转换:

<?php
$lastlogon
= $info[$i]['lastlogon'][0];
// 除以10,000,000以从100纳秒间隔获取秒数
$winInterval = round($lastlogon / 10000000);
// 减去1601-01-01 -> 1970-01-01的秒数
$unixTimestamp = ($winInterval - 11644473600);
// 在本地时区显示日期/时间
echo date("Y-m-d H:i:s", $unixTimestamp) ."\n";
?>

希望对您有所帮助。
maykelsb at yahoo dot com dot br
17年前
W2k3中ldap_search的问题,可以通过添加以下内容解决

// -- $conn是一个有效的ldap连接。

ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,3);
ldap_set_option($conn, LDAP_OPT_REFERRALS,0);

在ldap_bind之前,如http://bugs.php.net/bug.php?id=30670.中所述。
gcathell at thetdgroup dot com
18年前
我最近需要通过SSL将Microsoft Active Directory服务器作为LDAP服务访问,使用PHP。我花了很长时间才收集到所有必要的信息使其正常工作。

我尝试在这里发布一个包含详细信息的说明,但最终内容过长。我已将详细信息放在以下URL中,希望其他人从中受益,并能够比我更快地解决问题。

http://greg.cathell.net/php_ldap_ssl.html

祝你好运!
spam2004 at turniton dot dk
20年前
以下是有两个小型函数,使您可以将Microsoft AD中的二进制objectSID转换为更有用的文本版本(格式化(S-1-5.....))。

// 将小端序十六进制数字转换为'hexdec'可以转换的数字
function littleEndian($hex) {
for ($x=strlen($hex)-2; $x >= 0; $x=$x-2) {
$result .= substr($hex,$x,2);


}
return $result;
}

// 返回文本格式的 SID
function binSIDtoText($binsid) {
$hex_sid=bin2hex($binsid);
$rev = hexdec(substr($hex_sid,0,2)); // 获取 SID 的版本部分
$subcount = hexdec(substr($hex_sid,2,2)); // 获取子授权项的数量
$auth = hexdec(substr($hex_sid,4,12)); // SECURITY_NT_AUTHORITY
$result = "$rev-$auth";
for ($x=0;$x < $subcount; $x++) {
$subauth[$x] = hexdec(littleEndian(substr($hex_sid,16+($x*8),8))); // 获取所有 SECURITY_NT_AUTHORITY
$result .= "-".$subauth[$x];
}
return $result;
}

echo binSIDtoText($bin_sid);
hijinio at comcast dot net
19 年前
如果有人在 Solaris 10 系统上配置 PHP 的 LDAP 支持时遇到问题,以下是我使用的配置命令行

./configure --with-nsapi=/opt/SUNWwbsvr --enable-libgcc --disable-libxml --with-ldap=/usr/local --prefix=/opt/php/php-5.0.4

需要注意的重要部分是 --with-ldap= 使用的位置;对于大多数 S10 用户来说,将是 "--with-ldap=/usr/local"。
Richie Bartlett(at)ITsystems-Online com
19 年前
这是对 <i>wtfo at technocraft dot com</i>(2002 年 5 月 23 日 03:40)的更新... 此函数允许添加额外的(可选)参数。之前列出的函数在成功身份验证后未能关闭 ldap 连接。

<?php
function checkNTuser($username,$password,$DomainName="myDomain",
$ldap_server="ldap://PDC.example.net"){//v0.9
// 当用户/密码能够绑定到 LDAP(Windows 2k)时返回 true。
$auth_user=$username."@".$DomainName;
#echo $auth_user."->";
if($connect=@ldap_connect($ldap_server)){
#echo "connection ($ldap_server): ";
if($bind=@ldap_bind($connect, $auth_user, $password)){
#echo "true <BR>";
@ldap_close($connect);
return(
true);
}
//if bound to ldap
}//if connected to ldap
#echo "failed <BR>";
@ldap_close($connect);
return(
false);
}
//end function checkNTuser
?>
ant at solace dot mh dot se
20年前
在使用 LDAP 时,值得记住的是大多数
LDAP 服务器使用 UTF-8 编码其字符串。对于非 ASCII 字符串来说,这意味着
在为 LDAP 服务器创建过滤器时,需要使用 utf8_encode 和
utf8_decode 函数。

当然,如果可以,更简单的方法是避免使用非 ASCII 字符
但对于大多数站点,用户希望看到他们奇怪的本地字符
集,包括变音符号等。

如果您在期望非 ASCII 字符的地方只得到“?”字符,那么
您可能只需要升级您的 PHP 版本。
christopherbyrne at hotmail dot com
19 年前
对于任何在阅读以下文章后遇到 Active Directory 中“accountexpires”属性问题的用户

www.microsoft.com/technet/scriptcenter/
resources/qanda/sept05/hey0902.mspx

或类似的文章,这可能会帮您省去一些麻烦。在文章中提到,此属性是一个整数,表示自 1601 年 1 月 1 日 00:00:00 以来经过的纳秒数。

但是,“accountexpires”属性实际上似乎是自 1600 年 12 月 31 日 14:00:00 以来经过的 100 纳秒增量的数量。因此,如果您将整数除以 10,000,000 并减去 11644560000,您将获得一个与 AD 中日期匹配的 Unix 时间戳。

要设置“accountexpires”日期,只需反转此过程,即获取所需新日期的时间戳,添加 11644560000 并乘以 10,000,000。您还需要格式化结果数字,以确保它不会以科学记数法输出,以便 AD 可以正常使用它。

希望这有帮助!
llurovi at gmail dot com
8 年前
对于那些在用户密码包含特殊字符时遇到问题的用户,请确保将字符串解码为适当的编码。例如,我遇到了一些用户无法正常登录到我们的 Web 应用程序的问题。

简单连接示例

<?php

$ldap_ip
= 'LDAP-SERVER-IP';
$ldap = ldap_connect($ldap_ip);

$user = 'Test';
$password = 'otoño'; //此密码正确,但使用此格式绑定会报错

$password = utf8_decode($password); //$password = otoxF1o

$ldap_bind = ldap_bind($ldap, $user, $password); //现在绑定成功,$ldap_bind = true

?>
unroar at gmail dot com
17年前
在 Solaris 9 中,libnet 库是使用 LDAP、SASL 和 SSL 构建 PHP 的先决条件(libnet 可在 Sunfreeware 上获得)。

我没有在任何地方看到提及这一点,我不确定它是 ldap、sasl 还是 ssl 所需的。我在 Google 上搜索了一个小时都没有结果,然后才弄清楚,也许这条评论可以帮助下一个 Google 搜索者。

错误是:
ld: fatal: library -lnet: not found
ld: fatal: File processing errors. No output written to sapi/cli/php
collect2: ld returned 1 exit status
make: *** [sapi/cli/php] Error 1
alex at netflex dot nl
17年前
如果您想在 Windows 上使用 ldaps,但不想验证 tls 证书,请在 ldap_connect 调用之前尝试以下代码行

putenv('LDAPTLS_REQCERT=never') or die('Failed to setup the env');
jabba at zeelandnet dot nl
20年前
在 Windows 上使用 PHP 时,如果您尝试连接(绑定)到需要安全连接 (LDAPS) 的 Netware (6) LDAP 服务器,PHP 将返回一条消息,指出找不到服务器。

连接尝试期间发生的网络流量捕获显示服务器提供了用于 SSL 连接的证书,但客户端拒绝了此证书(***bad certificate SSLv3 packet)。

造成这种情况的原因可能是 PHP LDAP 实现尝试使用颁发证书的 CA 验证收到的证书。可能有一种方法可以使此验证成功,但也可以通过创建 openldap(令人惊讶!!)配置文件来禁用客户端(在本例中为 PHP)的此验证。

此配置文件的位置似乎在 Windows 的 LDAP 支持模块中是硬编码的,您可能需要手动创建以下目录结构

C:\openldap\sysconf\

在 sysconf 文件夹中,创建一个名为“ldap.conf”的文本文件(您可以使用记事本来执行此操作),并且,要禁用证书验证,请在 ldap.conf 文件中放置以下行

TLS_REQCERT never

之后,所有正常的 ldap_bind 调用都将起作用,前提是您提供的用户 ID 和密码正确。
Sami Oksanen
20年前
我编辑了 Jon Caplinger 的代码,该代码位于下方(日期:2002 年 11 月 9 日 05:44)。

- 我更正了以下代码行
"if (!($connect=@ldap_connect($ldap))) {" 改为
"if (!($connect=@ldap_connect($ldap_server))) {"

- 删除了 $name 属性

- “Name is:” 字段始终是数组,因此我将打印代码行更改为
" echo "Name is: ". $info[$i]["name"][0]."<br>";"

我还添加了一些备选搜索过滤器以供尝试。

以下是代码

<?php

$ldap_server
= "ldap://foo.bar.net";
$auth_user = "[email protected]";
$auth_pass = "mypassword";

// 设置搜索整个目录的基本 DN。

$base_dn = "DC=bar, DC=net";

// 仅显示用户人员
$filter = "(&(objectClass=user)(objectCategory=person)(cn=*))";

// 启用以仅显示用户
// $filter = "(&(objectClass=user)(cn=$*))";

// 启用以显示所有内容
// $filter = "(cn=*)";

// 连接到服务器

if (!($connect=@ldap_connect($ldap_server))) {
die(
"无法连接到 ldap 服务器");
}

// 绑定到服务器

if (!($bind=@ldap_bind($connect, $auth_user, $auth_pass))) {
die(
"无法绑定到服务器");
}

//if (!($bind=@ldap_bind($connect))) {
// die("Unable to bind to server");
//}

// 搜索活动目录

if (!($search=@ldap_search($connect, $base_dn, $filter))) {
die(
"无法搜索 ldap 服务器");
}

$number_returned = ldap_count_entries($connect,$search);
$info = ldap_get_entries($connect, $search);

echo
"返回的条目数为 ". $number_returned."<p>";

for (
$i=0; $i<$info["count"]; $i++) {
echo
"名称为: ". $info[$i]["name"][0]."<br>";
echo
"显示名称为: ". $info[$i]["displayname"][0]."<br>";
echo
"电子邮件为: ". $info[$i]["mail"][0]."<br>";
echo
"电话号码为: ". $info[$i]["telephonenumber"][0]."<p>";
}
?>
ben_demott at hotmail dot com
16 年前
对于任何程序员来说,如果不熟悉 Microsoft Active Directory 中的命名约定或如何在目录中查找对象,或者更重要的是如何引用这些对象,这将很有帮助。
从命令行运行“adsiedit.msc”将在目录中以易于阅读和复制的命名格式显示所有对象。
希望这有帮助!

注意
您必须从 AD 域控制器运行此命令
您必须安装 Windows 资源工具包工具
(不允许我创建这么长的链接,所以我不得不创建链接断开 - 对不起!)
a http://www.microsoft.com/downloads/details.aspx
?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&displaylang=en

安装此工具应该会修改您的系统路径,以便您只需从运行对话框中键入命令,否则绝对路径为
C:\Program Files\Windows Resource Kits\Tools\adsiedit.msc
nacenroe at remove dot this dot nystec dot com
18年前
如果您希望使用 PHP 将 LDAP 与 AD 集成(我正在使用 Win2K3),您可能需要修改 Win2k 和 Win2K3 中包含的 LDP.exe 工具(不需要资源工具包!!)。您可以直接从命令行运行此应用程序。

Win2K3 帮助功能是一个良好的起点,然后它指向了 M$ KB 中的一篇文章:http://support.microsoft.com/default.aspx?scid=kb;en-us;255602(XADM:使用 LDP 实用程序浏览和查询)。

所以...如果您的连接/绑定正在工作但您的查询没有工作,您可能需要从这里开始。当我在本地 AD 上运行它时,我发现它在查看属性等方面非常有用。
christopherbyrne at hotmail dot com
19 年前
只是对我之前帖子的修正:我的计算使用的是澳大利亚东部时间 (GMT+10),而 Unix 时间戳是 GMT。因此,Active Directoy 的“accountexpires”整数值确实从 1601 年 1 月 1 日 00:00:00 GMT 开始,并且此日期与 1970 年 1 月 1 日 00:00:00 GMT 之间的时间差为 11644524000 秒。

不过,增量仍然肯定以 100 纳秒为单位!
jpmens at gmail dot com
19 年前
补充 jabba at zeelandnet dot nl 的说明。如果您尝试使用 OpenLDAP 连接到 LDAPS URI,您可以按照 jabba 的描述创建配置文件,或者选择使用环境设置将 LDAPTLS_REQCERT=never 设置为 ldap.conf(5) 中所述。
knitterb at blandsite dot org
22 年前
在将 PHP 4.2.1 与 OpenLDAP 2.1.2 一起使用时,我在绑定到 ldap 服务器时遇到问题。我发现 php 使用的是旧协议,并在 slapd.conf 中添加了以下内容

allow bind_v2

有关 slapd.conf 文件中 allow 项的更多信息,请参阅“man slapd.conf”,这就是我所知道的全部! :)
Jimmy Wimenta Oei
20年前
如果要禁用/启用追查引用选项,则需要首先将协议版本设置为版本 3,否则 LDAP_OPT_REFERRALS 选项将不起作用。这对于查询 MS Active Directory 尤其如此。

<?php
ldap_set_option
($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
?>

并且像往常一样,这些应该在连接后但在绑定之前调用。
Andrew Sharpe
12 年前
要在 RHEL 6.2 x86_64 上编译 PHP 5.1.6,请将以下内容添加到您的配置命令中

--with-libdir=lib64
--with-ldap=/usr
pookey at pookey dot co dot uk
21 年前
这是一个查询 LDAP 服务器并打印所有条目的示例。

<?php

$ldapServer
= '127.0.0.1';
$ldapBase = 'DC=anlx,DC=net';

/*
* 尝试连接到服务器
*/
$ldapConn = ldap_connect($ldapServer);
if (!
$ldapConn)
{
die(
'无法连接到 LDAP 服务器');
}

/*
* 匿名绑定
*/
$ldapBind = ldap_bind($ldapConn);
if (!
$ldapBind)
{
die(
'无法绑定到 LDAP 服务器');
}

/*
* 设置 ldap 选项
*/
ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);

/*
* 搜索 LDAP 服务器
*/
$ldapSearch = ldap_search($ldapConn, $ldapBase, "(cn=*)");
$ldapResults = ldap_get_entries($ldapConn, $ldapSearch);

for (
$item = 0; $item < $ldapResults['count']; $item++)
{
for (
$attribute = 0; $attribute < $ldapResults[$item]['count']; $attribute++)
{
$data = $ldapResults[$item][$attribute];
echo
$data.":&nbsp;&nbsp;".$ldapResults[$item][$data][0]."<br>";
}
echo
'<hr />';
}

?>
greatsafari at hotmail dot com
21 年前
看到这么多连接和查询Active Directory服务器的方法变体,我真的很怀疑整个过程都依赖于Active Directory的配置。查看这篇文章:

http://www.phpbuilder.com/mail/php-general/2003022/1459.php

一些在某个实例中证明有效的方法在另一个实例中失败了。
nliu99 at nospam dot yahoo dot com
21 年前
libsasl.dll对于ldap功能**不是**必需的。查看以下帖子:http://bugs.php.net/bug.php?id=9485

在Win2k上,我按照以下简单步骤操作,使ldap工作起来
1. 将php_ldap.dll从扩展文件夹复制到winnt/system32
2. 编辑winnt/php.ini,启用ldap(取消注释该行)。
3. 重启IIS。
就是这样,尽情享受ldap吧。

关于Microsoft Active Directory的说明
1. 你可以使用用户电子邮件登录,例如[email protected]
2. 最简单的方法是使用ldap_search通过以下筛选器搜索用户信息:(userprincipalname=[user])
egeczi at nospamplease dot dist113 dot org
21 年前
在运行IIS的Win2k Server上,仅仅在启用php_ldap扩展后重启IIS是不够的。你需要重启服务器本身。
yorch at correo dot ath dot cx
21 年前
关于在Win2k机器上运行LDAP扩展的一些说明

在将php_ldap.php和libsasl.dll复制到所有可能的目录(c:\WinNT\System32、c:\php…)后,我决定阅读installation.txt文件。
安装php扩展的说明如下:“某些PHP扩展需要一些额外的DLL。请将捆绑的dll从发行包中的'dlls/'目录复制到您的windows/system(Win9.x)或winnt/system32(WinNT、Win2000、XP)目录。如果您的系统上已经安装了这些DLL,只有在某些功能无法正常工作时才覆盖它们。”

所以我做了以下操作:将“c:\php\dlls”中的所有dll文件复制到“c:\WinNT\System32”。
现在它们加载得非常漂亮;-)

希望这对某些人有所帮助。
Tod
17年前
在Win2k3上运行PHP 4和Apache 2.2的用户请注意。
为了使ldap_connect返回结果,Apache服务需要在本地管理员帐户下运行。这与Active Directory域中的服务器上可能发生的域管理员帐户相反。

否则,它看起来似乎工作正常,但不会返回任何结果。

因此,在服务登录属性中使用(服务器名称)\administrator作为用户名。

Tod
jector at inbox dot ru
17年前
花了一些时间修复“无法加载动态库'php_ldap.dll'”。将libeay32.dll和ssleay32.dll复制到各个地方,但错误仍然存在。

在挖掘所有这些dll后,我发现libeay32.dll和ssleay32.dll都需要msvcr70.dll(或msvcr71.dll,取决于编译器版本)。然后只需将该dll复制到system32\目录,它就可以完美运行。
nigelf at esp dot co dot uk
18年前
在Active Directory中跟踪引用(例如:跨域搜索)可能会很慢。您可以按照以下步骤在GC(全局编录)中查找对象

在使用ldap_connect时,删除对ldap://的任何引用,例如:使用“serv1.mydom.com”而不是“ldap://serv1.mydom.com”

连接到端口3268(而不是默认的389)。

将搜索的基本DN设置为null,即""(空字符串)。

然后,AD将在包含林中所有对象的副本的GC上运行搜索。您还可以检索属性的子集(包括组成员身份,但不包括本地组)。

对于完整的一组属性,您仍然需要跟踪引用。
hkemale at hkem dot com
21 年前
适用于IIS+PHP+NTFS文件系统用户
在将<php_dir>/dlls/*.dll复制到<windows>/systems32/后,请记住为“everyone”和扩展名*.dll添加读取和执行权限。这可以防止php_ldap.dll的“拒绝访问”警告。
gerbille at free dot fr
22 年前
PHP返回的MD5结果使用base16编码。但LDAP MD5返回使用base64编码的字符串。
$pwd="toto";
$pwd_md5=base64_encode(mhash(MHASH_MD5,$pwd));
只需在$pwd_md5前面添加"{MD5}"即可获得与LDAP目录相同的格式。

再见
奥莱莉亚
mike at whisperedlies dot org
22 年前
除了上面提到的NetBIOS建议外,在绑定到Windows 2k AD服务器时,可以使用目标用户的UPN。例如,如果您的SAM帐户名称为firstname.lastname,您的域名是domainname.com,那么您的UPN可能是[email protected]

这可以用于绑定到AD。我还没有在任何方法中看到任何差异。
rusko dot marton at gibzone dot hu
22 年前
您可以通过使用用户名简化的NetBIOS格式轻松地认证到Windows 2000域的ldap服务器。

有人写道
在认证到Win2k LDAP服务器时,人员的名称必须是
dn中的完整名称

不。您可以使用此格式

$user = "DOMAINNAME\\username"
$password = "Password_of_user";

if (!$connect = ldap_connect("<server>", <port>)) {
//错误
exit;
}
if (!$res = @ldap_bind($ldap, $user, $password)) {
//错误
exit;
}

它在Active Directory中运行良好,我们正在使用它。
webmaster at autourdupc dot com
22 年前
在认证到Win2k LDAP服务器时,人员的名称必须是dn中的完整名称

注意:不区分大小写!

$dn="cn=DUPOND John, cn=Users, dc=autourdupc, dc=com"
$password = "Password_of_DUPOND";

然后,当您绑定到LDAP数据库时,请使用

if (!($ldap = ldap_connect("<server>", <port>))) {
die ("无法连接到LDAP服务器");
}
if (!($res = @ldap_bind($ldap, $dn, $password))) {
die ("无法绑定到$dn");
}

希望这对每个人都有用!
To Top