artnum/ldap-helper

用于抽象 ldap_* 函数的辅助类

1.0.5 2021-03-31 13:26 UTC

This package is auto-updated.

Last update: 2024-09-29 05:22:30 UTC


README

php-ldap 扩展过度使用了 C API 的不良方面,而没有充分利用其良好方面。它也没有提供 LDAP 的全部功能。因此,这个辅助工具试图解决所有这些问题。

第一个和下一个条目/属性/等等

LDAP 协议的可爱之处在于其处理查询和结果的方式。基于事件的现代网络编程已经存在。您可以在数据尚未全部到达的情况下开始处理。这并不意味着它是以这种方式实现的,但它可以以这种方式实现。因此,当您发送一个查询时,您会收到第一个对象,处理它,然后到达可能已在中间接收到的第二个对象。

$conn = ldap_connect(....);
ldap_set_option(....);
ldap_bind(....);
$result = ldap_search($conn, ....);
for ($entryid = ldap_first_entry($conn, $result); $entryid; $entryid = ldap_next_entry($conn, $entryid)) {
    $entry = []
    for ($attr = ldap_first_attribute($conn, $entryid); $attr; ldap_next_attribute($conn, $entryid)) {
        $attributeValue = ldap_get_values($conn, $entryid, $attr);
        // or, in case of binary value
        $attributeValue = ldap_get_values_len($conn, $entryid, $attr);

        $entry[$attr] = $attributeValue;
    }
}

非常像 C 语言。使用辅助工具,大部分样板代码已经完成。默认情况下,它返回一个条目对象(LDAPHelperEntry)

$helper = new LDAPHelper();
$helper->addServer(....);
$results = $helper->search(....);
foreach ($results as $result) {
    for ($entry = $result->firstEntry(); $result; $entry = $result->nextEntry()) {
        $entry->dump()
    }
}

上层循环(foreach)存在是因为您可以添加多个服务器。这样做可以轻松地在委派服务器中进行搜索。您还可以有只读服务器和读写服务器。内层循环(for)允许获取每个条目,而无需关心属性和二进制/非二进制属性。魔力在于根 DSE。

根 DSE 解析

当添加服务器时,LDAPHelper::addServer(....),服务器配置会直接从服务器读取。其命名上下文或“基准”,协议版本或可用的属性类型和对象类。这意味着您只需要提供一个 URI 和身份验证参数即可开始使用任何 LDAP 服务器。

$helper = new LDAPHelper();
$helper->addServer('ldapi:///', 'simple', ['dn' => 'cn=admin,dc=example,dc=com', 'password' => 'secret'], true); // readonly server
$helper->addServer('ldaps://write.example.com', 'simple', ['dn' => 'cn=admin,dc=example,dc=com', 'password' => 'secret']); // readwrite server
$helper->addServer('ldaps://delegated.example.com', 'simple', ['dn' => 'cn=admin,dc=delegated,dc=example,dc=com', 'password' => 'secret']); // readwrite server

$results = $helper->search('dc=example,dc=com', '(objectclass=inetorgperson)', ['*'], 'sub');

在两个服务器上执行子树搜索。'ldapi:////' 和 'ldaps://write.example.com' 为 'dc=example,dc=com' 提供服务,因此只读服务器更受青睐(我们正在执行只读操作)。由于搜索发生在上层,因此也会查询委派服务器。

用法

添加服务器

假设您在 Linux 上运行一个 OpenLDAP。假设 Web 服务器进程以用户 id 33(www-data)和组 id 33(www-data)运行。假设您在 UNIX 套接字(ldapi://)和 ldap:// 上运行服务器。假设您在 OpenLDAP 配置中具有以下 acl 访问权限

olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
olcAccess: {1}to * by dn.exact=gidNumber=33+uidNumber=33,cn=peercred,cn=external,cn=auth write by * break
olcAccess: {2}to * by * read

这意味着 root 用户可以管理服务器,www-data 用户可以写入,任何人都可以读取(这不是您想要在生产服务器上配置的方式)。您会添加两个服务器

$helper = new LDAPHelper();
$helper->addServer('ldapi:///', 'sasl', ['mech' => 'EXTERNAL']);
$helper->addServer('ldap://', 'simple', [], true);

写入将发送到 ldapi:///,而读取则发送到 ldap://。

搜索条目

当搜索条目时,您会得到一个 LDAPHelperResult 数组。原因是如果您有多个上下文或一个服务器,您将会有多个正在运行多个结果集的请求。因此,为了在使用上保持一致性,搜索始终返回一个数组。甚至读取一个特定的 DN 也可能有多个结果,因为它们可能位于多个服务器上。搜索正在做所有工作,您可以选择范围(搜索子树、列出子树或读取对象)的参数 $scope。

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);

$base = '....';
$filter = '(objectclass=*)';
$attrs = ['*'];

$results = $helper->search($base, $filter, $attrs, 'sub'); // subtree search
// or
$results = $helper->search($base, $filter, $attrs, 'one'); // list search (one level)
// or
$results = $helper->search($base, $filter, $attrs, 'base'); // read object

foreach ($results as $rset) {
    for($entry = $rset->firstEntry(); $entry; $entry = $rset->nextEntry()) {
        // process entry
    }
}

添加条目

要添加条目,创建一个 LDAPHelper,添加一些服务器并创建一个 LDAPHelperEntry。设置 DN,添加属性,然后完成。

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);
$newEntry = new LDAPHelperEntry($helper);
// if you have a server with naming context dc=example,dc=com it will be choosen
$newEntry->dn('cn=test,dc=example,dc=com');
$newEntry->add('objectclass', ['person']);
$newEntry->add('sn', ['test']); // person must have sn attribute
$newEntry->commit()

修改条目

当您有一个 LDAPHelperEntry 时,您可以很容易地进行修改

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);

$results = $helper->search(....);
$entry = $results->firstEntry();
$entry->replace('sn', ['test']); // replace attribute sn
$entry->delete('l'); // delete attribute l
$entry->add('postalcode', ['1234567890']); // add attribute postalcode
$entry->commit();

您可以替换、添加或删除任何属性。如果您想取消所有修改,您有回滚而不是提交。

当提交完成后,对象的值反映了 LDAP 服务器上的内容,而无需读取它,本地保留了一个副本,并将更改应用于它。

移动/重命名条目

您可以移动一个条目。此操作与修改和/或重命名一起在线完成。您可以在一次提交中添加、替换、删除、移动和重命名。操作按顺序执行:先重命名,然后如果成功则执行添加/替换/删除,最后执行移动。所以它会像这样

$entry->delete('sn', ['test']);
$entry->move('ou=newparent,dc=example,dc=com');
$entry->rename('sn=test2');
$entry->commit();

重命名会负责添加所需的属性(如果尚未添加)。它不会删除旧的,您必须自己操作。

删除条目

当您拥有DN时,只需从辅助程序调用删除即可。

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);

$dn = '....';
$helper->delete($dn);

获取所有命名上下文(自1.0.1起)

您可以使用getNamingContexts获取每个服务器上找到的所有命名上下文(无论是读服务器还是写服务器)。

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);

$helper->getNamingContexts(); // writers naming contexts
$helper->getNamingContexts(true); // readers naming contexts

遍历属性(自1.0.2起)

一旦您有一个条目,您可能想要遍历每个属性。使用生成器eachAttribute:$helper-

$helper = new LDAPHelper();
$helper->addServer(....);
$results = $helper->search(....);
$entry = $results->firstEntry();

foreach($entry->eachAttribute as $name => $value) {
    // do what you want with the attribute and its value
}

查找每个服务器上支持的所有objectclass(自1.0.2起)

如果您需要知道每个服务器上存在哪些objectclass,请使用getClasses。

$helper = new LDAPHelper();
$helper->addServer(....);
$helper->addServer(....);
$helper->addServer(....);

$helper->getClasses(); // an array of all known classes

回滚

更改是在本地进行的。您调用commit将它们应用于目录。因此,它不是一个真正的“回滚”。例如,如果您重命名和修改一个条目,但在提交期间修改失败,重命名仍然会被应用。

更多示例

要查看更多如何使用它的示例,请查看项目SAddr(简单地址簿),这是一个多年前创建并正在使用此辅助程序重做的简单地址簿。它在https://github.com/artnum/saddr上可用,功能根据需要添加。