Passed
Branch development (e0e718)
by Nils
04:45
created

adLDAPUsers   D

Complexity

Total Complexity 136

Size/Duplication

Total Lines 608
Duplicated Lines 16.28 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 99
loc 608
rs 4.84
c 0
b 0
f 0
wmc 136
lcom 1
cbo 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like adLDAPUsers often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use adLDAPUsers, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace adLDAP\classes;
3
use adLDAP\adLDAP;
4
/**
5
 * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY 
6
 * Version 5.0.0
7
 * 
8
 * PHP Version 5 with SSL and LDAP support
9
 * 
10
 * Written by Scott Barnett, Richard Hyland
11
 *   email: [email protected], [email protected]
12
 *   http://github.com/adldap/adLDAP
13
 * 
14
 * Copyright (c) 2006-2014 Scott Barnett, Richard Hyland
15
 * 
16
 * We'd appreciate any improvements or additions to be submitted back
17
 * to benefit the entire community :)
18
 * 
19
 * This library is free software; you can redistribute it and/or
20
 * modify it under the terms of the GNU Lesser General Public
21
 * License as published by the Free Software Foundation; either
22
 * version 2.1 of the License.
23
 * 
24
 * This library is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27
 * Lesser General Public License for more details.
28
 * 
29
 * @category ToolsAndUtilities
30
 * @package adLDAP
31
 * @subpackage Users
32
 * @author Scott Barnett, Richard Hyland
33
 * @copyright (c) 2006-2014 Scott Barnett, Richard Hyland
34
 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
35
 * @version 5.0.0
36
 * @link http://github.com/adldap/adLDAP
37
 */
38
require_once(dirname(__FILE__).'/../adLDAP.php');
39
require_once(dirname(__FILE__).'/../collections/adLDAPUserCollection.php');
40
41
/**
42
* USER FUNCTIONS
43
*/
44
class adLDAPUsers {
45
    /**
46
     * The current adLDAP connection via dependency injection
47
     * 
48
     * @var adLDAP
49
     */
50
    protected $adldap;
51
    
52
    public function __construct(adLDAP $adldap) {
53
        $this->adldap = $adldap;
54
    }
55
    
56
    /**
57
     * Validate a user's login credentials
58
     * 
59
     * @param string $username A user's AD username
60
     * @param string $password A user's AD password
61
     * @param bool optional $prevent_rebind
62
     * @return bool
63
     */
64
    public function authenticate($username, $password, $preventRebind = false) {
65
        return $this->adldap->authenticate($username, $password, $preventRebind);
66
    }
67
    
68
    /**
69
     * Create a user
70
     * 
71
     * If you specify a password here, this can only be performed over SSL
72
     * 
73
     * @param array $attributes The attributes to set to the user account
74
     * @return string|boolean
75
     */
76
    public function create($attributes) {
77
        // Check for compulsory fields
78
        if (!array_key_exists("username", $attributes)) { return "Missing compulsory field [username]"; }
79
        if (!array_key_exists("firstname", $attributes)) { return "Missing compulsory field [firstname]"; }
80
        if (!array_key_exists("surname", $attributes)) { return "Missing compulsory field [surname]"; }
81
        if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; }
82
        if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; }
83
        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
84
85
        if (array_key_exists("password", $attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())) { 
86
            throw new \adLDAP\adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
87
        }
88
89
        if (!array_key_exists("display_name", $attributes)) { 
90
            $attributes["display_name"] = $attributes["firstname"]." ".$attributes["surname"]; 
91
        }
92
93
        // Translate the schema
94
        $add = $this->adldap->adldap_schema($attributes);
95
        
96
        // Additional stuff only used for adding accounts
97
        $add["cn"][0] = $attributes["display_name"];
98
        $add["samaccountname"][0] = $attributes["username"];
99
        $add["objectclass"][0] = "top";
100
        $add["objectclass"][1] = "person";
101
        $add["objectclass"][2] = "organizationalPerson";
102
        $add["objectclass"][3] = "user"; //person?
103
        //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
104
105
        // Set the account control attribute
106
        $control_options = array("NORMAL_ACCOUNT");
107
        if (!$attributes["enabled"]) { 
108
            $control_options[] = "ACCOUNTDISABLE"; 
109
        }
110
        $add["userAccountControl"][0] = $this->accountControl($control_options);
111
        
112
        // Determine the container
113
        $attributes["container"] = array_reverse($attributes["container"]);
114
        $container = "OU=".implode(", OU=", $attributes["container"]);
115
116
        // Add the entry
117
        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=".$add["cn"][0].", ".$container.",".$this->adldap->getBaseDn(), $add);
118
        if ($result !== true) { 
119
            return false; 
120
        }
121
        return true;
122
    }
123
    
124
    /**
125
     * Account control options
126
     *
127
     * @param string[] $options The options to convert to int 
128
     * @return int
129
     */
130
    protected function accountControl($options) {
131
        $val = 0;
132
133
        if (is_array($options)) {
134
            if (in_array("SCRIPT", $options)) { $val = $val + 1; }
135
            if (in_array("ACCOUNTDISABLE", $options)) { $val = $val + 2; }
136
            if (in_array("HOMEDIR_REQUIRED", $options)) { $val = $val + 8; }
137
            if (in_array("LOCKOUT", $options)) { $val = $val + 16; }
138
            if (in_array("PASSWD_NOTREQD", $options)) { $val = $val + 32; }
139
            //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
140
            //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
141
            if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED", $options)) { $val = $val + 128; }
142
            if (in_array("TEMP_DUPLICATE_ACCOUNT", $options)) { $val = $val + 256; }
143
            if (in_array("NORMAL_ACCOUNT", $options)) { $val = $val + 512; }
144
            if (in_array("INTERDOMAIN_TRUST_ACCOUNT", $options)) { $val = $val + 2048; }
145
            if (in_array("WORKSTATION_TRUST_ACCOUNT", $options)) { $val = $val + 4096; }
146
            if (in_array("SERVER_TRUST_ACCOUNT", $options)) { $val = $val + 8192; }
147
            if (in_array("DONT_EXPIRE_PASSWORD", $options)) { $val = $val + 65536; }
148
            if (in_array("MNS_LOGON_ACCOUNT", $options)) { $val = $val + 131072; }
149
            if (in_array("SMARTCARD_REQUIRED", $options)) { $val = $val + 262144; }
150
            if (in_array("TRUSTED_FOR_DELEGATION", $options)) { $val = $val + 524288; }
151
            if (in_array("NOT_DELEGATED", $options)) { $val = $val + 1048576; }
152
            if (in_array("USE_DES_KEY_ONLY", $options)) { $val = $val + 2097152; }
153
            if (in_array("DONT_REQ_PREAUTH", $options)) { $val = $val + 4194304; } 
154
            if (in_array("PASSWORD_EXPIRED", $options)) { $val = $val + 8388608; }
155
            if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION", $options)) { $val = $val + 16777216; }
156
        }
157
        return $val;
158
    }
159
    
160
    /**
161
     * Delete a user account
162
     * 
163
     * @param string $username The username to delete (please be careful here!)
164
     * @param bool $isGUID Is the username a GUID or a samAccountName
165
     * @return boolean
166
     */
167
    public function delete($username, $isGUID = false) {      
168
        $userinfo = $this->info($username, array("*"), $isGUID);
169
        $dn = $userinfo[0]['distinguishedname'][0];
170
        $result = $this->adldap->folder()->delete($dn);
171
        if ($result !== true) { 
172
            return false;
173
        }        
174
        return true;
175
    }
176
    
177
    /**
178
     * Groups the user is a member of
179
     * 
180
     * @param string $username The username to query
181
     * @param bool $recursive Recursive list of groups
182
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
183
     * @return array
184
     */
185
    public function groups($username, $recursive = NULL, $isGUID = false) {
186
        if ($username === NULL) { return false; }
187
        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
188
        if (!$this->adldap->getLdapBind()) { return false; }
189
        
190
        // Search the directory for their information
191
        $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
192
        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
193
194
        if ($recursive === true) {
195
            foreach ($groups as $id => $groupName) {
196
                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
197
                $groups = array_merge($groups, $extraGroups);
198
            }
199
        }
200
        return $groups;
201
    }
202
    
203
    /**
204
     * Find information about the users. Returned in a raw array format from AD
205
     * 
206
     * @param string $username The username to query
207
     * @param array $fields Array of parameters to query
208
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
209
     * @return array
210
     */
211
    public function info($username, $fields = NULL, $isGUID = false) {
212
        if ($username === NULL) { return false; }
213
        if (!$this->adldap->getLdapBind()) { return false; }
214
215
        if ($isGUID === true) {
216
            $username = $this->adldap->utilities()->strGuidToHex($username);
217
            $filter = "objectguid=".$username;
218
        } else if (strpos($username, "@")) {
219
                $filter = "userPrincipalName=".$username;
220
        } else {
221
                $filter = "samaccountname=".$username;
222
        }
223
        $filter = "(&(objectCategory=person)({$filter}))";
224
        if ($fields === NULL) { 
225
            $fields = array("samaccountname", "mail", "memberof", "department", "displayname", "telephonenumber", "primarygroupid", "objectsid"); 
226
        }
227
        if (!in_array("objectsid", $fields)) {
228
            $fields[] = "objectsid";
229
        }
230
        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
231
        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
232
        
233
        if (isset($entries[0])) {
234
            if ($entries[0]['count'] >= 1) {
235
                if (in_array("memberof", $fields)) {
236
                    // AD does not return the primary group in the ldap query, we may need to fudge it
237
                    if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])) {
238
                        //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
239
                        $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
240
                    } else {
241
                        $entries[0]["memberof"][] = "CN=Domain Users,CN=Users,".$this->adldap->getBaseDn();
242
                    }
243
                    if (!isset($entries[0]["memberof"]["count"])) {
244
                        $entries[0]["memberof"]["count"] = 0;
245
                    }
246
                    $entries[0]["memberof"]["count"]++;
247
                }
248
            }
249
            return $entries;
250
        }
251
        return false;
252
    }
253
    
254
    /**
255
     * Find information about the users. Returned in a raw array format from AD
256
     * 
257
     * @param string $username The username to query
258
     * @param array $fields Array of parameters to query
259
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
260
     * @return mixed
261
     */
262
    public function infoCollection($username, $fields = NULL, $isGUID = false) {
263
        if ($username === NULL) { return false; }
264
        if (!$this->adldap->getLdapBind()) { return false; }
265
        
266
        $info = $this->info($username, $fields, $isGUID);
267
        
268
        if ($info !== false) {
269
            $collection = new \adLDAP\collections\adLDAPUserCollection($info, $this->adldap);
270
            return $collection;
271
        }
272
        return false;
273
    }
274
    
275
    /**
276
     * Determine if a user is in a specific group
277
     * 
278
     * @param string $username The username to query
279
     * @param string $group The name of the group to check against
280
     * @param bool $recursive Check groups recursively
281
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
282
     * @return bool
283
     */
284
    public function inGroup($username, $group, $recursive = NULL, $isGUID = false) {
285
        if ($username === NULL) { return false; }
286
        if ($group === NULL) { return false; }
287
        if (!$this->adldap->getLdapBind()) { return false; }
288
        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
289
        
290
        // Get a list of the groups
291
        $groups = $this->groups($username, $recursive, $isGUID);
292
        
293
        // Return true if the specified group is in the group list
294
        if (in_array($group, $groups)) { 
295
            return true; 
296
        }
297
        return false;
298
    }
299
    
300
    /**
301
     * Determine a user's password expiry date
302
     * 
303
     * @param string $username The username to query
304
     * @param book $isGUID Is the username passed a GUID or a samAccountName
305
     * @requires bcmath http://www.php.net/manual/en/book.bc.php
306
     * @return array
307
     */
308
    public function passwordExpiry($username, $isGUID = false) {
309
        if ($username === NULL) { return "Missing compulsory field [username]"; }
310
        if (!$this->adldap->getLdapBind()) { return false; }
311
        if (!function_exists('bcmod')) { throw new \adLDAP\adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
312
        
313
        $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
314
        $pwdLastSet = $userInfo[0]['pwdlastset'][0];
315
        $status = array();
316
        
317
        if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
318
            // Password does not expire
319
            return "Does not expire";
320
        }
321
        if ($pwdLastSet === '0') {
322
            // Password has already expired
323
            return "Password has expired";
324
        }
325
        
326
            // Password expiry in AD can be calculated from TWO values:
327
            //   - User's own pwdLastSet attribute: stores the last time the password was changed
328
            //   - Domain's maxPwdAge attribute: how long passwords last in the domain
329
            //
330
            // Although Microsoft chose to use a different base and unit for time measurements.
331
            // This function will convert them to Unix timestamps
332
            $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
333
            if (!$sr) {
334
                return false;
335
            }
336
            $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
337
            $maxPwdAge = $info[0]['maxpwdage'][0];
338
         
339
            // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
340
            //
341
            // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), 
342
            // stored in a 64 bit integer. 
343
            //
344
            // The number of seconds between this date and Unix epoch is 11644473600.
345
            //
346
            // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
347
            // intervals from the time the password was set before the password expires.
348
            //
349
            // We also need to scale this to seconds but also this value is a _negative_ quantity!
350
            //
351
            // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
352
            //
353
            // Unfortunately the maths involved are too big for PHP integers, so I've had to require
354
            // BCMath functions to work with arbitrary precision numbers.
355
            if (bcmod($maxPwdAge, 4294967296) === '0') {
356
            return "Domain does not expire passwords";
357
        }
358
        
359
        // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
360
        // time units.  Because maxpwd age is negative we need to subtract it.
361
        $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
362
    
363
        // Convert MS's time to Unix time
364
        $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
365
        $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
366
        
367
        return $status;
368
    }
369
    
370
    /**
371
     * Modify a user
372
     * 
373
     * @param string $username The username to query
374
     * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
375
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
376
     * @return string|boolean
377
     */
378
    public function modify($username, $attributes, $isGUID = false) {
379
        if ($username === NULL) { return "Missing compulsory field [username]"; }
380
        if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
381
            throw new \adLDAP\adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
382
        }
383
384
        // Find the dn of the user
385
        $userDn = $this->dn($username, $isGUID);
386
        if ($userDn === false) { 
387
            return false; 
388
        }
389
        
390
        // Translate the update to the LDAP schema                
391
        $mod = $this->adldap->adldap_schema($attributes);
392
        
393
        // Check to see if this is an enabled status update
394
        if (!$mod && !array_key_exists("enabled", $attributes)) { 
395
            return false; 
396
        }
397
        
398
        // Set the account control attribute (only if specified)
399
        if (array_key_exists("enabled", $attributes)) {
400
            if ($attributes["enabled"]) { 
401
                $controlOptions = array("NORMAL_ACCOUNT"); 
402
            } else { 
403
                $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); 
404
            }
405
            $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
406
        }
407
408
        // Do the update
409
        $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
410
        if ($result === false) { 
411
            return false; 
412
        }
413
        return true;
414
    }
415
    
416
    /**
417
     * Disable a user account
418
     * 
419
     * @param string $username The username to disable
420
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
421
     * @return string|boolean
422
     */
423
    public function disable($username, $isGUID = false) {
424
        if ($username === NULL) { return "Missing compulsory field [username]"; }
425
        $attributes = array("enabled" => 0);
426
        $result = $this->modify($username, $attributes, $isGUID);
427
        if ($result === false) { return false; }
428
       
429
        return true;
430
    }
431
    
432
    /**
433
     * Enable a user account
434
     * 
435
     * @param string $username The username to enable
436
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
437
     * @return string|boolean
438
     */
439
    public function enable($username, $isGUID = false) {
440
        if ($username === NULL) { return "Missing compulsory field [username]"; }
441
        $attributes = array("enabled" => 1);
442
        $result = $this->modify($username, $attributes, $isGUID);
443
        if ($result === false) { return false; }
444
        
445
        return true;
446
    }
447
    
448
    /**
449
     * Set the password of a user - This must be performed over SSL
450
     * 
451
     * @param string $username The username to modify
452
     * @param string $password The new password
453
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
454
     * @return bool
455
     */
456
    public function password($username, $password, $isGUID = false) {
457
        if ($username === NULL) { return false; }
458
        if ($password === NULL) { return false; }
459
        if (!$this->adldap->getLdapBind()) { return false; }
460
        if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
461
            throw new \adLDAP\adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
462
        }
463
        
464
        $userDn = $this->dn($username, $isGUID);
465
        if ($userDn === false) { 
466
            return false; 
467
        }
468
                
469
        $add = array();
470
        $add["unicodePwd"][0] = $this->encodePassword($password);
471
        
472
        $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
473
        if ($result === false) {
474
            $err = ldap_errno($this->adldap->getLdapConnection());
475
            if ($err) {
476
                $msg = 'Error '.$err.': '.ldap_err2str($err).'.';
477
                if ($err == 53) {
478
                    $msg .= ' Your password might not match the password policy.';
479
                }
480
                throw new \adLDAP\adLDAPException($msg);
481
            } else {
482
                return false;
483
            }
484
        }
485
        return true;
486
    }
487
    
488
    /**
489
     * Encode a password for transmission over LDAP
490
     *
491
     * @param string $password The password to encode
492
     * @return string
493
     */
494
    public function encodePassword($password) {
495
        $password = "\"".$password."\"";
496
        $encoded = "";
497
        for ($i = 0; $i < strlen($password); $i++) { $encoded .= "{$password{$i}}\000"; }
498
        return $encoded;
499
    }
500
     
501
    /**
502
     * Obtain the user's distinguished name based on their userid 
503
     * 
504
     * 
505
     * @param string $username The username
506
     * @param bool $isGUID Is the username passed a GUID or a samAccountName
507
     * @return string
508
     */
509
    public function dn($username, $isGUID = false) {
510
        $user = $this->info($username, array("cn"), $isGUID);
511
        if ($user[0]["dn"] === NULL) { 
512
            return false; 
513
        }
514
        $userDn = $user[0]["dn"];
515
        return $userDn;
516
    }
517
    
518
    /**
519
     * Return a list of all users in AD
520
     * 
521
     * @param bool $includeDescription Return a description of the user
522
     * @param string $search Search parameter
523
     * @param bool $sorted Sort the user accounts
524
     * @return array
525
     */
526
    public function all($includeDescription = false, $search = "*", $sorted = true) {
527
        if (!$this->adldap->getLdapBind()) { return false; }
528
        
529
        // Perform the search and grab all their details
530
        $filter = "(&(objectClass=user)(samaccounttype=".adLDAP::ADLDAP_NORMAL_ACCOUNT.")(objectCategory=person)(cn=".$search."))";
531
        $fields = array("samaccountname", "displayname");
532
        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
533
        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
534
535
        $usersArray = array();
536
        for ($i = 0; $i < $entries["count"]; $i++) {
537
            if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
538
                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
539
            } elseif ($includeDescription) {
540
                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
541
            } else {
542
                array_push($usersArray, $entries[$i]["samaccountname"][0]);
543
            }
544
        }
545
        if ($sorted) { 
546
            asort($usersArray); 
547
        }
548
        return $usersArray;
549
    }
550
    
551
    /**
552
     * Converts a username (samAccountName) to a GUID
553
     * 
554
     * @param string $username The username to query
555
     * @return string
556
     */
557
    public function usernameToGuid($username) {
558
        if (!$this->adldap->getLdapBind()) { return false; }
559
        if ($username === null) { return "Missing compulsory field [username]"; }
560
        
561
        $filter = "samaccountname=".$username; 
562
        $fields = array("objectGUID"); 
563
        $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); 
564
        if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { 
565
            $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); 
566
            $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); 
567
            $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);          
568
            return $strGUID; 
569
        }
570
        return false; 
571
    }
572
    
573
    /**
574
     * Return a list of all users in AD that have a specific value in a field
575
     *
576
     * @param bool $includeDescription Return a description of the user
577
     * @param string $searchField Field to search search for
578
     * @param string $searchFilter Value to search for in the specified field
579
     * @param bool $sorted Sort the user accounts
580
     * @return array
581
     */
582
    public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true) {
583
        if (!$this->adldap->getLdapBind()) { return false; }
584
          
585
        // Perform the search and grab all their details
586
        $searchParams = "";
587
        if ($searchField) {
588
            $searchParams = "(".$searchField."=".$searchFilter.")";
589
        }                           
590
        $filter = "(&(objectClass=user)(samaccounttype=".adLDAP::ADLDAP_NORMAL_ACCOUNT.")(objectCategory=person)".$searchParams.")";
591
        $fields = array("samaccountname", "displayname");
592
        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
593
        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
594
595
        $usersArray = array();
596
        for ($i = 0; $i < $entries["count"]; $i++) {
597
            if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
598
                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
599
            } else if ($includeDescription) {
600
                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
601
            } else {
602
                array_push($usersArray, $entries[$i]["samaccountname"][0]);
603
            }
604
        }
605
        if ($sorted) { 
606
            asort($usersArray); 
607
        }
608
        return ($usersArray);
609
    }
610
    
611
    /**
612
     * Move a user account to a different OU
613
     *
614
     * @param string $username The username to move (please be careful here!)
615
     * @param array $container The container or containers to move the user to (please be careful here!).
616
     * accepts containers in 1. parent 2. child order
617
     * @return string|boolean
618
     */
619
    public function move($username, $container) {
620
        if (!$this->adldap->getLdapBind()) { return false; }
621
        if ($username === null) { return "Missing compulsory field [username]"; }
622
        if ($container === null) { return "Missing compulsory field [container]"; }
623
        if (!is_array($container)) { return "Container must be an array"; }
624
        
625
        $userInfo = $this->info($username, array("*"));
626
        $dn = $userInfo[0]['distinguishedname'][0];
627
        $newRDn = "cn=".$username;
628
        $container = array_reverse($container);
629
        $newContainer = "ou=".implode(",ou=", $container);
630
        $newBaseDn = strtolower($newContainer).",".$this->adldap->getBaseDn();
631
        $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
632
        if ($result !== true) {
633
            return false;
634
        }
635
        return true;
636
    }
637
    
638
    /**
639
     * Get the last logon time of any user as a Unix timestamp
640
     * 
641
     * @param string $username
642
     * @return long $unixTimestamp
643
     */
644
    public function getLastLogon($username) {
645
        if (!$this->adldap->getLdapBind()) { return false; }
646
        if ($username === null) { return "Missing compulsory field [username]"; }
647
        $userInfo = $this->info($username, array("lastLogonTimestamp"));
648
        $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
649
        return $lastLogon;
650
    }
651
}
652
?>
653