本文将演示如何使用php连接一个ldap服务器。具体的例子是连接到一个公共的ldap服务器并且进行搜索。这个例子模拟的是netscape communicator 4.*,通过自己的地址本连接到ldap资源。
ldap介绍
可能不少人已经听说过ldap,但是却不了解它具体是什么东东和如何工作。在这里我将不会很详细地介绍ldap,只是对该协议做一个简介。
ldap是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。
ldap最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果,不过在其它方面,例如更新,就慢得多。要特别注意的是,ldap通常作为一个hierarchal数据库使用,而不是一个关系数据库。因此,它的结构用树来表示比用表格好。正因为这样,就不能用 sql语句了。
简单说来,ldap是一个得到关于人或者资源的集中、静态数据的快速方式。
要求
phpv.4(以前的版本也可以,不过没有经过测试),编译支持ladp,即使用编译时带--with-ldap公共的ldap目录。在例子中提供了两个。
例子概览
1.设置公共ldap服务器的信息
2.创建一个ldap查询
3.连接到ldap服务器
4.如果连接成功,处理查询
5.格式化输出
6.关闭连接
7.设计搜索界面的html表格
8.显示结果
设置公共ldap服务器的信息
我们要做的第一件事情是定义所有欲搜索的ldap服务器的信息
"ldap_name" = 新的ldap项目的名字
"ldap_server" = 新的ldap项目的ip地址或者主机名
"ldap_root_dn" = 新的ldap项目的根的辨识名
<?php
$ldap_name[0] = "netscape net center";
$ldap_server[0] = "memberdir.netscape.com";
$ldap_root_dn[0] = "ou=member_directory,o=netcenter.com";
$ldap_name[1] = "bigfoot";
$ldap_server[1] = "ldap.bigfoot.com";
$ldap_root_dn[1] = "";
//如果没有选择服务器的话将它设置为0
if(!$server_id)
$server_id=0;
?>
建立ldap查询
前面已经提到,ldap查询与sql查询是不一样的。因此,语句要受到一定的限制,以下是一个基本的例子。
//create query $ldap_query = "cn=$common";
在我们的例子中,“cn”是我们要进行搜索的属性,而$common是由搜索的form中得到的字符串变量。ldap的查询语句语句可使用通配符‘*’。例如‘$stanley’将可以找出‘dan stanley’。
连接到ldap服务器
以下的函数连接到一个ldap资源,并且将连接的识别号赋给一个变量,就好象连接到一个通常的数据库一样,例如mysql。
<?php
//连接到ldap
$connect_id = ldap_connect($ldap_server[$server_id]);
?>
在我们的例子中,“$connect_id”是连接的识别号,$ldap_server是可能的ldap服务器数组,而$server_id是由搜索表格得到的ldap服务器变量。
如果连接成功,处理查询
如果连接成功的话,我们将得到一个有效的ldap连接识别号,这样我们就可以处理查询。
<?php
if($connect_id)
{
//认证
$bind_id = ldap_bind($connect_id);
//执行搜索
$search_id = ldap_search($connect_id, $ldap_root_dn[$server_id], $ldap_query);
//将结果集合分配给一个数组
$result_array = ldap_get_entries($connect_id, $search_id);
}
else
{
//显示连接错误
echo "could not connect to ldap server: $ldap_server[$server_id]";
}
?>
一旦我们与ldap服务器建立好连接,我们就必须进行认证。php在连接大多数的数据库时,都是通过发送用户名和密码来进行的。不过,在ldap中,认证是未知的,直到进行一个bind操作。在我们的例子中,“$bind_id”是绑定连接的标识符。我们是通过匿名绑定到公共的ldap服务器的。因此,在执行ldap_bind()时,只使用连接识别号就可以了,无需其它的参数。
在经过认证后(这里是匿名的),我们就可以使用ldap_search()函数来执行查询,产生的$search_id是我们搜索的连接识别符。
然后,我们使用ldap_get_entries()函数将结果集赋给$result_array变量。这样我们能够以逻辑的方式排列信息,以便显示。
格式化输出
在执行完ldap搜索后,返回的数据是以查找的顺序排列的。不过我们在排序时没有sql这样方便,使用order by语句就可以了。通常多数公共的ldap目录都没有标准的大小规范。排序是基于字符的ascii值,我们必须将字符全部格式化为小写,以便按字母的顺序输出。
要特别注意的是,返回的ldap结果集是一个多维的数组。因此,我们脚本中的$result_array的结构如下:
$result_array[0]["cn"] [0] = "dannie stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "dannie"
["sn"] [0] = "stanley"
["mail"] [0] = "danspam@spinweb.net"
$result_array[1]["cn"] [0] = "michael reynolds"
["dn"] [0] = "uid=michael,dc=spinweb.net"
["givenname"][0] = "michael"
["sn"] [0] = "reynolds"
["mail"] [0] = "michaelspam@spinweb.net"
数据以这种格式存放的原因是每个属性都可能有超过一个值(象树的结构)。例如,如果我的名字是‘dannie’,我还可以在ldap中增加一些属性,例如:
$result_array[0]["cn"] [0] = "dannie stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "dannie"
["givenname"][0] = "dan"
["sn"] [0] = "stanley"
["mail"] [0] = "danspam@spinweb.net"
在我们的搜索中,我们只关心每个属性的首个值,因此除了dn只有一个值外,其它我们只使用每个属性中序号为0的值。以下就是属性和它们含义的简单列表:
"cn" = common name
"dn" = distinguished name
"givenname" = first name
"sn" = last name
"mail" = email地址
<?php
//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}
//排序数组
sort($format_array, "sort_string");
for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];
if($dn && $fname && $lname && $email)
{
$result_list .= "$fname $lname";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$cn</a>";
$result_list .= " <a href='/"mailto:$email/"'>$email</a>
";
}
}
}
else
{
echo "result set empty for query: $ldap_query";
}
?>
在我们的例子中,$format_array是我们建立的新数组,里面包括有查询的结果,并且被格式化用作输出。首先循环$result_array中的每个元素,并且将它分配给一个两维的数组用作排序。同时我们使用strtolower()函数将所有的值变为小写。
接着,我们使用php自带的一个称为sort()的函数进行排序。首个参数是要排序的数组,另一个是要执行的排序类型,该类型是由php的文档定义的。由于我们根据字符串排序,我们使用“sort_string”。
第三,我们循环已经格式化好的数组,并且将它分配给一个名字为$result_list的输出字符,该字符包含了html描述。要特别注意的是,在超链接中,我使用的是ldap的url格式。这个格式的例子类似:href="ldap://ldap.domain.net/uid=dannie,dc= domain.net"。
关闭连接
现在我们所有的数据已经包含在$result_list中了,我们可以安全地关闭ldap的连接。
<?php
//关闭连接
ldap_close($connect_id);
定制搜索界面的html表格
最后,我们要定制搜索用的html表格,它是用来给用户执行搜索的。
//定制表格
echo " <center><form action='"$php_self"' method='"get"'>";
echo "search in:<select name='"server_id"'>"; //循环以建立select选项 for($i=0; $i<count($ldap_name); <br $i++)> echo "<option selected value='"$i"'>".$ldap_name[$i]."</option>"; echo "</select>
";
echo "search for:<input name='"common"' type='"text"'>";
echo "<input name='"lookup"' type='"submit"' value='"go"'>
";
echo "(you can use * for wildcard searches, ex. * stanley will find all stanleys)
";
echo "</form></center>";
?>
代码中的$php_self是一个全局的常量,代表的是脚本页面自身,其中的循环是用来通过我们的$ldap_name变量创建select选项。
显示结果
现在所有的工作已经完成了,我们将打印出结果集。如果没有符合的结果,将会显示"no results"的信息。
<<?>php
//显示结果
if($result_list)
{
echo " <center><table border='"1"' cellpadding='"10"' cellspacing='"0"'
bgcolor="#ffffea" width="450"> <tbody><tr><td>$result_list</td></tr>
</tbody></table></center>";
}
else
echo "no results";
?>
源代码
以下是完整的源代码,只要将它剪切并粘贴到一个html文档,就可以尝试一下了。
<?php
$ldap_name[0] = "netscape net center";
$ldap_server[0] = "memberdir.netscape.com";
$ldap_root_dn[0] = "ou=member_directory,o=netcenter.com";
$ldap_name[1] = "bigfoot";
$ldap_server[1] = "ldap.bigfoot.com";
$ldap_root_dn[1] = "";
//如果没有选择服务器的话将它设置为0
if(!$server_id)
$server_id=0;
//建立查询
$ldap_query = "cn=$common";
//连接到ldap
$connect_id = ldap_connect($ldap_server[$server_id]);
if($connect_id)
{
//认证
$bind_id = ldap_bind($connect_id);
//执行搜索
$search_id = ldap_search($connect_id, $ldap_root_dn[$server_id], $ldap_query);
//将结果集合分配给一个数组
$result_array = ldap_get_entries($connect_id, $search_id);
}
else
{
//显示连接错误
echo "could not connect to ldap server: $ldap_server[$server_id]";
}
//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}
//排序数组
sort($format_array, "sort_string");
for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];
if($dn && $fname && $lname && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$fname $lname</a>";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$cn</a>";
$result_list .= " <<a href='/"mailto:$email/"'>$email</a>
";
}
}
}
else
{
echo "result set empty for query: $ldap_query";
}
//关闭连接
ldap_close($connect_id);
//定制表格
echo " <center><form action='"$php_self"' method='"get"'>";
echo "search in:<select name='"server_id"'>"; //循环以建立select选项 for($i=0; $i echo "<option selected value='"$i"'>".$ldap_name[$i]."</option>"; echo "</select>
";
echo "search for:<input name='"common"' type='"text"'>";
echo "<input name='"lookup"' type='"submit"' value='"go"'>
";
echo "(you can use * for wildcard searches, ex. * stanley will find all stanleys)
";
echo "</form></center>";
//显示结果
if($result_list)
{
echo " <center><table border='"1"' cellpadding='"10"' cellspacing='"0"'
bgcolor="#ffffea" width="450"> <tbody><tr><td>$result_list</td></tr>
</tbody></table></center>";
}
else
echo "no results";
}
?>
ldap介绍
可能不少人已经听说过ldap,但是却不了解它具体是什么东东和如何工作。在这里我将不会很详细地介绍ldap,只是对该协议做一个简介。
ldap是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。
ldap最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果,不过在其它方面,例如更新,就慢得多。要特别注意的是,ldap通常作为一个hierarchal数据库使用,而不是一个关系数据库。因此,它的结构用树来表示比用表格好。正因为这样,就不能用 sql语句了。
简单说来,ldap是一个得到关于人或者资源的集中、静态数据的快速方式。
要求
phpv.4(以前的版本也可以,不过没有经过测试),编译支持ladp,即使用编译时带--with-ldap公共的ldap目录。在例子中提供了两个。
例子概览
1.设置公共ldap服务器的信息
2.创建一个ldap查询
3.连接到ldap服务器
4.如果连接成功,处理查询
5.格式化输出
6.关闭连接
7.设计搜索界面的html表格
8.显示结果
设置公共ldap服务器的信息
我们要做的第一件事情是定义所有欲搜索的ldap服务器的信息
"ldap_name" = 新的ldap项目的名字
"ldap_server" = 新的ldap项目的ip地址或者主机名
"ldap_root_dn" = 新的ldap项目的根的辨识名
<?php
$ldap_name[0] = "netscape net center";
$ldap_server[0] = "memberdir.netscape.com";
$ldap_root_dn[0] = "ou=member_directory,o=netcenter.com";
$ldap_name[1] = "bigfoot";
$ldap_server[1] = "ldap.bigfoot.com";
$ldap_root_dn[1] = "";
//如果没有选择服务器的话将它设置为0
if(!$server_id)
$server_id=0;
?>
建立ldap查询
前面已经提到,ldap查询与sql查询是不一样的。因此,语句要受到一定的限制,以下是一个基本的例子。
//create query $ldap_query = "cn=$common";
在我们的例子中,“cn”是我们要进行搜索的属性,而$common是由搜索的form中得到的字符串变量。ldap的查询语句语句可使用通配符‘*’。例如‘$stanley’将可以找出‘dan stanley’。
连接到ldap服务器
以下的函数连接到一个ldap资源,并且将连接的识别号赋给一个变量,就好象连接到一个通常的数据库一样,例如mysql。
<?php
//连接到ldap
$connect_id = ldap_connect($ldap_server[$server_id]);
?>
在我们的例子中,“$connect_id”是连接的识别号,$ldap_server是可能的ldap服务器数组,而$server_id是由搜索表格得到的ldap服务器变量。
如果连接成功,处理查询
如果连接成功的话,我们将得到一个有效的ldap连接识别号,这样我们就可以处理查询。
<?php
if($connect_id)
{
//认证
$bind_id = ldap_bind($connect_id);
//执行搜索
$search_id = ldap_search($connect_id, $ldap_root_dn[$server_id], $ldap_query);
//将结果集合分配给一个数组
$result_array = ldap_get_entries($connect_id, $search_id);
}
else
{
//显示连接错误
echo "could not connect to ldap server: $ldap_server[$server_id]";
}
?>
一旦我们与ldap服务器建立好连接,我们就必须进行认证。php在连接大多数的数据库时,都是通过发送用户名和密码来进行的。不过,在ldap中,认证是未知的,直到进行一个bind操作。在我们的例子中,“$bind_id”是绑定连接的标识符。我们是通过匿名绑定到公共的ldap服务器的。因此,在执行ldap_bind()时,只使用连接识别号就可以了,无需其它的参数。
在经过认证后(这里是匿名的),我们就可以使用ldap_search()函数来执行查询,产生的$search_id是我们搜索的连接识别符。
然后,我们使用ldap_get_entries()函数将结果集赋给$result_array变量。这样我们能够以逻辑的方式排列信息,以便显示。
格式化输出
在执行完ldap搜索后,返回的数据是以查找的顺序排列的。不过我们在排序时没有sql这样方便,使用order by语句就可以了。通常多数公共的ldap目录都没有标准的大小规范。排序是基于字符的ascii值,我们必须将字符全部格式化为小写,以便按字母的顺序输出。
要特别注意的是,返回的ldap结果集是一个多维的数组。因此,我们脚本中的$result_array的结构如下:
$result_array[0]["cn"] [0] = "dannie stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "dannie"
["sn"] [0] = "stanley"
["mail"] [0] = "danspam@spinweb.net"
$result_array[1]["cn"] [0] = "michael reynolds"
["dn"] [0] = "uid=michael,dc=spinweb.net"
["givenname"][0] = "michael"
["sn"] [0] = "reynolds"
["mail"] [0] = "michaelspam@spinweb.net"
数据以这种格式存放的原因是每个属性都可能有超过一个值(象树的结构)。例如,如果我的名字是‘dannie’,我还可以在ldap中增加一些属性,例如:
$result_array[0]["cn"] [0] = "dannie stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "dannie"
["givenname"][0] = "dan"
["sn"] [0] = "stanley"
["mail"] [0] = "danspam@spinweb.net"
在我们的搜索中,我们只关心每个属性的首个值,因此除了dn只有一个值外,其它我们只使用每个属性中序号为0的值。以下就是属性和它们含义的简单列表:
"cn" = common name
"dn" = distinguished name
"givenname" = first name
"sn" = last name
"mail" = email地址
<?php
//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}
//排序数组
sort($format_array, "sort_string");
for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];
if($dn && $fname && $lname && $email)
{
$result_list .= "$fname $lname";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$cn</a>";
$result_list .= " <a href='/"mailto:$email/"'>$email</a>
";
}
}
}
else
{
echo "result set empty for query: $ldap_query";
}
?>
在我们的例子中,$format_array是我们建立的新数组,里面包括有查询的结果,并且被格式化用作输出。首先循环$result_array中的每个元素,并且将它分配给一个两维的数组用作排序。同时我们使用strtolower()函数将所有的值变为小写。
接着,我们使用php自带的一个称为sort()的函数进行排序。首个参数是要排序的数组,另一个是要执行的排序类型,该类型是由php的文档定义的。由于我们根据字符串排序,我们使用“sort_string”。
第三,我们循环已经格式化好的数组,并且将它分配给一个名字为$result_list的输出字符,该字符包含了html描述。要特别注意的是,在超链接中,我使用的是ldap的url格式。这个格式的例子类似:href="ldap://ldap.domain.net/uid=dannie,dc= domain.net"。
关闭连接
现在我们所有的数据已经包含在$result_list中了,我们可以安全地关闭ldap的连接。
<?php
//关闭连接
ldap_close($connect_id);
定制搜索界面的html表格
最后,我们要定制搜索用的html表格,它是用来给用户执行搜索的。
//定制表格
echo " <center><form action='"$php_self"' method='"get"'>";
echo "search in:<select name='"server_id"'>"; //循环以建立select选项 for($i=0; $i<count($ldap_name); <br $i++)> echo "<option selected value='"$i"'>".$ldap_name[$i]."</option>"; echo "</select>
";
echo "search for:<input name='"common"' type='"text"'>";
echo "<input name='"lookup"' type='"submit"' value='"go"'>
";
echo "(you can use * for wildcard searches, ex. * stanley will find all stanleys)
";
echo "</form></center>";
?>
代码中的$php_self是一个全局的常量,代表的是脚本页面自身,其中的循环是用来通过我们的$ldap_name变量创建select选项。
显示结果
现在所有的工作已经完成了,我们将打印出结果集。如果没有符合的结果,将会显示"no results"的信息。
<<?>php
//显示结果
if($result_list)
{
echo " <center><table border='"1"' cellpadding='"10"' cellspacing='"0"'
bgcolor="#ffffea" width="450"> <tbody><tr><td>$result_list</td></tr>
</tbody></table></center>";
}
else
echo "no results";
?>
源代码
以下是完整的源代码,只要将它剪切并粘贴到一个html文档,就可以尝试一下了。
<?php
$ldap_name[0] = "netscape net center";
$ldap_server[0] = "memberdir.netscape.com";
$ldap_root_dn[0] = "ou=member_directory,o=netcenter.com";
$ldap_name[1] = "bigfoot";
$ldap_server[1] = "ldap.bigfoot.com";
$ldap_root_dn[1] = "";
//如果没有选择服务器的话将它设置为0
if(!$server_id)
$server_id=0;
//建立查询
$ldap_query = "cn=$common";
//连接到ldap
$connect_id = ldap_connect($ldap_server[$server_id]);
if($connect_id)
{
//认证
$bind_id = ldap_bind($connect_id);
//执行搜索
$search_id = ldap_search($connect_id, $ldap_root_dn[$server_id], $ldap_query);
//将结果集合分配给一个数组
$result_array = ldap_get_entries($connect_id, $search_id);
}
else
{
//显示连接错误
echo "could not connect to ldap server: $ldap_server[$server_id]";
}
//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}
//排序数组
sort($format_array, "sort_string");
for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];
if($dn && $fname && $lname && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$fname $lname</a>";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "<a href='/"ldap://$ldap_server[$server_id]/$dn/"'>$cn</a>";
$result_list .= " <<a href='/"mailto:$email/"'>$email</a>
";
}
}
}
else
{
echo "result set empty for query: $ldap_query";
}
//关闭连接
ldap_close($connect_id);
//定制表格
echo " <center><form action='"$php_self"' method='"get"'>";
echo "search in:<select name='"server_id"'>"; //循环以建立select选项 for($i=0; $i echo "<option selected value='"$i"'>".$ldap_name[$i]."</option>"; echo "</select>
";
echo "search for:<input name='"common"' type='"text"'>";
echo "<input name='"lookup"' type='"submit"' value='"go"'>
";
echo "(you can use * for wildcard searches, ex. * stanley will find all stanleys)
";
echo "</form></center>";
//显示结果
if($result_list)
{
echo " <center><table border='"1"' cellpadding='"10"' cellspacing='"0"'
bgcolor="#ffffea" width="450"> <tbody><tr><td>$result_list</td></tr>
</tbody></table></center>";
}
else
echo "no results";
}
?>
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http://jackxiang.com/post/591/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!
评论列表