blob: 6503cead3fd81c137ee69dd644d8ffc56f51d18c [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace LdapRecord;
4
5class Ldap implements LdapInterface
6{
7 use HandlesConnection, DetectsErrors;
8
9 /**
10 * @inheritdoc
11 */
12 public function getEntries($searchResults)
13 {
14 return $this->executeFailableOperation(function () use ($searchResults) {
15 return ldap_get_entries($this->connection, $searchResults);
16 });
17 }
18
19 /**
20 * Retrieves the first entry from a search result.
21 *
22 * @see http://php.net/manual/en/function.ldap-first-entry.php
23 *
24 * @param resource $searchResults
25 *
26 * @return resource
27 */
28 public function getFirstEntry($searchResults)
29 {
30 return $this->executeFailableOperation(function () use ($searchResults) {
31 return ldap_first_entry($this->connection, $searchResults);
32 });
33 }
34
35 /**
36 * Retrieves the next entry from a search result.
37 *
38 * @see http://php.net/manual/en/function.ldap-next-entry.php
39 *
40 * @param resource $entry
41 *
42 * @return resource
43 */
44 public function getNextEntry($entry)
45 {
46 return $this->executeFailableOperation(function () use ($entry) {
47 return ldap_next_entry($this->connection, $entry);
48 });
49 }
50
51 /**
52 * Retrieves the ldap entry's attributes.
53 *
54 * @see http://php.net/manual/en/function.ldap-get-attributes.php
55 *
56 * @param resource $entry
57 *
58 * @return array|false
59 */
60 public function getAttributes($entry)
61 {
62 return $this->executeFailableOperation(function () use ($entry) {
63 return ldap_get_attributes($this->connection, $entry);
64 });
65 }
66
67 /**
68 * Returns the number of entries from a search result.
69 *
70 * @see http://php.net/manual/en/function.ldap-count-entries.php
71 *
72 * @param resource $searchResults
73 *
74 * @return int
75 */
76 public function countEntries($searchResults)
77 {
78 return $this->executeFailableOperation(function () use ($searchResults) {
79 return ldap_count_entries($this->connection, $searchResults);
80 });
81 }
82
83 /**
84 * Compare value of attribute found in entry specified with DN.
85 *
86 * @see http://php.net/manual/en/function.ldap-compare.php
87 *
88 * @param string $dn
89 * @param string $attribute
90 * @param string $value
91 *
92 * @return mixed
93 */
94 public function compare($dn, $attribute, $value)
95 {
96 return $this->executeFailableOperation(function () use ($dn, $attribute, $value) {
97 return ldap_compare($this->connection, $dn, $attribute, $value);
98 });
99 }
100
101 /**
102 * @inheritdoc
103 */
104 public function getLastError()
105 {
106 if (! $this->connection) {
107 return;
108 }
109
110 return ldap_error($this->connection);
111 }
112
113 /**
114 * @inheritdoc
115 */
116 public function getDetailedError()
117 {
118 if (! $number = $this->errNo()) {
119 return;
120 }
121
122 $this->getOption(LDAP_OPT_DIAGNOSTIC_MESSAGE, $message);
123
124 return new DetailedError($number, $this->err2Str($number), $message);
125 }
126
127 /**
128 * Get all binary values from the specified result entry.
129 *
130 * @see http://php.net/manual/en/function.ldap-get-values-len.php
131 *
132 * @param $entry
133 * @param $attribute
134 *
135 * @return array
136 */
137 public function getValuesLen($entry, $attribute)
138 {
139 return $this->executeFailableOperation(function () use ($entry, $attribute) {
140 return ldap_get_values_len($this->connection, $entry, $attribute);
141 });
142 }
143
144 /**
145 * @inheritdoc
146 */
147 public function setOption($option, $value)
148 {
149 return ldap_set_option($this->connection, $option, $value);
150 }
151
152 /**
153 * @inheritdoc
154 */
155 public function getOption($option, &$value = null)
156 {
157 ldap_get_option($this->connection, $option, $value);
158
159 return $value;
160 }
161
162 /**
163 * Set a callback function to do re-binds on referral chasing.
164 *
165 * @see http://php.net/manual/en/function.ldap-set-rebind-proc.php
166 *
167 * @param callable $callback
168 *
169 * @return bool
170 */
171 public function setRebindCallback(callable $callback)
172 {
173 return ldap_set_rebind_proc($this->connection, $callback);
174 }
175
176 /**
177 * @inheritdoc
178 */
179 public function startTLS()
180 {
181 return $this->executeFailableOperation(function () {
182 return ldap_start_tls($this->connection);
183 });
184 }
185
186 /**
187 * @inheritdoc
188 */
189 public function connect($hosts = [], $port = 389)
190 {
191 $this->bound = false;
192
193 $this->host = $this->makeConnectionUris($hosts, $port);
194
195 return $this->connection = $this->executeFailableOperation(function () {
196 return ldap_connect($this->host);
197 });
198 }
199
200 /**
201 * @inheritdoc
202 */
203 public function close()
204 {
205 $result = is_resource($this->connection) ? @ldap_close($this->connection) : false;
206
207 $this->connection = null;
208 $this->bound = false;
209 $this->host = null;
210
211 return $result;
212 }
213
214 /**
215 * @inheritdoc
216 */
217 public function search($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
218 {
219 return $this->executeFailableOperation(function () use (
220 $dn,
221 $filter,
222 $fields,
223 $onlyAttributes,
224 $size,
225 $time,
226 $deref,
227 $serverControls
228 ) {
229 return empty($serverControls)
230 ? ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
231 : ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
232 });
233 }
234
235 /**
236 * @inheritdoc
237 */
238 public function listing($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
239 {
240 return $this->executeFailableOperation(function () use (
241 $dn,
242 $filter,
243 $fields,
244 $onlyAttributes,
245 $size,
246 $time,
247 $deref,
248 $serverControls
249 ) {
250 return empty($serverControls)
251 ? ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
252 : ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
253 });
254 }
255
256 /**
257 * @inheritdoc
258 */
259 public function read($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
260 {
261 return $this->executeFailableOperation(function () use (
262 $dn,
263 $filter,
264 $fields,
265 $onlyAttributes,
266 $size,
267 $time,
268 $deref,
269 $serverControls
270 ) {
271 return empty($serverControls)
272 ? ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
273 : ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
274 });
275 }
276
277 /**
278 * @inheritdoc
279 */
280 public function parseResult($result, &$errorCode, &$dn, &$errorMessage, &$referrals, &$serverControls = [])
281 {
282 return $this->executeFailableOperation(function () use (
283 $result,
284 &$errorCode,
285 &$dn,
286 &$errorMessage,
287 &$referrals,
288 &$serverControls
289 ) {
290 return empty($serverControls)
291 ? ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals)
292 : ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals, $serverControls);
293 });
294 }
295
296 /**
297 * @inheritdoc
298 */
299 public function bind($username, $password)
300 {
301 return $this->bound = $this->executeFailableOperation(function () use ($username, $password) {
302 return ldap_bind($this->connection, $username, html_entity_decode($password));
303 });
304 }
305
306 /**
307 * @inheritdoc
308 */
309 public function add($dn, array $entry)
310 {
311 return $this->executeFailableOperation(function () use ($dn, $entry) {
312 return ldap_add($this->connection, $dn, $entry);
313 });
314 }
315
316 /**
317 * @inheritdoc
318 */
319 public function delete($dn)
320 {
321 return $this->executeFailableOperation(function () use ($dn) {
322 return ldap_delete($this->connection, $dn);
323 });
324 }
325
326 /**
327 * @inheritdoc
328 */
329 public function rename($dn, $newRdn, $newParent, $deleteOldRdn = false)
330 {
331 return $this->executeFailableOperation(function () use (
332 $dn,
333 $newRdn,
334 $newParent,
335 $deleteOldRdn
336 ) {
337 return ldap_rename($this->connection, $dn, $newRdn, $newParent, $deleteOldRdn);
338 });
339 }
340
341 /**
342 * @inheritdoc
343 */
344 public function modify($dn, array $entry)
345 {
346 return $this->executeFailableOperation(function () use ($dn, $entry) {
347 return ldap_modify($this->connection, $dn, $entry);
348 });
349 }
350
351 /**
352 * @inheritdoc
353 */
354 public function modifyBatch($dn, array $values)
355 {
356 return $this->executeFailableOperation(function () use ($dn, $values) {
357 return ldap_modify_batch($this->connection, $dn, $values);
358 });
359 }
360
361 /**
362 * @inheritdoc
363 */
364 public function modAdd($dn, array $entry)
365 {
366 return $this->executeFailableOperation(function () use ($dn, $entry) {
367 return ldap_mod_add($this->connection, $dn, $entry);
368 });
369 }
370
371 /**
372 * @inheritdoc
373 */
374 public function modReplace($dn, array $entry)
375 {
376 return $this->executeFailableOperation(function () use ($dn, $entry) {
377 return ldap_mod_replace($this->connection, $dn, $entry);
378 });
379 }
380
381 /**
382 * @inheritdoc
383 */
384 public function modDelete($dn, array $entry)
385 {
386 return $this->executeFailableOperation(function () use ($dn, $entry) {
387 return ldap_mod_del($this->connection, $dn, $entry);
388 });
389 }
390
391 /**
392 * @inheritdoc
393 */
394 public function controlPagedResult($pageSize = 1000, $isCritical = false, $cookie = '')
395 {
396 return $this->executeFailableOperation(function () use ($pageSize, $isCritical, $cookie) {
397 return ldap_control_paged_result($this->connection, $pageSize, $isCritical, $cookie);
398 });
399 }
400
401 /**
402 * @inheritdoc
403 */
404 public function controlPagedResultResponse($result, &$cookie, &$estimated = null)
405 {
406 return $this->executeFailableOperation(function () use ($result, &$cookie, &$estimated) {
407 return ldap_control_paged_result_response($this->connection, $result, $cookie, $estimated);
408 });
409 }
410
411 /**
412 * @inheritdoc
413 */
414 public function freeResult($result)
415 {
416 return ldap_free_result($result);
417 }
418
419 /**
420 * @inheritdoc
421 */
422 public function errNo()
423 {
424 return $this->connection ? ldap_errno($this->connection) : null;
425 }
426
427 /**
428 * @inheritdoc
429 */
430 public function err2Str($number)
431 {
432 return ldap_err2str($number);
433 }
434
435 /**
436 * Returns the extended error hex code of the last command.
437 *
438 * @return string|null
439 */
440 public function getExtendedErrorHex()
441 {
442 if (preg_match("/(?<=data\s).*?(?=,)/", $this->getExtendedError(), $code)) {
443 return $code[0];
444 }
445 }
446
447 /**
448 * Returns the extended error code of the last command.
449 *
450 * @return bool|string
451 */
452 public function getExtendedErrorCode()
453 {
454 return $this->extractDiagnosticCode($this->getExtendedError());
455 }
456
457 /**
458 * Extract the diagnostic code from the message.
459 *
460 * @param string $message
461 *
462 * @return string|bool
463 */
464 public function extractDiagnosticCode($message)
465 {
466 preg_match('/^([\da-fA-F]+):/', $message, $matches);
467
468 return isset($matches[1]) ? $matches[1] : false;
469 }
470
471 /**
472 * @inheritdoc
473 */
474 public function getDiagnosticMessage()
475 {
476 $this->getOption(LDAP_OPT_ERROR_STRING, $message);
477
478 return $message;
479 }
480}