diff --git a/src/adLDAP.php b/src/adLDAP.php index 6831c72..152e70d 100644 --- a/src/adLDAP.php +++ b/src/adLDAP.php @@ -163,6 +163,13 @@ class adLDAP { */ protected $recursiveGroups = true; + /** + * Charset used for internal encoding + * + * @var string + */ + public $charset = 'iso-8859-1'; + // You should not need to edit anything below this line //****************************************************************************************** @@ -584,6 +591,9 @@ function __construct($options = array()) { $this->setUseSSO(false); } } + if (array_key_exists("charset", $options)) { + $this->charset = strtolower($options["charset"]); + } } if ($this->ldapSupported() === false) { @@ -919,15 +929,18 @@ public function adldap_schema($attributes) { */ protected function encode8Bit(&$item, $key) { $encode = false; - if (is_string($item)) { + if (is_string($item) && $key != 'password' && $this->charset != 'utf-8') { for ($i=0; $i> 7) { $encode = true; + break; } } } - if ($encode === true && $key != 'password') { - $item = utf8_encode($item); + if ($encode === true) { + $item = function_exists('mb_convert_encoding') ? + mb_convert_encoding($item, 'utf-8', $this->charset) : + utf8_encode($item); } } diff --git a/src/classes/adLDAPGroups.php b/src/classes/adLDAPGroups.php index e95b477..6f2e426 100644 --- a/src/classes/adLDAPGroups.php +++ b/src/classes/adLDAPGroups.php @@ -1,29 +1,29 @@ adldap = $adldap; } - + /** * Add a group to a group - * + * * @param string $parent The parent group name * @param string $child The child group name * @return bool @@ -64,30 +64,30 @@ public function addGroup($parent,$child) { // Find the parent group's dn $parentGroup = $this->ginfo($parent, array("cn")); if ($parentGroup[0]["dn"] === NULL) { - return false; + return false; } $parentDn = $parentGroup[0]["dn"]; - + // Find the child group's dn $childGroup = $this->info($child, array("cn")); - if ($childGroup[0]["dn"] === NULL) { - return false; - } + if ($childGroup[0]["dn"] === NULL) { + return false; + } $childDn = $childGroup[0]["dn"]; - + $add = array(); $add["member"] = $childDn; - + $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add); - if ($result == false) { - return false; + if ($result == false) { + return false; } return true; } - + /** * Add a user to a group - * + * * @param string $group The group to add the user to * @param string $user The user to add to the group * @param bool $isGUID Is the username passed a GUID or a samAccountName @@ -96,33 +96,33 @@ public function addGroup($parent,$child) { public function addUser($group, $user, $isGUID = false) { // Adding a user is a bit fiddly, we need to get the full DN of the user // and add it using the full DN of the group - + // Find the user's dn $userDn = $this->adldap->user()->dn($user, $isGUID); - if ($userDn === false) { - return false; + if ($userDn === false) { + return false; } - + // Find the group's dn $groupInfo = $this->info($group, array("cn")); - if ($groupInfo[0]["dn"] === NULL) { - return false; + if ($groupInfo[0]["dn"] === NULL) { + return false; } $groupDn = $groupInfo[0]["dn"]; - + $add = array(); $add["member"] = $userDn; - + $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add); - if ($result == false) { - return false; + if ($result == false) { + return false; } return true; } - + /** * Add a contact to a group - * + * * @param string $group The group to add the contact to * @param string $contactDn The DN of the contact to add * @return bool @@ -131,42 +131,43 @@ public function addContact($group, $contactDn) { // To add a contact we take the contact's DN // and add it using the full DN of the group - + // Find the group's dn $groupInfo = $this->info($group, array("cn")); - if ($groupInfo[0]["dn"] === NULL) { - return false; + if ($groupInfo[0]["dn"] === NULL) { + return false; } $groupDn = $groupInfo[0]["dn"]; - + $add = array(); $add["member"] = $contactDn; - + $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add); - if ($result == false) { - return false; + if ($result == false) { + return false; } return true; } /** * Create a group - * + * + * Extended to allow to specify $attribute["container"] as string, because array hardcodes "OU=", while Samba4 and win2008r2 uses "CN=Users" + * * @param array $attributes Default attributes of the group * @return bool */ public function create($attributes) { - if (!is_array($attributes)) { return "Attributes must be an array"; } - if (!array_key_exists("group_name", $attributes)) { return "Missing compulsory field [group_name]"; } - if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; } - if (!array_key_exists("description", $attributes)) { return "Missing compulsory field [description]"; } - if (!is_array($attributes["container"])) { return "Container attribute must be an array."; } - $attributes["container"] = array_reverse($attributes["container"]); + if (!is_array($attributes)){ return "Attributes must be an array"; } + if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; } + if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; } + if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; } + if (empty($attributes["container"])){ return "Container attribute must be an array or string."; } //$member_array = array(); //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com"; //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com"; - + $add = array(); $add["cn"] = $attributes["group_name"]; $add["samaccountname"] = $attributes["group_name"]; @@ -174,217 +175,221 @@ public function create($attributes) { $add["description"] = $attributes["description"]; //$add["member"] = $member_array; UNTESTED - $container = "OU=" . implode(",OU=", $attributes["container"]); - $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add); - if ($result != true) { - return false; + // Determine the container + if (is_array($attributes['container'])) { + $attributes["container"] = array_reverse($attributes["container"]); + $attributes["container"] = "OU=" . implode(",OU=",$attributes["container"]); + } + $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . "," . $attributes["container"] . "," . $this->adldap->getBaseDn(), $add); + if ($result != true) { + return false; } return true; } - + /** - * Delete a group account - * - * @param string $group The group to delete (please be careful here!) - * - * @return array + * Delete a group account + * + * @param string $group The group to delete (please be careful here!) + * + * @return array */ public function delete($group) { if (!$this->adldap->getLdapBind()) { return false; } if ($group === null) { return "Missing compulsory field [group]"; } - + $groupInfo = $this->info($group, array("*")); - $dn = $groupInfo[0]['distinguishedname'][0]; - $result = $this->adldap->folder()->delete($dn); - if ($result !== true) { - return false; - } - return true; + $dn = $groupInfo[0]['distinguishedname'][0]; + $result = $this->adldap->folder()->delete($dn); + if ($result !== true) { + return false; + } + return true; } /** * Remove a group from a group - * + * * @param string $parent The parent group name * @param string $child The child group name * @return bool */ public function removeGroup($parent , $child) { - + // Find the parent dn $parentGroup = $this->info($parent, array("cn")); - if ($parentGroup[0]["dn"] === NULL) { - return false; + if ($parentGroup[0]["dn"] === NULL) { + return false; } $parentDn = $parentGroup[0]["dn"]; - + // Find the child dn $childGroup = $this->info($child, array("cn")); - if ($childGroup[0]["dn"] === NULL) { - return false; + if ($childGroup[0]["dn"] === NULL) { + return false; } $childDn = $childGroup[0]["dn"]; - + $del = array(); $del["member"] = $childDn; - + $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del); - if ($result == false) { - return false; + if ($result == false) { + return false; } return true; } - + /** * Remove a user from a group - * + * * @param string $group The group to remove a user from * @param string $user The AD user to remove from the group * @param bool $isGUID Is the username passed a GUID or a samAccountName * @return bool */ public function removeUser($group, $user, $isGUID = false) { - + // Find the parent dn $groupInfo = $this->info($group, array("cn")); - if ($groupInfo[0]["dn"] === NULL) { - return false; + if ($groupInfo[0]["dn"] === NULL) { + return false; } $groupDn = $groupInfo[0]["dn"]; - + // Find the users dn $userDn = $this->adldap->user()->dn($user, $isGUID); if ($userDn === false) { - return false; + return false; } $del = array(); $del["member"] = $userDn; - + $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del); if ($result == false) { - return false; + return false; } return true; } - + /** * Remove a contact from a group - * + * * @param string $group The group to remove a user from * @param string $contactDn The DN of a contact to remove from the group * @return bool */ public function removeContact($group, $contactDn) { - + // Find the parent dn $groupInfo = $this->info($group, array("cn")); - if ($groupInfo[0]["dn"] === NULL) { - return false; + if ($groupInfo[0]["dn"] === NULL) { + return false; } $groupDn = $groupInfo[0]["dn"]; - + $del = array(); $del["member"] = $contactDn; - + $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del); - if ($result == false) { - return false; + if ($result == false) { + return false; } return true; } - + /** * Return a list of groups in a group - * + * * @param string $group The group to query * @param bool $recursive Recursively get groups * @return array */ public function inGroup($group, $recursive = NULL) { if (!$this->adldap->getLdapBind()){ return false; } - if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it - + if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it + // Search the directory for the members of a group $info = $this->info($group, array("member","cn")); $groups = $info[0]["member"]; if (!is_array($groups)) { - return false; + return false; } - + $groupArray = array(); - for ($i=0; $i<$groups["count"]; $i++) { + for ($i=0; $i<$groups["count"]; $i++) { $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))"; $fields = array("samaccountname", "distinguishedname", "objectClass"); $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); - // not a person, look for a group - if ($entries['count'] == 0 && $recursive == true) { - $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))"; - $fields = array("distinguishedname"); - $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); - $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); + // not a person, look for a group + if ($entries['count'] == 0 && $recursive == true) { + $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))"; + $fields = array("distinguishedname"); + $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); + $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); if (!isset($entries[0]['distinguishedname'][0])) { - continue; + continue; } - $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive); + $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive); if (is_array($subGroups)) { - $groupArray = array_merge($groupArray, $subGroups); - $groupArray = array_unique($groupArray); + $groupArray = array_merge($groupArray, $subGroups); + $groupArray = array_unique($groupArray); } - continue; - } + continue; + } $groupArray[] = $entries[0]['distinguishedname'][0]; } return $groupArray; } - + /** * Return a list of members in a group - * + * * @param string $group The group to query * @param bool $recursive Recursively get group members * @return array */ public function members($group, $recursive = NULL) { if (!$this->adldap->getLdapBind()) { return false; } - if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it + if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it // Search the directory for the members of a group $info = $this->info($group, array("member","cn")); $users = $info[0]["member"]; if (!is_array($users)) { - return false; + return false; } - + $userArray = array(); - for ($i=0; $i<$users["count"]; $i++) { + for ($i=0; $i<$users["count"]; $i++) { $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))"; $fields = array("samaccountname", "distinguishedname", "objectClass"); $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); - // not a person, look for a group - if ($entries['count'] == 0 && $recursive == true) { - $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))"; - $fields = array("samaccountname"); - $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); - $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); + // not a person, look for a group + if ($entries['count'] == 0 && $recursive == true) { + $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))"; + $fields = array("samaccountname"); + $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); + $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); if (!isset($entries[0]['samaccountname'][0])) { - continue; + continue; } - $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive); + $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive); if (is_array($subUsers)) { - $userArray = array_merge($userArray, $subUsers); - $userArray = array_unique($userArray); + $userArray = array_merge($userArray, $subUsers); + $userArray = array_unique($userArray); } - continue; - } - else if ($entries['count'] == 0) { - continue; - } + continue; + } + else if ($entries['count'] == 0) { + continue; + } if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) { $userArray[] = $entries[0]['distinguishedname'][0]; @@ -395,11 +400,11 @@ public function members($group, $recursive = NULL) { } return $userArray; } - + /** * Group Information. Returns an array of raw information about a group. * The group name is case sensitive - * + * * @param string $groupName The group name to retrieve info about * @param array $fields Fields to retrieve * @return array @@ -407,14 +412,14 @@ public function members($group, $recursive = NULL) { public function info($groupName, $fields = NULL) { if ($groupName === NULL) { return false; } if (!$this->adldap->getLdapBind()) { return false; } - + if (stristr($groupName, '+')) { - $groupName = stripslashes($groupName); + $groupName = stripslashes($groupName); } - + $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))"; - if ($fields === NULL) { - $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); + if ($fields === NULL) { + $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); } $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); @@ -442,11 +447,11 @@ public function info($groupName, $fields = NULL) { } return $entries; } - + /** * Group Information. Returns an collection * The group name is case sensitive - * + * * @param string $groupName The group name to retrieve info about * @param array $fields Fields to retrieve * @return adLDAPGroupCollection @@ -454,7 +459,7 @@ public function info($groupName, $fields = NULL) { public function infoCollection($groupName, $fields = NULL) { if ($groupName === NULL) { return false; } if (!$this->adldap->getLdapBind()) { return false; } - + $info = $this->info($groupName, $fields); if ($info !== false) { $collection = new adLDAPGroupCollection($info, $this->adldap); @@ -462,33 +467,33 @@ public function infoCollection($groupName, $fields = NULL) { } return false; } - + /** * Return a complete list of "groups in groups" - * + * * @param string $group The group to get the list from * @return array */ public function recursiveGroups($group) { if ($group === NULL) { return false; } - $stack = array(); - $processed = array(); - $retGroups = array(); - - array_push($stack, $group); // Initial Group to Start with + $stack = array(); + $processed = array(); + $retGroups = array(); + + array_push($stack, $group); // Initial Group to Start with while (count($stack) > 0) { $parent = array_pop($stack); array_push($processed, $parent); - + $info = $this->info($parent, array("memberof")); - + if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) { - $groups = $info[0]["memberof"]; + $groups = $info[0]["memberof"]; if ($groups) { - $groupNames = $this->adldap->utilities()->niceNames($groups); + $groupNames = $this->adldap->utilities()->niceNames($groups); $retGroups = array_merge($retGroups, $groupNames); //final groups to return - foreach ($groupNames as $id => $groupName) { + foreach ($groupNames as $id => $groupName) { if (!in_array($groupName, $processed)) { array_push($stack, $groupName); } @@ -498,10 +503,10 @@ public function recursiveGroups($group) { } return $retGroups; } - + /** - * Returns a complete list of the groups in AD based on a SAM Account Type - * + * Returns a complete list of the groups in AD based on a SAM Account Type + * * @param string $sAMAaccountType The account type to return * @param bool $includeDescription Whether to return a description * @param string $search Search parameters @@ -510,7 +515,7 @@ public function recursiveGroups($group) { */ public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) { if (!$this->adldap->getLdapBind()) { return false; } - + $filter = '(&(objectCategory=group)'; if ($sAMAaccountType !== null) { $filter .= '(samaccounttype='. $sAMAaccountType .')'; @@ -521,7 +526,7 @@ public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); - $groupsArray = array(); + $groupsArray = array(); for ($i=0; $i<$entries["count"]; $i++) { if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) { $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0]; @@ -533,8 +538,8 @@ public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, array_push($groupsArray, $entries[$i]["samaccountname"][0]); } } - if ($sorted) { - asort($groupsArray); + if ($sorted) { + asort($groupsArray); } return $groupsArray; } @@ -557,7 +562,7 @@ public function dn($groupname) { /** * Returns a complete list of all groups in AD - * + * * @param bool $includeDescription Whether to return a description * @param string $search Search parameters * @param bool $sorted Whether to sort the results @@ -567,10 +572,10 @@ public function all($includeDescription = false, $search = "*", $sorted = true) $groupsArray = $this->search(null, $includeDescription, $search, $sorted); return $groupsArray; } - + /** * Returns a complete list of security groups in AD - * + * * @param bool $includeDescription Whether to return a description * @param string $search Search parameters * @param bool $sorted Whether to sort the results @@ -580,10 +585,10 @@ public function allSecurity($includeDescription = false, $search = "*", $sorted $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted); return $groupsArray; } - + /** * Returns a complete list of distribution lists in AD - * + * * @param bool $includeDescription Whether to return a description * @param string $search Search parameters * @param bool $sorted Whether to sort the results @@ -593,14 +598,14 @@ public function allDistribution($includeDescription = false, $search = "*", $sor $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted); return $groupsArray; } - + /** * Coping with AD not returning the primary group - * http://support.microsoft.com/?kbid=321360 - * - * This is a re-write based on code submitted by Bruce which prevents the + * http://support.microsoft.com/?kbid=321360 + * + * This is a re-write based on code submitted by Bruce which prevents the * need to search each security group to find the true primary group - * + * * @param string $gid Group ID * @param string $usersid User's Object SID * @return mixed @@ -620,29 +625,29 @@ public function getPrimaryGroup($gid, $usersid) { } return false; } - + /** * Coping with AD not returning the primary group - * http://support.microsoft.com/?kbid=321360 - * + * http://support.microsoft.com/?kbid=321360 + * * For some reason it's not possible to search on primarygrouptoken=XXX * If someone can show otherwise, I'd like to know about it :) * this way is resource intensive and generally a pain in the @#%^ - * + * * @deprecated deprecated since version 3.1, see get get_primary_group * @param string $gid Group ID * @return string */ - public function cn($gid) { + public function cn($gid) { if ($gid === NULL) { return false; } $sr = false; $r = ''; - + $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))"; $fields = array("primarygrouptoken", "samaccountname", "distinguishedname"); $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); - + for ($i=0; $i<$entries["count"]; $i++) { if ($entries[$i]["primarygrouptoken"][0] == $gid) { $r = $entries[$i]["distinguishedname"][0]; diff --git a/src/classes/adLDAPUsers.php b/src/classes/adLDAPUsers.php index 65c5733..8490974 100644 --- a/src/classes/adLDAPUsers.php +++ b/src/classes/adLDAPUsers.php @@ -1,29 +1,29 @@ adldap = $adldap; } - + /** * Validate a user's login credentials - * + * * @param string $username A user's AD username * @param string $password A user's AD password * @param bool optional $prevent_rebind @@ -63,38 +63,46 @@ public function __construct(adLDAP $adldap) { public function authenticate($username, $password, $preventRebind = false) { return $this->adldap->authenticate($username, $password, $preventRebind); } - + /** * Create a user - * + * * If you specify a password here, this can only be performed over SSL - * + * + * Extended to allow to specify $attribute["container"] as string, because array hardcodes "OU=", while Samba4 and win2008r2 uses "CN=Users" + * + * Extended to ensure following creating order required by at least win2008r2: + * - new user without password and deactivated + * - add password, see new method setPassword + * - activate user + * * @param array $attributes The attributes to set to the user account * @return bool */ public function create($attributes) { // Check for compulsory fields - if (!array_key_exists("username", $attributes)) { return "Missing compulsory field [username]"; } - if (!array_key_exists("firstname", $attributes)) { return "Missing compulsory field [firstname]"; } - if (!array_key_exists("surname", $attributes)) { return "Missing compulsory field [surname]"; } - if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; } - if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; } - if (!is_array($attributes["container"])) { return "Container attribute must be an array."; } - - if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())) { + if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; } + if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; } + if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; } + if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; } + if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; } + if (empty($attributes["container"])){ return "Container attribute must be an array or string."; } + + if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())) { throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.'); } - if (!array_key_exists("display_name", $attributes)) { - $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; + if (!array_key_exists("display_name", $attributes)) { + $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; } // Translate the schema $add = $this->adldap->adldap_schema($attributes); - + // Additional stuff only used for adding accounts - $add["cn"][0] = $attributes["display_name"]; + $add["cn"][0] = $attributes["username"]; // win2008r2 uses username, not displayname $add["samaccountname"][0] = $attributes["username"]; + $add["userPrincipalName"][0] = $attributes["username"].$this->adldap->getAccountSuffix(); $add["objectclass"][0] = "top"; $add["objectclass"][1] = "person"; $add["objectclass"][2] = "organizationalPerson"; @@ -102,28 +110,44 @@ public function create($attributes) { //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"]; // Set the account control attribute - $control_options = array("NORMAL_ACCOUNT"); - if (!$attributes["enabled"]) { - $control_options[] = "ACCOUNTDISABLE"; - } + $control_options = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); $add["userAccountControl"][0] = $this->accountControl($control_options); - + // Determine the container + if (is_array($attributes['container'])) { $attributes["container"] = array_reverse($attributes["container"]); - $container = "OU=" . implode(", OU=",$attributes["container"]); + $attributes["container"] = "OU=" . implode(",OU=",$attributes["container"]); + } + // we can NOT set password with ldap_add or ldap_modify, it needs ldap_mod_replace, at least under Win2008r2 + unset($add['unicodePwd']); // Add the entry - $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add); - if ($result != true) { - return false; + $result = @ldap_add($ds=$this->adldap->getLdapConnection(), $dn="CN=" . $add["cn"][0] . "," . $attributes["container"] . "," . $this->adldap->getBaseDn(), $add); + if ($result != true) { + return false; } + + // now password can be added to still disabled account + if (array_key_exists("password",$attributes)) + { + if (!$this->setPassword($dn, $attributes['password'])) return false; + + // now account can be enabled + if ($attributes["enabled"]) + { + $control_options = array("NORMAL_ACCOUNT"); + $mod = array("userAccountControl" => $this->accountControl($control_options)); + $result = @ldap_modify($ds, $dn, $mod); + } + } + return true; } - + /** * Account control options * - * @param array $options The options to convert to int + * @param array $options The options to convert to int * @return int */ protected function accountControl($options) { @@ -149,33 +173,33 @@ protected function accountControl($options) { if (in_array("TRUSTED_FOR_DELEGATION",$options)) { $val=$val+524288; } if (in_array("NOT_DELEGATED",$options)) { $val=$val+1048576; } if (in_array("USE_DES_KEY_ONLY",$options)) { $val=$val+2097152; } - if (in_array("DONT_REQ_PREAUTH",$options)) { $val=$val+4194304; } + if (in_array("DONT_REQ_PREAUTH",$options)) { $val=$val+4194304; } if (in_array("PASSWORD_EXPIRED",$options)) { $val=$val+8388608; } if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)) { $val=$val+16777216; } } return $val; } - + /** * Delete a user account - * + * * @param string $username The username to delete (please be careful here!) * @param bool $isGUID Is the username a GUID or a samAccountName * @return array */ - public function delete($username, $isGUID = false) { + public function delete($username, $isGUID = false) { $userinfo = $this->info($username, array("*"), $isGUID); $dn = $userinfo[0]['distinguishedname'][0]; $result = $this->adldap->folder()->delete($dn); - if ($result != true) { + if ($result != true) { return false; - } + } return true; } - + /** * Groups the user is a member of - * + * * @param string $username The username to query * @param bool $recursive Recursive list of groups * @param bool $isGUID Is the username passed a GUID or a samAccountName @@ -185,7 +209,7 @@ public function groups($username, $recursive = NULL, $isGUID = false) { if ($username === NULL) { return false; } if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it if (!$this->adldap->getLdapBind()) { return false; } - + // Search the directory for their information $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID); $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames) @@ -198,10 +222,10 @@ public function groups($username, $recursive = NULL, $isGUID = false) { } return $groups; } - + /** * Find information about the users. Returned in a raw array format from AD - * + * * @param string $username The username to query * @param array $fields Array of parameters to query * @param bool $isGUID Is the username passed a GUID or a samAccountName @@ -222,15 +246,15 @@ public function info($username, $fields = NULL, $isGUID = false) { $filter = "samaccountname=" . $username; } $filter = "(&(objectCategory=person)({$filter}))"; - if ($fields === NULL) { - $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); + if ($fields === NULL) { + $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); } if (!in_array("objectsid", $fields)) { $fields[] = "objectsid"; } $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr); - + if (isset($entries[0])) { if ($entries[0]['count'] >= 1) { if (in_array("memberof", $fields)) { @@ -251,10 +275,10 @@ public function info($username, $fields = NULL, $isGUID = false) { } return false; } - + /** * Find information about the users. Returned in a raw array format from AD - * + * * @param string $username The username to query * @param array $fields Array of parameters to query * @param bool $isGUID Is the username passed a GUID or a samAccountName @@ -263,19 +287,19 @@ public function info($username, $fields = NULL, $isGUID = false) { public function infoCollection($username, $fields = NULL, $isGUID = false) { if ($username === NULL) { return false; } if (!$this->adldap->getLdapBind()) { return false; } - + $info = $this->info($username, $fields, $isGUID); - + if ($info !== false) { $collection = new adLDAPUserCollection($info, $this->adldap); return $collection; } return false; } - + /** * Determine if a user is in a specific group - * + * * @param string $username The username to query * @param string $group The name of the group to check against * @param bool $recursive Check groups recursively @@ -287,20 +311,20 @@ public function inGroup($username, $group, $recursive = NULL, $isGUID = false) { if ($group === NULL) { return false; } if (!$this->adldap->getLdapBind()) { return false; } if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it - + // Get a list of the groups $groups = $this->groups($username, $recursive, $isGUID); - + // Return true if the specified group is in the group list - if (in_array($group, $groups)) { - return true; + if (in_array($group, $groups)) { + return true; } return false; } - + /** * Determine a user's password expiry date - * + * * @param string $username The username to query * @param book $isGUID Is the username passed a GUID or a samAccountName * @requires bcmath http://www.php.net/manual/en/book.bc.php @@ -310,11 +334,11 @@ public function passwordExpiry($username, $isGUID = false) { if ($username === NULL) { return "Missing compulsory field [username]"; } if (!$this->adldap->getLdapBind()) { return false; } if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); }; - + $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID); $pwdLastSet = $userInfo[0]['pwdlastset'][0]; $status = array(); - + if ($userInfo[0]['useraccountcontrol'][0] == '66048') { // Password does not expire return "Does not expire"; @@ -323,7 +347,7 @@ public function passwordExpiry($username, $isGUID = false) { // Password has already expired return "Password has expired"; } - + // Password expiry in AD can be calculated from TWO values: // - User's own pwdLastSet attribute: stores the last time the password was changed // - Domain's maxPwdAge attribute: how long passwords last in the domain @@ -336,11 +360,11 @@ public function passwordExpiry($username, $isGUID = false) { } $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr); $maxPwdAge = $info[0]['maxpwdage'][0]; - + // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx // - // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), - // stored in a 64 bit integer. + // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), + // stored in a 64 bit integer. // // The number of seconds between this date and Unix epoch is 11644473600. // @@ -356,21 +380,21 @@ public function passwordExpiry($username, $isGUID = false) { if (bcmod($maxPwdAge, 4294967296) === '0') { return "Domain does not expire passwords"; } - + // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's // time units. Because maxpwd age is negative we need to subtract it. $pwdExpire = bcsub($pwdLastSet, $maxPwdAge); - + // Convert MS's time to Unix time $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'); $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600')); - + return $status; } - + /** * Modify a user - * + * * @param string $username The username to query * @param array $attributes The attributes to modify. Note if you set the enabled attribute you must not specify any other attributes * @param bool $isGUID Is the username passed a GUID or a samAccountName @@ -378,46 +402,54 @@ public function passwordExpiry($username, $isGUID = false) { */ public function modify($username, $attributes, $isGUID = false) { if ($username === NULL) { return "Missing compulsory field [username]"; } - if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { + if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.'); } // Find the dn of the user $userDn = $this->dn($username, $isGUID); - if ($userDn === false) { - return false; + if ($userDn === false) { + return false; } - - // Translate the update to the LDAP schema + + // Translate the update to the LDAP schema $mod = $this->adldap->adldap_schema($attributes); - + // Check to see if this is an enabled status update - if (!$mod && !array_key_exists("enabled", $attributes)) { - return false; + if (!$mod && !array_key_exists("enabled", $attributes)) { + return false; } - + // Set the account control attribute (only if specified) if (array_key_exists("enabled", $attributes)) { - if ($attributes["enabled"]) { - $controlOptions = array("NORMAL_ACCOUNT"); + if ($attributes["enabled"]) { + $controlOptions = array("NORMAL_ACCOUNT"); } - else { - $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); + else { + $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); } $mod["userAccountControl"][0] = $this->accountControl($controlOptions); } + // we can NOT set password with ldap_add or ldap_modify, it needs ldap_mod_replace, at least under Win2008r2 + unset($mod['unicodePwd']); - // Do the update - $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod); - if ($result == false) { - return false; + if ($mod) { + // Do the update + $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod); + if ($result == false) { + return false; + } + } + if (array_key_exists("password",$attributes) && !$this->setPassword($userDn, $attributes['password'])) + { + return false; } return true; } - + /** * Disable a user account - * + * * @param string $username The username to disable * @param bool $isGUID Is the username passed a GUID or a samAccountName * @return bool @@ -427,13 +459,13 @@ public function disable($username, $isGUID = false) { $attributes = array("enabled" => 0); $result = $this->modify($username, $attributes, $isGUID); if ($result == false) { return false; } - + return true; } - + /** * Enable a user account - * + * * @param string $username The username to enable * @param bool $isGUID Is the username passed a GUID or a samAccountName * @return bool @@ -443,36 +475,70 @@ public function enable($username, $isGUID = false) { $attributes = array("enabled" => 1); $result = $this->modify($username, $attributes, $isGUID); if ($result == false) { return false; } - + return true; } - + + /** + * Check if we can to a real password change, not just a password reset + * + * Requires PHP 5.4 >= 5.4.26, PHP 5.5 >= 5.5.10 or PHP 5.6 >= 5.6.0 + * + * @return boolean + */ + public static function changePasswordSupported() + { + return function_exists('ldap_modify_batch'); + } + /** * Set the password of a user - This must be performed over SSL - * + * * @param string $username The username to modify * @param string $password The new password * @param bool $isGUID Is the username passed a GUID or a samAccountName + * @param string $old_password old password for password change, if supported * @return bool */ - public function password($username, $password, $isGUID = false) { + public function password($username, $password, $isGUID = false, $old_password=null) + { if ($username === NULL) { return false; } if ($password === NULL) { return false; } if (!$this->adldap->getLdapBind()) { return false; } - if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { + if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.'); } - + $userDn = $this->dn($username, $isGUID); - if ($userDn === false) { - return false; + if ($userDn === false) { + return false; } - + $add=array(); - $add["unicodePwd"][0] = $this->encodePassword($password); - - $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add); - if ($result === false) { + + if (empty($old_password) || !self::changePasswordSupported()) + { + $add["unicodePwd"][0] = $this->encodePassword($password); + + $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add); + } + else + { + $mods = array( + array( + "attrib" => "unicodePwd", + "modtype" => LDAP_MODIFY_BATCH_REMOVE, + "values" => array($this->encodePassword($old_password)), + ), + array( + "attrib" => "unicodePwd", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => array($this->encodePassword($password)), + ), + ); + $result = ldap_modify_batch($this->adldap->getLdapConnection(), $userDn, $mods); + } + if ($result === false){ $err = ldap_errno($this->adldap->getLdapConnection()); if ($err) { $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.'; @@ -485,42 +551,68 @@ public function password($username, $password, $isGUID = false) { return false; } } + return true; } - + /** * Encode a password for transmission over LDAP * + * Extended to use mbstring to convert from arbitrary charset to UTF-16LE + * * @param string $password The password to encode * @return string */ public function encodePassword($password) { $password="\"".$password."\""; + if (function_exists('mb_convert_encoding')) + { + return mb_convert_encoding($password, 'UTF-16LE', $this->adldap->charset); + } $encoded=""; for ($i=0; $i adldap->getLdapConnection(), $dn, array( + 'unicodePwd' => $this->encodePassword($password), + )); + return $result; + } + /** - * Obtain the user's distinguished name based on their userid - * - * + * Obtain the user's distinguished name based on their userid + * + * * @param string $username The username * @param bool $isGUID Is the username passed a GUID or a samAccountName * @return string */ public function dn($username, $isGUID=false) { $user = $this->info($username, array("cn"), $isGUID); - if ($user[0]["dn"] === NULL) { - return false; + if ($user[0]["dn"] === NULL) { + return false; } $userDn = $user[0]["dn"]; return $userDn; } - + /** * Return a list of all users in AD - * + * * @param bool $includeDescription Return a description of the user * @param string $search Search parameter * @param bool $sorted Sort the user accounts @@ -528,7 +620,7 @@ public function dn($username, $isGUID=false) { */ public function all($includeDescription = false, $search = "*", $sorted = true) { if (!$this->adldap->getLdapBind()) { return false; } - + // Perform the search and grab all their details $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))"; $fields = array("samaccountname","displayname"); @@ -545,34 +637,34 @@ public function all($includeDescription = false, $search = "*", $sorted = true) array_push($usersArray, $entries[$i]["samaccountname"][0]); } } - if ($sorted) { - asort($usersArray); + if ($sorted) { + asort($usersArray); } return $usersArray; } - + /** * Converts a username (samAccountName) to a GUID - * + * * @param string $username The username to query * @return string */ public function usernameToGuid($username) { if (!$this->adldap->getLdapBind()){ return false; } if ($username === null){ return "Missing compulsory field [username]"; } - - $filter = "samaccountname=" . $username; - $fields = array("objectGUID"); - $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); - if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { - $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); - $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); - $strGUID = $this->adldap->utilities()->binaryToText($guid[0]); - return $strGUID; - } - return false; + + $filter = "samaccountname=" . $username; + $fields = array("objectGUID"); + $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); + if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { + $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); + $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); + $strGUID = $this->adldap->utilities()->binaryToText($guid[0]); + return $strGUID; + } + return false; } - + /** * Return a list of all users in AD that have a specific value in a field * @@ -584,12 +676,12 @@ public function usernameToGuid($username) { */ public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true) { if (!$this->adldap->getLdapBind()) { return false; } - + // Perform the search and grab all their details $searchParams = ""; if ($searchField) { $searchParams = "(" . $searchField . "=" . $searchFilter . ")"; - } + } $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")"; $fields = array("samaccountname","displayname"); $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); @@ -607,12 +699,12 @@ public function find($includeDescription = false, $searchField = false, $searchF array_push($usersArray, $entries[$i]["samaccountname"][0]); } } - if ($sorted) { - asort($usersArray); + if ($sorted) { + asort($usersArray); } return ($usersArray); } - + /** * Move a user account to a different OU * @@ -626,7 +718,7 @@ public function move($username, $container) { if ($username === null) { return "Missing compulsory field [username]"; } if ($container === null) { return "Missing compulsory field [container]"; } if (!is_array($container)) { return "Container must be an array"; } - + $userInfo = $this->info($username, array("*")); $dn = $userInfo[0]['distinguishedname'][0]; $newRDn = "cn=" . $username; @@ -639,10 +731,10 @@ public function move($username, $container) { } return true; } - + /** * Get the last logon time of any user as a Unix timestamp - * + * * @param string $username * @return long $unixTimestamp */ diff --git a/src/classes/adLDAPUtils.php b/src/classes/adLDAPUtils.php index de88d1c..8a16bb2 100644 --- a/src/classes/adLDAPUtils.php +++ b/src/classes/adLDAPUtils.php @@ -1,29 +1,29 @@ adldap = $adldap; } - - + + /** * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN) * * @param array $groups * @return array */ - public function niceNames($groups) { + public static function niceNames($groups) { $groupArray = array(); for ($i=0; $i<$groups["count"]; $i++) { // For each group $line = $groups[$i]; - - if (strlen($line)>0) { + + if (strlen($line)>0) { // More presumptions, they're all prefixed with CN= // so we ditch the first three characters and the group // name goes up to the first comma @@ -74,23 +74,23 @@ public function niceNames($groups) { $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3)); } } - return $groupArray; + return $groupArray; } - + /** * Escape characters for use in an ldap_create function - * + * * @param string $str * @return string */ - public function escapeCharacters($str) { + public static function escapeCharacters($str) { $str = str_replace(",", "\,", $str); return $str; } - + /** * Escape strings for the use in LDAP filters - * + * * DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT * Ported from Perl's Net::LDAP::Util escape_filter_value * @@ -99,7 +99,7 @@ public function escapeCharacters($str) { * @author Modified for PHP55 by Esteban Santana Santana * @return string */ - public function ldapSlashes($str) { + public static function ldapSlashes($str) { return preg_replace_callback( '/([\x00-\x1F\*\(\)\\\\])/', function ($matches) { @@ -108,14 +108,14 @@ function ($matches) { $str ); } - + /** * Converts a string GUID to a hexdecimal value so it can be queried - * + * * @param string $strGUID A string representation of a GUID * @return string */ - public function strGuidToHex($strGUID) { + public static function strGuidToHex($strGUID) { $strGUID = str_replace('-', '', $strGUID); $octet_str = '\\' . substr($strGUID, 6, 2); @@ -132,17 +132,17 @@ public function strGuidToHex($strGUID) { $octet_str .= '\\' . substr($strGUID, $i, 2); } } - + return $octet_str; } - + /** * Convert a binary SID to a text SID - * + * * @param string $binsid A Binary SID * @return string */ - public function getTextSID($binsid) { + public static function getTextSID($binsid) { $hex_sid = bin2hex($binsid); $rev = hexdec(substr($hex_sid, 0, 2)); $subcount = hexdec(substr($hex_sid, 2, 2)); @@ -151,17 +151,17 @@ public function getTextSID($binsid) { for ($x=0;$x < $subcount; $x++) { $subauth[$x] = - hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); + hexdec(self::littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); $result .= "-" . $subauth[$x]; } // Cheat by tacking on the S- return 'S-' . $result; } - + /** * Converts a little-endian hex number to one that hexdec() can convert - * + * * @param string $hex A hex code * @return string */ @@ -172,45 +172,45 @@ public function littleEndian($hex) { } return $result; } - + /** * Converts a binary attribute to a string - * + * * @param string $bin A binary LDAP attribute * @return string */ - public function binaryToText($bin) { - $hex_guid = bin2hex($bin); - $hex_guid_to_guid_str = ''; - for($k = 1; $k <= 4; ++$k) { - $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2); - } - $hex_guid_to_guid_str .= '-'; - for($k = 1; $k <= 2; ++$k) { - $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2); - } - $hex_guid_to_guid_str .= '-'; - for($k = 1; $k <= 2; ++$k) { - $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2); - } - $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4); - $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); - return strtoupper($hex_guid_to_guid_str); + public static function binaryToText($bin) { + $hex_guid = bin2hex($bin); + $hex_guid_to_guid_str = ''; + for($k = 1; $k <= 4; ++$k) { + $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2); + } + $hex_guid_to_guid_str .= '-'; + for($k = 1; $k <= 2; ++$k) { + $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2); + } + $hex_guid_to_guid_str .= '-'; + for($k = 1; $k <= 2; ++$k) { + $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2); + } + $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4); + $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); + return strtoupper($hex_guid_to_guid_str); } - + /** * Converts a binary GUID to a string GUID - * + * * @param string $binaryGuid The binary GUID attribute to convert * @return string */ - public function decodeGuid($binaryGuid) { + public static function decodeGuid($binaryGuid) { if ($binaryGuid === null){ return "Missing compulsory field [binaryGuid]"; } - - $strGUID = $this->binaryToText($binaryGuid); - return $strGUID; + + $strGUID = self::binaryToText($binaryGuid); + return $strGUID; } - + /** * Convert a boolean value to a string * You should never need to call this yourself @@ -218,45 +218,45 @@ public function decodeGuid($binaryGuid) { * @param bool $bool Boolean value * @return string */ - public function boolToStr($bool) { + public static function boolToStr($bool) { return ($bool) ? 'TRUE' : 'FALSE'; } - + /** * Convert 8bit characters e.g. accented characters to UTF8 encoded characters */ public function encode8Bit(&$item, $key) { - $encode = false; - if (is_string($item)) { - for ($i=0; $i> 7) { - $encode = true; - } - } - } - if ($encode === true && $key != 'password') { - $item = utf8_encode($item); - } - } - + return $this->adldap->encode8bit($item, $key); + } + /** * Get the current class version number - * + * * @return string */ public function getVersion() { return self::ADLDAP_VERSION; } - + /** * Round a Windows timestamp down to seconds and remove the seconds between 1601-01-01 and 1970-01-01 - * + * * @param long $windowsTime * @return long $unixTime */ public static function convertWindowsTimeToUnixTime($windowsTime) { - $unixTime = round($windowsTime / 10000000) - 11644477200; - return $unixTime; + $unixTime = round($windowsTime / 10000000) - 11644477200; + return $unixTime; + } + + /** + * Add seconds between 1601-01-01 and 1970-01-01 and multiply by 10000000 + * + * @param long $unixTime + * @return long windowsTime + */ + public static function convertUnixTimeToWindowsTime($unixTime) { + return ($unixTime + 11644477200) * 10000000; } }