forked from p-moon/develop-reference-data
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphp-ldap.html
More file actions
288 lines (266 loc) · 15 KB
/
php-ldap.html
File metadata and controls
288 lines (266 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-CN" />
<!--[if lt IE 9]><style type="text/css">@font-face { font-family: "JinBuGuoWebMono"; src: url("/d/mono.eot"); }</style><![endif]-->
<style media="all" type="text/css">
@font-face { font-family: "JinBuGuoWebMono"; src: url("/d/mono.ttf") format("truetype"); }
* { font-family: "JinBuGuoWebMono", "Ubuntu Mono", "Consolas", "Menlo", monospace; }
body { margin:10px; }
h1,h2 { text-align:center; background:#ddd; }
h2 { margin: 10px 5%; }
h2#auth_name { background:#fff; }
dt { margin-top: 0.5em; color:#600; }
pre { background: #edc; }
table { vertical-align:middle; border:solid 1px #111; border-collapse:collapse; margin:4px; background:#fff; }
caption, th { font-weight:bold; }
th, td { border:solid 1px #999; padding:4px; }
</style>
<title>PHP-LDAP 学习笔记 [金步国]</title>
<script>var _hmt=_hmt||[]; (function(){ var hm=document.createElement("script"); hm.src="//hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s=document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm,s); })();</script>
</head>
<body>
<h1>PHP-LDAP 学习笔记</h1><h2 id="auth_name">作者:<strong><a href="http://www.jinbuguo.com/">金步国</a></strong></h2>
<hr />
<h3>版权声明</h3>
<p>本文作者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布。</p>
<ul>
<li>无担保:本文作者不保证作品内容准确无误,亦不承担任何由于使用此文档所导致的损失。</li>
<li>自由使用:任何人都可以自由的<u>阅读/链接/打印</u>此文档,无需任何附加条件。</li>
<li>名誉权:任何人都可以自由的<u>转载/引用/再创作</u>此文档,但必须保留作者署名并注明出处。</li>
</ul>
<h3>其他作品</h3>
<p>本文作者十分愿意与他人分享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有的作品集:</p>
<ul>
<li><a href="http://www.jinbuguo.com/">金步国作品集</a> [ <a href="http://www.jinbuguo.com/">http://www.jinbuguo.com/</a> ]</li>
</ul>
<h3>联系方式</h3>
<p>由于作者水平有限,因此不能保证作品内容准确无误。如果你发现了作品中的错误(哪怕是错别字也好),请来信指出,任何提高作品质量的建议我都将虚心接纳。</p>
<ul>
<li>Email(QQ):70171448在QQ邮箱</li>
</ul>
<hr />
<h2>LDAP简介</h2>
<p><a href="http://zh.wikipedia.org/wiki/%E8%BD%BB%E5%9E%8B%E7%9B%AE%E5%BD%95%E8%AE%BF%E9%97%AE%E5%8D%8F%E8%AE%AE">LDAP</a>(Lightweight Directory Access Protocol)的意思是"轻量级目录访问协议",是一个用于访问"目录服务器"(Directory Servers)的协议。这里所谓的"目录"是指一种按照树状结构存储信息的数据库。这个概念和硬盘上的目录结构类似,不过LDAP的"根目录"必须是"The world",并且其一级子目录必须是"countries"。二级目录通常包含有公司(companies)、组织(organisations)、地点(places)等等……相应的三级子目录通常会包含人员(people)、设备(equipment)、文档(documents)等等……</p>
<p>
当你引用硬盘上的文件时,通常是这样的:
<pre>/usr/local/myapp/docs</pre>
正斜杠(/)在这里表示级别分界线,并且从左向右阅读。
</p>
<p>
而在LDAP中则通过"distinguished name"(简称"dn")来表示文件,通常像下面这样:
<pre>cn=John Smith,ou=Accounts,o=My Company,c=US</pre>
逗号(,)在这里表示级别分界线,并且从右向左阅读。上述dn可以理解为:
<pre>
country = US
organization = My Company
organizationalUnit = Accounts
commonName = John Smith
</pre>
术语对比:
<pre>
dn,entry 目录/文件
attribute 属性
value 值
</pre>
与硬盘目录一样,目录服务器上的目录结构也没有任何限制,这就意味着你必须了解一些服务器的结构信息才能写程序。
</p>
<p>
更多关于LDAP的信息可以在下面两个URL找到:<br>
<a href="https://wiki.mozilla.org/Directory">Mozilla</a><br>
<a href="http://www.openldap.org/">OpenLDAP Project</a>
</p>
<h2>安装与配置</h2>
<p>PHP默认并不启用LDAP支持,PHP的LDAP模块依赖于<a href="ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/">OpenLDAP</a>或<a href="http://www.bind9.net/download-openldap/">bind9.net</a>提供的客户端LDAP库,你必须在编译的时候使用 --with-ldap[=DIR] 才行,如果你想要SASL支持,那还必须使用 --with-ldap-sasl[=DIR] 选项,而且你的系统中必须有 sasl.h 头文件才行。</p>
<p>LDAP模块的行为受下面的配置指令的影响</p>
<table>
<tr><th>指令</th><th>数据类型</th><th>作用域</th><th>默认值</th><th>解释</th></tr>
<tr><td>ldap.max_links</td><td>整数</td><td>PHP_INI_SYSTEM</td><td>-1</td><td>每进程允许的最大LDAP连接数。"-1"表示无限制。</td></tr>
</table>
<h2>编程步骤</h2>
<p>在进行LDAP编程之前,你必须知道目录服务器的下列信息:</p>
<ul>
<li>服务器的IP地址(主机名)以及端口号</li>
<li>服务器的"base dn"(也就是"the world"目录下的子目录,比如:"o=My Company,c=US")</li>
<li>访问服务器的用户名(RDN)和密码(许多服务器允许"匿名绑定"来读取信息,但是其他操作必须有密码才行)</li>
</ul>
<p>一般的LDAP编程步骤如下:</p>
<ol>
<li>ldap_connect() // 连接到LDAP服务器</li>
<li>ldap_bind() // 匿名登陆或者认证登陆</li>
<li>做一些操作,比如读取、添加、删除等...</li>
<li>ldap_unbind() // 关闭连接</li>
</ol>
<h2>LDAP常用函数简介</h2>
<dl>
<dt><b><code>resource ldap_connect ([ string $hostname = NULL [, int $port = 389 ]] )</code></b></dt>
<dd>
<p>使用指定的主机名($hostname)和端口($port)连接到LDAP服务器。</p>
<dl>
<dt><var>$hostname</var></dt>
<dd>主机名,如果服务器端是 OpenLDAP 2.x.x 或更高版本,那么还可以使用 ldap://hostname/ 格式(URL格式)。<br>
要使用SSL连接,那么必须确保OpenLDAP和PHP都带有SSL支持,并使用 ldaps://hostname/ 的格式。<br>
如果使用空格分隔的主机名列表(比如"192.168.0.100:389 192.168.0.101"),那么此函数将依次尝试直到连接成功为止。</dd>
<dt><var>$port</var></dt>
<dd>连接的端口(默认为389)。在使用URL格式的时候不需要使用此参数,直接在URL里面指明即可(ldap://hostname:port/)。</dd>
</dl>
<p>连接成功则返回一个LDAP连接标识符,连接失败则返回 FALSE 。<br>
如果服务器端是 OpenLDAP 2.x.x 或更高版本,那么此函数将始终返回一个LDAP连接标识符,而永远不会失败。实际的连接动作将在接下来调用 ldap_* 函数[通常是ldap_bind()]时执行。<br>
如果不带任何参数调用此函数,则返回上一次连接已经打开的连接标识符。</p>
</dd>
<dt><b><code>bool ldap_bind ( resource $link_identifier [, string $bind_rdn = NULL [, string $bind_password = NULL ]] )</code></b></dt>
<dd>
<p>使用指定的RDN($bind_rdn)和密码($bind_password)绑定到LDAP目录。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$bind_rdn<br>$bind_password</var></dt>
<dd>绑定时使用的RDN(Relative Distinguished Name)和密码。如果未指定则使用匿名认证。</dd>
</dl>
<p>绑定成功返回 TRUE 否则返回 FALSE 。</p>
</dd>
<dt><b><code>string ldap_error ( resource $link_identifier )</code></b></dt>
<dd>
<p>检索LDAP操作的错误信息。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
</dl>
<p>返回指定的连接标识符上最近一次LDAP操作的错误信息。</p>
</dd>
<dt><b><code>bool ldap_get_option ( resource $link_identifier , int $option , mixed &$retval )<br>bool ldap_set_option ( resource $link_identifier , int $option , mixed $newval )</code></b></dt>
<dd>
<p>获取/设置LDAP选项的值。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$option</var></dt>
<dd>LDAP选项名称,主要的选项及其数据类型如下:</dd>
<dd><dl>
<dt>LDAP_OPT_DEREF(int)</dt>
<dd>搜索的时候如何处理别名,取值范围如下:LDAP_DEREF_NEVER(0,默认值), LDAP_DEREF_SEARCHING(1), LDAP_DEREF_FINDING(2), LDAP_DEREF_ALWAYS(3)</dd>
<dt>LDAP_OPT_NETWORK_TIMEOUT(int)</dt>
<dd>网络超时秒数,LDAP_NO_LIMIT(0,默认值)表示永不超时。</dd>
<dt>LDAP_OPT_PROTOCOL_VERSION(int)</dt>
<dd>指定使用的LDAP协议版本,取值范围如下:LDAP_VERSION2(2,默认值), LDAP_VERSION3 (3)。</dd>
<dt>LDAP_OPT_REFERRALS(bool)</dt>
<dd>LDAP库是否自动追随LDAP服务器返回的引用,取值范围如下:TRUE(1,默认值), FALSE(0)。</dd>
</dl></dd>
<dt><var>&$retval</var></dt>
<dd>接受选项值的变量</dd>
<dt><var>$newval</var></dt>
<dd>选项的新值</dd>
</dl>
<p>获取/设置成功返回 TRUE 否则返回 FALSE 。</p>
</dd>
<dt><b><code>bool ldap_add ( resource $link_identifier , string $dn , array $entry )<br>bool ldap_delete ( resource $link_identifier , string $dn )</code></b></dt>
<dd>
<p>在LDAP目录中添加/删除一个项。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$dn</var></dt>
<dd>将要添加/删除的项目名称(distinguished name)。</dd>
<dt><var>$entry</var></dt>
<dd>指定新项内容的关联数组(attribute=>value)。如果value也是一个数组,那么必须是从0开始的索引数组。例如:
<pre>
$entry["bool"]='TRUE';
$entry["int"]='-3';
$entry["mail"]='jonj@example.com';
$entree["tel"][0] = "2222222";
$entree["tel"][1] = "4444444";
</pre>
</dd>
</dl>
<p>添加/删除成功返回 TRUE 否则返回 FALSE 。</p>
</dd>
<dt><b><code>mixed ldap_compare ( resource $link_identifier , string $dn , string $attribute , string $value )</code></b></dt>
<dd>
<p>检查LDAP目录项$dn的$attribute属性值与给定的$value是否相同。注意:不能用来比较二进制数据!</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$dn</var></dt>
<dd>LDAP项的名称(distinguished name)</dd>
<dt><var>$attribute</var></dt>
<dd>属性名</dd>
<dt><var>$value</var></dt>
<dd>给定的值</dd>
</dl>
<p>相同返回 TRUE ,不同返回 FALSE ,遇见错误返回 -1 </p>
</dd>
<dt><b><code>resource ldap_read ( resource $link_identifier , string $base_dn , string $filter [, array $attributes [, int $attrsonly [, int $sizelimit [, int $timelimit [, int $deref ]]]]] )<br>resource ldap_list ( resource $link_identifier , string $base_dn , string $filter [, array $attributes [, int $attrsonly [, int $sizelimit [, int $timelimit [, int $deref ]]]]] )<br>resource ldap_search ( resource $link_identifier , string $base_dn , string $filter [, array $attributes [, int $attrsonly [, int $sizelimit [, int $timelimit [, int $deref ]]]]] )</code></b></dt>
<dd>
<p>
使用指定的过滤器搜索LDAP目录。三个函数的不同之处在于搜索范围不同:<br>
read仅搜索$base_dn本身(LDAP_SCOPE_BASE),相当于从目录中读取一个条目(entry)。<br>
list仅搜索$base_dn的下一级对象(LDAP_SCOPE_ONELEVEL),不包含本身,相当于"ls"命令。<br>
search搜索$base_dn本身及其所有子对象(LDAP_SCOPE_SUBTREE),相当于搜索整个目录树。
</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$base_dn</var></dt>
<dd>将要被搜索的目录的DN</dd>
<dt><var>$filter</var></dt>
<dd>搜索过滤器。比如"(objectClass=*)"表示搜索所有条目(对于read函数则表示所有属性)。<br>其语法规则在<a href="http://www.ietf.org/rfc/rfc2254.txt">RFC2254</a>中描述,例如:"(|(sn=$person*)(givenname=$person*))"</dd>
<dt><var>$attributes</var></dt>
<dd>需要检索的属性名称数组,比如:array("mail", "sn", "cn")。<br>注意:不管有没有指定,"dn"属性的值总会被返回。<br>如果不指定此参数,那么将返回所有的属性值。</dd>
<dt><var>$attrsonly</var></dt>
<dd>默认值"0"表示同时获取属性的类型(attribute type)和属性的值(attribute value)。<br>非默认值"1"表示仅获取属性的类型(attribute type)。</dd>
<dt><var>$sizelimit</var></dt>
<dd>限定最多返回多少条记录。默认值"0"表示没有限制。注意:这个参数不能超越服务器的限制。</dd>
<dt><var>$timelimit</var></dt>
<dd>限定搜索操作最大允许进行多少秒。默认值"0"表示没有限制。注意:这个参数不能超越服务器的限制。</dd>
<dt><var>$deref</var></dt>
<dd>指定搜索的时候如何处理别名。取值范围如下:</dd>
<dd><dl>
<dt>LDAP_DEREF_NEVER(默认)</dt>
<dd>在搜索中或者查找那基础对象时做不复引用别名</dd>
<dt>LDAP_DEREF_SEARCHING</dt>
<dd>在基础对象的附属的搜索中而不是查找那基础对象时做复引用别名</dd>
<dt>LDAP_DEREF_FINDING</dt>
<dd>在基础对象而不是其附属的搜索中做复引用别名</dd>
<dt>LDAP_DEREF_ALWAYS</dt>
<dd>在搜索中或者查找那基础对象时做都复引用别名</dd>
</dl></dd>
</dl>
<p>成功返回一个结果集的资源描述符,通常被其他函数以$result_identifier引用,失败返回FALSE</p>
</dd>
<dt><b><code>array ldap_get_entries ( resource $link_identifier , resource $result_identifier )</code></b></dt>
<dd>
<p>返回前一次搜索操作的结果集,包括每一项的属性和属性值。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
<dt><var>$result_identifier</var></dt>
<dd>ldap_read/ldap_list/ldap_search函数返回的结果集的资源描述符。</dd>
</dl>
<p>
成功返回一个包含结果集的多维数组,失败返回FALSE。<br>
注意:结果集数组的属性索引将被转换成小写字母(对于LDAP来说属性是大小写无关的)。<br>
结果集数组的结构如下所示:
<pre>
return_value["count"] = 结果集中的条目总数(包含第零项)
return_value[0] : 对结果集中第零项(一般不同于后面的常规项)的详细信息的引用
return_value[i]["dn"] = 结果集中第 i 个条目的 DN
return_value[i]["count"] = 结果集中第 i 个条目的属性数量
return_value[i][j] = 结果集中第 i 个条目的第 j 个属性
return_value[i]["attribute"]["count"] = 结果集中第 i 个条目的"attribute"属性的值的数量
return_value[i]["attribute"][j] = 结果集中第 i 个条目的"attribute"属性的第 j 个值
</pre>
</p>
</dd>
<dt><b><code>bool ldap_unbind ( resource $link_identifier )</code></b></dt>
<dd>
<p>解除绑定,也就是关闭LDAP连接。</p>
<dl>
<dt><var>$link_identifier</var></dt>
<dd>ldap_connect()函数返回的LDAP连接标识符</dd>
</dl>
<p>成功返回 TRUE 否则返回 FALSE 。</p>
</dd>
</dl>
<hr />
</body></html>