| 1 |
lars |
1 |
<html>
|
|
|
2 |
<head>
|
|
|
3 |
<title>Net_LDAP2 Manual</title>
|
|
|
4 |
<style type="text/css">
|
|
|
5 |
pre { border: 1px solid #000000; background-color:#EBEBEB; padding:5px; }
|
|
|
6 |
</style>
|
|
|
7 |
</head>
|
|
|
8 |
<body>
|
|
|
9 |
<h1>Net_LDAP2 Manual</h1>
|
|
|
10 |
Welcome to the Net_LDAP2 user manual! here you have a quick introduction on
|
|
|
11 |
how to use Net_LDAP2 to acces your directory server with php.
|
|
|
12 |
<p><font color="red">Note that this manual is only a brief introduction and also may be outdated.
|
|
|
13 |
The official manual is available at the <a href="http://pear.php.net/package/Net_LDAP2/docs">PEAR project website.</a>
|
|
|
14 |
The reason this manual remains here is, that it may be useful in cases you don't have internet
|
|
|
15 |
acces at the moment.</font></p>
|
|
|
16 |
|
|
|
17 |
<h2>First step: Connect</h2>
|
|
|
18 |
<p>
|
|
|
19 |
To do this, use the Net_LDAP2::connect function like this:
|
|
|
20 |
|
|
|
21 |
<p><pre>
|
|
|
22 |
require_once('Net_LDAP22/LDAP2.php');
|
|
|
23 |
|
|
|
24 |
$config = array (
|
|
|
25 |
'binddn' => 'uid=tarjei,dc=php,dc=net',
|
|
|
26 |
'bindpw' => 'secret',
|
|
|
27 |
'basedn' => dc=php,dc=net
|
|
|
28 |
);
|
|
|
29 |
|
|
|
30 |
$ldap = Net_LDAP2::connect($config);
|
|
|
31 |
</pre></p>
|
|
|
32 |
</p>
|
|
|
33 |
<p>
|
|
|
34 |
But what are valid values in the config array?
|
|
|
35 |
<ul>Here's a quick table: (defaults)
|
|
|
36 |
<li><b>binddn</b> = the DN to bind as. (none)</li>
|
|
|
37 |
<li><b>bindpw</b> = Password of the user specified by 'binddn' (none)</li>
|
|
|
38 |
<li><b>host</b> = the ldap host to connect to (localhost)</li>
|
|
|
39 |
<li><b>base</b> = ldap base, this is usually the Entry point of your directory (none)</li>
|
|
|
40 |
<li><b>port</b> = the server port (389)</li>
|
|
|
41 |
<li><b>starttls</b> = when set, ldap_start_tls() is run after connecting. (false)</li>
|
|
|
42 |
<li><b>version</b> = ldap version (defaults to v 3) </li>
|
|
|
43 |
<li><b>filter</b> = default search filter (objectclass=*)</li>
|
|
|
44 |
<li><b>scope</b> = default search scope (sub)</li>
|
|
|
45 |
</ul>
|
|
|
46 |
We'll get back to these later.
|
|
|
47 |
</p>
|
|
|
48 |
|
|
|
49 |
|
|
|
50 |
|
|
|
51 |
<h2>Errorhandling</h2>
|
|
|
52 |
<p>
|
|
|
53 |
Now you should have the base ldapobject stored in the variable "$ldap".
|
|
|
54 |
But, what if it is an error? Net_LDAP2 returns a Net_LDAP2_error object (basicly a
|
|
|
55 |
pear_error object) when an error occurs. So wherever you need to check an error, do like this:
|
|
|
56 |
<p><pre>
|
|
|
57 |
$ldap = Net_LDAP2::connect($config); // copied from above!
|
|
|
58 |
|
|
|
59 |
if (Net_LDAP2::isError($ldap)) {
|
|
|
60 |
print $ldap->getMessage(); // this will tell you what went wrong!
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
</pre></p>
|
|
|
64 |
</p>
|
|
|
65 |
<p>
|
|
|
66 |
Two things to note:
|
|
|
67 |
|
|
|
68 |
<br>1) The function is_a() might be faster:
|
|
|
69 |
<p><pre>
|
|
|
70 |
if (is_a($ldap,'net_ldap_error')) {
|
|
|
71 |
// do the same as above
|
|
|
72 |
}
|
|
|
73 |
</pre></p>
|
|
|
74 |
In PHP5 you must use the instanceof operator instead of is_a().
|
|
|
75 |
|
|
|
76 |
<br>2) Net_LDAP2_Error can also return an errornumber. These numbers are standardized. A good description of what they mean is found there:
|
|
|
77 |
http://www.directory-info.com/LDAP2/LDAPErrorCodes.html
|
|
|
78 |
</p>
|
|
|
79 |
|
|
|
80 |
|
|
|
81 |
|
|
|
82 |
<h2>Searching (basics)</h2>
|
|
|
83 |
<p>
|
|
|
84 |
Most of the work you do on an ldapserver is in searching,
|
|
|
85 |
for example, you search for your boss's password or his wife's phonenumber.
|
|
|
86 |
<br>Searching an ldapserver is a bit like doing SQL and a lot not like it at all.</br>
|
|
|
87 |
Think of the directory as some sort of "telephone book".
|
|
|
88 |
Basically, searches are performed by applying a "filter" to objects under a
|
|
|
89 |
specific "base" in the directory. Additionally, there is a "scope" applied to the search,
|
|
|
90 |
so you can specify the recursion level in the directory tree.
|
|
|
91 |
</p>
|
|
|
92 |
<p>
|
|
|
93 |
<h3>Base:</h3>
|
|
|
94 |
The "base" is the point under the directory where you want to search under.
|
|
|
95 |
To search for all people under php.net, you may use: "ou=People,dc=php,dc=net".
|
|
|
96 |
But if you want just to search the devs, you can use "ou=dev,ou=People,dc=php,dc=net".
|
|
|
97 |
</p>
|
|
|
98 |
<p>
|
|
|
99 |
<h3>Filter:</h3> Filters define what you are looking for. They "filter out" unwanted entries.
|
|
|
100 |
<br>Filters start with a ( and end with a ). There is a lot to be said about filters, most is better said by examples:
|
|
|
101 |
|
|
|
102 |
<br><br><b>(&(objectclass=posixAccount)(uid=boss)) :</b> The object has to satisfy both filters.
|
|
|
103 |
I.e. an object that is both boss and an posixAccount. If you had another object
|
|
|
104 |
with uid=boss but that wasn't an postixaccount it would be excluded.
|
|
|
105 |
<br><b>(|(uid=boss)(uid=secretary)) :</b> Either the boss or the secretary.
|
|
|
106 |
Note that both logical operators are placed before the filters not between the
|
|
|
107 |
two conditions as you might used to from sql.
|
|
|
108 |
<br><b>(&(objectclass=posixAccount)(|(uid=boss)(uid=secretary))) :</b>
|
|
|
109 |
Here they must have the posixAccount objectclass as well.
|
|
|
110 |
|
|
|
111 |
<b>(objectclass=*) :</b> All objects must have an objectclass, so this is the simplest way of saying everything.
|
|
|
112 |
|
|
|
113 |
<b>(uid=t*) :</b> With the right indexes on the server, you may search the substring of an attriute. Here; all users with the first name beginning with a "T".
|
|
|
114 |
|
|
|
115 |
<br>Please note, that Net_LDAP2 provides a filter class for simplier generation and combination of filters.
|
|
|
116 |
You should use that class unless you know how filters work. This will save you a lot of trouble,
|
|
|
117 |
since there are some encoding issues with ldap-filters. If you want to provide the filter yourself,
|
|
|
118 |
you should also have a look to <a href="http://www.ietf.org/rfc/rfc1558.txt">RFC #1558</a> defining LDAP-Filters.
|
|
|
119 |
</p>
|
|
|
120 |
|
|
|
121 |
<p>
|
|
|
122 |
<h3>Searchscope</h3>
|
|
|
123 |
The scope of an search may be three things:
|
|
|
124 |
<ul>
|
|
|
125 |
<li><b>'base'</b> = Just the entry in question.</li>
|
|
|
126 |
<li><b>'sub'</b> = All subentries.</li>
|
|
|
127 |
<li><b>'one'</b> = All entries just below the searchbase.</li>
|
|
|
128 |
</ul>
|
|
|
129 |
|
|
|
130 |
Searching with scope 'base' may be handy for getting just one entry. But then again, that's what the getEntry function does.
|
|
|
131 |
</p>
|
|
|
132 |
|
|
|
133 |
<p>
|
|
|
134 |
<h3>Searching some entries</h3>
|
|
|
135 |
We know now, how to search, so we will test out our new knowledge.
|
|
|
136 |
We want to search all person entries whose second name starts with "Ha", but only developers.
|
|
|
137 |
Later we want to know the name and the telephone number of the persons.
|
|
|
138 |
<pre>
|
|
|
139 |
$filter = '(&(objectclass=person)(sn=Ha*))';
|
|
|
140 |
$searchbase = 'ou=dev,ou=People,dc=php,dc=net';
|
|
|
141 |
$options = array(
|
|
|
142 |
'scope' => 'sub', // all entries below the searchbase (recursive all subtrees from there)
|
|
|
143 |
'attributes' => array('sn','gn','telephonenumber') // what attributes to select
|
|
|
144 |
);
|
|
|
145 |
$search = $ldap->search($searchbase, $filter, $options);
|
|
|
146 |
</pre>
|
|
|
147 |
$search should now be an Net_LDAP2_Search object.
|
|
|
148 |
<br>Okay, now we assume that everything was fine (in production, test for error!).
|
|
|
149 |
We have several options now.
|
|
|
150 |
We can fetch the found entries at once sorted ($search->sorted()) or unsorted ($search->entries()), or we can read
|
|
|
151 |
the objects one by one inside a loop using $search->shiftEntry(). See the class documentation of Net_LDAP2_Search
|
|
|
152 |
for more details.
|
|
|
153 |
</p>
|
|
|
154 |
|
|
|
155 |
<h2>Entries</h2>
|
|
|
156 |
<p>
|
|
|
157 |
This describes how to get an entry and modifying it.
|
|
|
158 |
If we just want one single entry, it may be useful to directly fetch that entry instead
|
|
|
159 |
of searching it manually. To do this you can use Net_LDAP2s "getEntry()" method:
|
|
|
160 |
<pre>
|
|
|
161 |
$dn = 'cn=Foo Bar,ou=dev,ou=People,dc=php,dc=net';
|
|
|
162 |
$entry =& $ldap->getEntry($dn, array('sn','gn','telephonenumber'));
|
|
|
163 |
</pre>
|
|
|
164 |
</p>
|
|
|
165 |
With this entry object you now can perform some actions like fetching the contents of attributes:
|
|
|
166 |
<pre>
|
|
|
167 |
$telephonenumber = $entry->getValue('telephonenumber','single');
|
|
|
168 |
</pre>
|
|
|
169 |
Or you can modify a attribute:
|
|
|
170 |
<pre>
|
|
|
171 |
$entry->replace("telephonenumber" => "0123456789"); // replace the attributes values with the new number
|
|
|
172 |
$entry->update(); // update temporarily modified entry on the server
|
|
|
173 |
</pre>
|
|
|
174 |
Of course there are much more other possibilitys. Please note that adding and deleting
|
|
|
175 |
whole entrys is performed through the Net_LDAP2 class and not with the Net_LDAP2_Entry class.
|
|
|
176 |
|
|
|
177 |
<h2>Schemas</h2>
|
|
|
178 |
You may also use Net_LDAP2 to find out what schemas your ldap-server supports. Here's an example of how:
|
|
|
179 |
<pre>
|
|
|
180 |
$schema = $ldap->schema();
|
|
|
181 |
</pre>
|
|
|
182 |
Now you got a schemaobject.
|
|
|
183 |
To read from this schemaobject, you have several methods defined in the class Net_LDAP2_Schema.
|
|
|
184 |
<br>For example, to find out which attributes are required for inetOrgPerson, you do this:
|
|
|
185 |
<pre>
|
|
|
186 |
$required = $schema->must( 'inetOrgUser' );
|
|
|
187 |
|
|
|
188 |
print_r($required);
|
|
|
189 |
/* The output of this will be:
|
|
|
190 |
Array
|
|
|
191 |
(
|
|
|
192 |
[0] => sn
|
|
|
193 |
[1] => cn
|
|
|
194 |
)
|
|
|
195 |
*/
|
|
|
196 |
</pre>
|
|
|
197 |
|
|
|
198 |
Ok, but what kind of attribute is sn? Let's check:
|
|
|
199 |
<pre>
|
|
|
200 |
$att = $schema->get('attribute','sn');
|
|
|
201 |
|
|
|
202 |
print_r($att);
|
|
|
203 |
/* The output of this will be:
|
|
|
204 |
Array
|
|
|
205 |
(
|
|
|
206 |
[aliases] => Array
|
|
|
207 |
(
|
|
|
208 |
[0] => surname
|
|
|
209 |
)
|
|
|
210 |
|
|
|
211 |
[oid] => 2.5.4.4
|
|
|
212 |
[name] => sn
|
|
|
213 |
[desc] => RFC2256: last (family) name(s) for which the entity is known by
|
|
|
214 |
[sup] => Array
|
|
|
215 |
(
|
|
|
216 |
[0] => name
|
|
|
217 |
)
|
|
|
218 |
[type] => attribute
|
|
|
219 |
)
|
|
|
220 |
*/
|
|
|
221 |
</pre>
|
|
|
222 |
Hmm, ok, the sup part is important. It means that surname derives it's syntax from another attribute,
|
|
|
223 |
the name attribute. So , we need to check that as well.
|
|
|
224 |
<br>We do:
|
|
|
225 |
<pre>
|
|
|
226 |
$att_dep = $schema->get('attribute',$att['sup'][0]);
|
|
|
227 |
|
|
|
228 |
print_r($att_dep);
|
|
|
229 |
/* The output of this will be:
|
|
|
230 |
Array
|
|
|
231 |
(
|
|
|
232 |
[aliases] => Array
|
|
|
233 |
(
|
|
|
234 |
)
|
|
|
235 |
|
|
|
236 |
[oid] => 2.5.4.41
|
|
|
237 |
[name] => name
|
|
|
238 |
[desc] => RFC2256: common supertype of name attributes
|
|
|
239 |
[equality] => caseIgnoreMatch
|
|
|
240 |
[substr] => caseIgnoreSubstringsMatch
|
|
|
241 |
[syntax] => 1.3.6.1.4.1.1466.115.121.1.15{32768}
|
|
|
242 |
[max_length] => 32768
|
|
|
243 |
[type] => attribute
|
|
|
244 |
)
|
|
|
245 |
*/
|
|
|
246 |
</pre>
|
|
|
247 |
From this we find out that the attribute has a maxlength of 32768 characters
|
|
|
248 |
and has the syntax 1.3.6.1.4.1.1466.115.121.1.15{32768}.
|