开发人员:PHP
使用 PHP 创建 LDAP 目录服务
学习如何使用 PHP 在 OID 中创建 LDAP 目录服务
2007 年 12 月发布
Oracle Internet Directory (OID) 是一个利用了 Oracle 数据库的伸缩性、高可用性和安全性特性的符合 LDAP v3 标准的目录,它可以提供目录服务以存储并修改有关网络资源的信息。(例如,OID 充当 Oracle 身份管理的中心用户信息库。)
很多企业应用程序都使用 Java 命名和目录接口 (JNDI) 来访问 OID 中的目录服务。不过,当涉及到基于 PHP 的 Web 应用程序时 — 这样的应用程序数以百万计,同时其中很多都有着不断演变的安全性和认证要求 — 上述方法就显然不是好的选择了。改为使用将 PHP 和 OID 进行集成的方法则可以提供所需的目录服务。
在本文中,您将学习如何使用 PHP LDAP 扩展在 OID 中创建目录服务。您还将使用 LDAP PHP 类库来添加、修改、搜索和删除目录条目。
背景
目录服务是一个应用程序,用于存储、检索和修改有关网络资源(如网络用户)的信息。实际数据存储在数据库中。目录服务是数据库上的一个抽象层。轻型目录访问协议 (LDAP) 是一个用于访问目录服务的轻型协议,它也可定义目录条目的添加、搜索、修改和删除等操作。
一个“条目”是一组属性,由一个全局唯一的识别名称 (DN) 进行识别。每个目录条目的属性都有一个类型和一个或多个值。目录条目的 DN 中的属性按从右到左的层次进行排列,最右侧的属性为顶层条目,而最左侧在该级别上唯一的属性称作相对识别名称 (RDN)。
一个 DN 是一个 RDN 序列。表 1 讨论了属性类型的一些示例。
表 1 属性类型
| 属性类型 |
说明 |
o |
组织 |
dc |
域组件 |
ou |
组织单位 |
cn |
常用名称 |
uid |
用户标识 |
dn |
识别名称 |
mail |
电子邮件地址 |
下面是一个 DN 示例:
cn=dvohra,cn=PUBLIC,dc=example,dc=com
在本例中,基本条目/根是 dc=example,dc=com,而 RDN 是 cn=dvohra。
安装 PHP
下载 Apache HTTP Server 2.0。要安装 Apache HTTP 服务器,双击 Apache Web 服务器应用程序 apache_2.2.3-win32-x86-no_ssl。
下载 PHP 5.2.5。将 PHP zip 文件 php-5.2.5-Win32.zip 解压缩至安装目录,如 C:/PHP。
将 PHP 5 的安装目录 C:/PHP 添加到 PATH 环境系统变量中。将 C:/PHP 目录中推荐的 php.init 文件修改为 php.ini。
在 Apache HTTP 服务器中安装 PHP 5。在 <Apache2>\conf\httpd.conf 文件中添加:
# For PHP 5
LoadModule php5_module "C:/PHP/php5apache2.dll"
AddType application/x-httpd-php .php
# configure the path to php.ini
PHPIniDir "C:/PHP/"
<Apache2> 是 Apache 2 Web 服务器的安装目录,Apache Http Server 2.2.3 的默认安装目录是 C:\Program Files\Apache Software Foundation\Apache2.2。不过,对于本教程,Apache 2 web 服务器安装在 C:/Apache2 目录下。如果 PHP 5 的安装目录不是 C:/PHP,用实际安装目录替换 C:/PHP。
安装 Oracle Internet Directory
- 下载 Oracle 身份管理基础架构的 Disk1 和 Disk2 以及 Oracle Identity Federation 的 zip 文件。
- 将 disk1 解压缩至某目录。将 disk2 zip 文件解压缩至 disk1 所在的目录。
- 要安装 Oracle Internet Directory,单击 \install\setup 应用程序。Oracle Universal Installer 启动。
- 单击 Next。
- 在 Specify File Locations 框中指定安装目录,单击 Next。
 图 1
选择 Oracle Application Server Infrastructure 10g,单击 Next。Oracle 应用服务器基础架构 10g 包含 OID 和 Oracle 数据库。
 图 2
在 Select Installation Type 框中,选择 Identity Management and Metadata Repository,它将安装 Oracle Internet Directory 和 Oracle 数据库 10g。单击 Next。
 图 3
选择需要安装的默认 Oracle 应用服务器基础架构 10g 组件,单击 Next。
 图 4
检查安装前要求,单击 Next。选择默认的配置选项,单击 Next。
 图 5
选择默认的端口配置选项,单击 Next。
 图 6
在 Oracle Internet Directory 中指定命名空间以创建新用户。例如,指定 dc=example,dc=com,单击 Next。
 图 7
指定数据库配置选项或选择默认的数据库配置选项,单击 Next。
 图 8
指定数据库模式口令,单击 Next。
 图 9
指定 Oracle 应用服务器基础架构实例名。指定 ias_admin 管理员用户名的口令,单击 Next。
 图 10
单击 Install 安装 Oracle 应用服务器基础架构。
 图 11
出现一个对话框,要求提供 Oracle 应用服务器 10g 的 disk 2。指定 disk2 的存放目录。
 图 12
接着,配置助手进行安装。
 图 13
单击 Next。
 图 14
单击 Exit 完成安装。
 图 15
接着,启动 Oracle 目录管理器,它用于管理 OID。您需要先启动 OID Monitor 和一个 OID 服务器实例,然后才能使用 OID。使用以下命令启动 OID Monitor。
C:\>oidmon start
使用以下命令启动一个 Oracle 目录服务器实例。
C:\>oidctl server=oidldapd instance=2 start
接着,启动 Oracle 目录管理器。在 Connect 框中,指定用户名为 orcladmin(这是一个超级用户),指定口令为 Oracle 应用服务器基础架构 10g 实例的口令。指定服务器为 localhost,端口为 389(默认端口)。单击 Login。
 图 16
Oracle 目录管理器启动。
 图 17
安装 PHP LDAP 扩展
默认情况下没有启用 PHP LDAP 扩展。要启用 PHP LDAP 扩展,删除 php.ini 配置文件中以下行前面的“;”。
extension=php_ldap.dll
将 C:/PHP 目录中的 libeay32.dll 和 ssleay32.dll 复制到 C:/WINNT/system32 目录。重启 Apache Http 服务器。
PHP LDAP 类库提供各种用于创建 LDAP 目录服务的函数。表 2 讨论了一些常用的 PHP LDAP 函数。
表 2 PHP LDAP 函数
| 方法 |
说明 |
ldap_connect ( [string hostname [, int port]] ) |
连接到 LDAP 服务器。如果未指定主机名,将返回已打开链接的链接标识符。端口默认为 389。出错时返回 LDAP 链接标识符或 FALSE。 |
ldap_add ( resource link_identifier, string dn, array entry ) |
添加一个目录条目。参数 link_identifier 指定 LDAP 连接资源。参数 dn 指定目录条目的 dn。参数 entry 指定目录条目中的一组属性。如果完成添加操作,返回 TRUE;如果发生错误,返回 FALSE。 |
ldap_bind ( resource link_identifier [, string bind_rdn [, string bind_password]] ) |
使用指定的连接资源绑定到 LDAP 目录。如果完成绑定操作,返回 TRUE;如果发生错误,返回 FALSE。 |
ldap_unbind ( resource link_identifier ) |
取消与 LDAP 目录的绑定。如果完成取消绑定操作,返回 TRUE;如果发生错误,返回 FALSE。 |
ldap_close ( resource link_identifier ) |
取消与 LDAP 目录的绑定。 |
ldap_count_entries ( resource link_identifier, resource result_identifier ) |
返回 LDAP 搜索中的条目数。出错时返回 FALSE。 |
ldap_delete ( resource link_identifier, string dn ) |
删除一个目录条目。 |
ldap_error ( resource link_identifier ) |
返回上一 LDAP 命令的出错信息。 |
ldap_get_attributes ( resource link_identifier, resource result_entry_identifier ) |
返回目录条目中的一组属性。 出错时返回 FALSE。 |
ldap_first_entry ( resource link_identifier, resource result_identifier ) |
返回结果资源中的第一个条目。 |
ldap_next_entry ( resource link_identifier, resource result_entry_identifier ) |
返回结果资源中的下一条目。 |
ldap_get_entries ( resource link_identifier, resource result_identifier ) |
返回结果资源中的一组条目。 |
ldap_get_dn ( resource link_identifier, resource result_entry_identifier ) |
返回结果资源的 dn。 |
ldap_get_values ( resource link_identifier, resource result_entry_identifier, string attribute ) |
返回结果条目资源中某属性的全部属性值。 |
ldap_mod_add ( resource link_identifier, string dn, array entry ) |
为目录条目的属性添加属性值。 |
ldap_mod_del ( resource link_identifier, string dn, array entry ) |
删除 dn 属性的属性值。 |
ldap_mod_replace ( resource link_identifier, string dn, array entry ) |
替换 dn 的属性值。 |
ldap_modify ( resource link_identifier, string dn, array entry ) |
修改一个目录条目。 |
ldap_search ( resource link_identifier, string base_dn, string filter [, array attributes [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]] ) |
使用基础 dn、指定的筛选器和一组属性(可选)来搜索目录。筛选器指定搜索的筛选方式,例如,仅搜索特定 objectclass 的属性。只有在要求属性类型时,才将 attrsonly 参数设置为 1。attrsonly 的默认值是 0,它用于获取属性类型和属性值。sizelimit 参数可用于限制返回条目的数量。Sizelimit 值为 0 等同于未设置 sizelimit。参数 timelimit 指定搜索操作的时间限制,单位为秒。 |
创建目录条目
接下来,在 OID LDAP 服务器中创建一个目录条目。例如,创建一个 JDeveloper 开发人员目录。LDAP 条目以 LDAP 数据交换格式 (LDIF) 表示,格式为 .ldif。条目格式如下所示。
dn: <distinguished name>
<attrdesc>: <attrvalue>
<attrdesc>: <attrvalue>
dn 表示目录条目的识别名称,attrdesc/attrvalue 表示目录条目的属性。我们将使用以下 dn 作为根/基础 DN。
cn=PUBLIC,cn=Users,dc=example,dc=com
基础 dn 的目录节点如下所示。所选的 dn 支持 top、person、organizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类。
 图 18
每个目录条目用 dn 属性识别。objectclass 属性指定数据类型以及条目中必需的和可选的属性。针对目录条目所实施的不同的对象类,objectclass 属性可以有多个值。对象类形成一个类层次,一些常用的对象类包括 top、organization 和 organizationalPerson。所有的对象类都是对象类“top”的子类。每个 objectclass 都有必需的和可选的属性。
现在创建一个包含 top、person、organizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类的目录服务。“top”对象类没有任何必需的属性。Person 对象类的必需属性是“cn”和“sn”。OrganizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类没有任何必需的属性。在对象类 organizationalPerson 的目录条目中,可以指定的一些属性包括 title 和 telephoneNumber。
在 C:\Apache2\htdocs 目录中创建一个 PHP 脚本 add_entry.php。启动 OID LDAP 服务器(若还未启动)。首先,使用 ldap_connect() 函数创建一个与 OID 服务器的连接。
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
ldap_connect() 仅初始化连接参数并返回一个连接资源,但并不真正与 LDAP 服务器相连接。如果 ldap_connect() 方法没有返回错误,使用 LDAP_OPT_PROTOCOL_VERSION 将 LDAP 协议版本设置为 3。
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
接着,通过 ldap_bind() 函数使用连接资源、用户名和口令绑定到 LDAP 服务器。
$r=ldap_bind($ldapconn," cn=orcladmin, "cn=PUBLIC,cn=Users,dc=example,dc=com","oid10admin");
要添加一个目录条目,创建一个包含一组属性的条目。例如,对“cn”属性作如下指定。
$directory_entry["cn"]="DeepakVohra";
在此示例目录条目中,您应当设置属性 cn、sn、title、telephoneNumber、physicalDeliveryOfficeName 和 facsimileTelephoneNumber。如果某属性具有多个值,属性值用二维数组进行指定。例如,objectclass 值按以下清单所示进行设置。
$directory_entry["objectclass"][0]="top";
$directory_entry["objectclass"][1]="person";
$directory_entry["objectclass"][2]="inetOrgPerson";
$directory_entry["objectclass"][3]="organizationalPerson";
$directory_entry["objectclass"][4]="orclUser";
$directory_entry["objectclass"][5]="orclUserV2";
指定待添加目录条目的 dn。
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
使用 ldap_add() 方法将目录条目添加到 LDAP 目录中。
$r=ldap_add($ldapconn, $dn, $directory_entry);
用于添加目录条目的 PHP 脚本 add_entry.php 如下所示。
<?php
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
if ($ldapconn) {
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
if(!$r){echo "User did not bind to LDAP Server";}
else echo "User was bound to LDAP Server";
$directory_entry["cn"]="DeepakVohra";
$directory_entry["sn"]="Vohra";
$directory_entry["objectclass"][0]="top";
$directory_entry["objectclass"][1]="person";
$directory_entry["objectclass"][2]="inetOrgPerson";
$directory_entry["objectclass"][3]="organizationalPerson";
$directory_entry["objectclass"][4]="orclUser";
$directory_entry["objectclass"][5]="orclUserV2";
$directory_entry["title"]="PHP Developer";
$directory_entry["telephoneNumber"]="555 1234";
$directory_entry["physicalDeliveryOfficeName"]="JDeveloper";
$directory_entry["facsimileTelephoneNumber"]="555 5678";
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
$r=ldap_add($ldapconn, $dn, $directory_entry);
if(!$r) echo "Directory Entry not Added.";
else echo "Directory Entry Added";
ldap_close($ldapconn);
} else {
echo ldap_error($ldapconn);}
?>
将 PHP 脚本 add_entry.php 复制到 C:\Apache2\htdocs 目录。使用 URL http://localhost/add_entry.php 运行 PHP 脚本。在 Oracle 目录管理器中,使用 View > Refresh 刷新目录条目。
 图 19
添加了一个目录条目,如 Oracle 目录管理器中所示。
 图 20
修改目录
在本节中,您将修改前面添加的目录条目。创建 PHP 脚本 modify_entry.php 以修改目录条目。
首先,使用 ldap_connect() 方法创建连接资源。
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
如果已创建连接资源,则将 LDAP 协议版本设置为 3,并使用 ldap_bind() 函数与 LDAP 目录进行绑定。
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
使用修改后的值创建一组目录条目属性。例如,修改“title”属性值和 physicalDeliveryOfficeName 属性值。
$directory_entry["title"]="Web Developer";
$directory_entry["physicalDeliveryOfficeName"]="Oracle JDeveloper";
只有要修改的属性才需要在属性数组中进行指定。
每个目录条目用识别名称进行识别。指定待修改目录条目的 dn。
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
使用 ldap_modify() 函数修改目录条目。
$r=ldap_modify($ldapconn,$dn, $directory_entry);
用于修改目录条目的 PHP 脚本 ldap_modify.php 见清单 2。
清单 2 modify_entry.php
<?php
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
if ($ldapconn) {
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
$directory_entry["title"]="Web Developer";
$directory_entry["physicalDeliveryOfficeName"]="Oracle JDeveloper";
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
$r=ldap_modify($ldapconn,$dn, $directory_entry);
if(!$r) echo "Directory Entry Not Modified";
else echo "Directory Entry Modified";
ldap_close($ldapconn);
} else {
echo ldap_error($ldapconn);
}
?>
复制 modify_entry.php 到 C:\Apache2\htdocs 目录。 使用 URL http://localhost/modify_entry.php 运行该脚本。目录条目已修改,如 Oracle 目录管理器中所示。
 图 21
搜索目录
在本节中,您将使用 PHTML(嵌入在 HTML 中的 PHP)脚本搜索目录条目并在 HTML 中显示结果。将 .phtml 扩展添加到 C:/Apache2/conf/httpd.conf 文件的以下 Apache 2 配置指令中。
AddType application/x-httpd-php .php .phtml
重启 Apache 2 服务器。在 C:/Apache2/htdocs 目录中创建一个 PHTML 脚本 search_entry.phtml。首先,使用 ldap_connect() 方法为 LDAP 服务器连接创建一个连接资源。
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
如果已创建连接资源,则将 LDAP 协议版本设置为 3,同时目录服务器要使用 ldap_bind() 方法。
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
接着,指定要为其检索属性值的属性数组。默认情况下,检索所有的属性。
$attribute_array=array("cn", "sn", "title", "telephoneNumber","physicalDeliveryOfficeName",
"facsimileTelephoneNumber", "objectclass");
指定待搜索目录条目的 dn。
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
指定搜索的筛选器。例如,指定搜索所有 objectclass 的筛选器。
$filter = "(objectclass=*)";
使用 ldap_search() 方法搜索目录。
$sr=ldap_search($ldapconn,$dn, $filter, $attribute_array);
使用 ldap_get_entries() 方法检索搜索结果中的目录条目。
$directory_entries= ldap_get_entries($ldapconn, $sr);
创建 HTML 表以显示搜索结果。为表添加标题行。检索每个属性的值并将其添加到表中。目录条目搜索结果是一组条目。第一个目录条目通过表达式 $directory_entries[0] 进行访问。
一个目录条目包含一组属性。目录条目中的属性通过在属性数组中指定属性名进行访问。(例如,“cn”属性通过表达式 $directory_entries[0]['cn'] 进行访问。)
一个属性由一组值构成,数组值通过指定属性值数组索引进行访问。objectclass 属性有多个值。例如,objectclass 属性值数组中的第一个值通过表达式 $directory_entries[0]['objectclass'][0] 进行访问。数组中属性值的数目可通过“count”属性获得。例如,objectclass 属性的值的数目获取方式如下。
$count=$directory_entries[0]['objectclass']["count"];
从搜索结果中检索属性值并添加到表中。例如,“cn”属性行的添加如下所示。
<tr><td>cn</td><td><?php echo $directory_entries[0]['cn'][0]; ?></td></tr>
如果一个属性有多个值(如 objectclass 属性),使用 () 循环来遍历属性值并进行输出。
for ($i=0; $i<$count; $i++){
print $directory_entries[0]['objectclass'][$i]."<br>";
}
search_entry.phtml 脚本见清单 3。
清单 3 search_entry.phtml
<?php
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
if ($ldapconn) {
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","phpldap");
$attribute_array=array("cn", "sn", "title", "telephoneNumber",
"physicalDeliveryOfficeName","facsimileTelephoneNumber",
"objectclass");
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com"; $filter = "(objectclass=*)";
$sr=ldap_search($ldapconn,$dn, $filter, $attribute_array);
$directory_entries= ldap_get_entries($ldapconn, $sr);
ldap_close($ldapconn);
} else {
echo ldap_error($ldapconn);}
?>
<HTML>
<HEAD>
<TITLE> Directory Entry</TITLE>
</HEAD
<BODY>
<p> </p>
<table border>
<tr><th>Attribute</th><th>Value</th></tr>
<tr><td>cn</td><td><?php echo $directory_entries[0]['cn'][0]; ?></td></tr>
<tr><td>sn</td><td><?php print $directory_entries[0]['sn'][0]; ?></td></tr>
<tr><td>title</td><td><?php print $directory_entries[0]['title'][0]; ?></td></tr>
<tr><td>telephoneNumber</td><td>
<?php print $directory_entries[0]['telephonenumber'][0]; ?></td></tr>
<tr><td>physicalDeliveryOfficeName</td><td>
<?php print $directory_entries[0]['physicaldeliveryofficename'][0]; ?></td></tr>
<tr><td>facsimileTelephoneNumber</td><td>
<?php print $directory_entries[0]['facsimiletelephonenumber'][0]; ?></td></tr>
<tr><td>objectclass</td><td>
<?php
$count=$directory_entries[0]['objectclass']["count"];
for ($i=0; $i<$count; $i++){
print $directory_entries[0]['objectclass'][$i]."<br>";
}
?></td></tr>
</table>
</BODY>
</HTML>
要搜索某一目录条目,使用 URL http://localhost/search_entry.phtml 运行 search_entry.phtml 脚本。显示目录条目属性。
 图 22
删除目录
在本节中,您将删除一个目录条目。?在 C:/Apache2/htdocs 目录中创建一个 PHP 脚本 delete_entry.php。首先,使用 ldap_connect() 方法获得一个用于 LDAP 服务器的连接资源。
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
如果已创建连接资源,则将 LDAP 协议版本设置为 3,并使用 ldap_bind() 函数进行绑定。
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
指定待删除目录条目的 dn。
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
使用 ldap_delete() 方法删除目录条目。
$r=ldap_delete($ldapconn, $dn);
PHP 脚本 delete_entry.php 见清单 4。
清单 4 delete_entry.php
<?php
$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);
if ($ldapconn) {
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
$r=ldap_delete($ldapconn, $dn);
if(!$r) echo "Directory Entry Not Deleted";
else echo "Directory Entry Deleted";
ldap_close($ldapconn);
} else {
echo ldap_error($ldapconn);
}
?>
要删除一个目录条目,使用 URL http://localhost/delete_entry.php 调用 delete_entry.php 脚本。目录条目已删除,如 Oracle 目录管理器中所示。
 图 23
恭喜!您已经学会了如何使用 PHP 在 OID 中创建和删除 LDAP 目录服务。
Deepak Vohra (dvohra09@yahoo.com) 是一位 Sun 认证的 Java 程序员和 NuBean 顾问,经常在 onjava.com、XML Journal、WebLogic Developer's Journal 和 OTN 上发表文章。
|