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