Use PHP and LDAP to list members of an Active Directory group

An improved/updated version of this function was posted on 10/19/2011, get it here

PHP function that gets the members of an Active Directory group, and returns the data as an array.

Input for the function: group name, user name, password

Related Post: PHP login script using LDAP, verify group membership

Share

33 thoughts on “Use PHP and LDAP to list members of an Active Directory group

  1. Forgive my ignorance, I’m pretty ignorant when it comes to PHP. Is there an easy way I can extract attributes as well as names for this? Instead of the results you would normally get, you would get something like this:

    The Manager Group contains:
    Joe Smith – 6165551212 – jsmith@globocorp.com
    Jane Doe – 6195551234 – jdoe@globocorp.com

  2. Abrahem,

    To do this you could:
    1. Query all the members of the group
    2. For each member of the group, query further details
    3. Return the array

    Tweaking the code above, you can do this:

    <?php
    // explode DN into array
    function explode_dn($dn, $with_attributes=0)
    {
        $result = ldap_explode_dn($dn, $with_attributes);
        //translate hex code into ascii again
        foreach($result as $key => $value) $result[$key] = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $value);
        return $result;
    }
    
    // get members list from AD
    function get_members($group,$user,$password) {
    
    	// Active Directory server
    	$ldap_host = "server.college.school.edu";
    
    	// Active Directory DN
    	$ldap_dn = "OU=Departments,DC=college,DC=school,DC=edu";
    
    	// Domain, for purposes of constructing $user
    	$ldap_usr_dom = "@college.school.edu";
    
    	// connect and search ldap
    	$ldap = ldap_connect($ldap_host);
    	@ldap_bind($ldap, $user . $ldap_usr_dom, $password);
    	$results = ldap_search($ldap,$ldap_dn, "cn=" . $group);
    	$member_list = ldap_get_entries($ldap, $results);
    
    	// establish variables
    	$dirty = 0;
    	$group_member_details = array();
    
    	// build array of members for this group, first item is count - skipped using $dirty
    	foreach($member_list[0]['member'] as $member) {
    		if($dirty == 0) {
    			$dirty = 1;
    		} else {
    			// get member's CN from the result
    			$member_dn = explode_dn($member);
    			$member_cn = str_replace("CN=","",$member_dn[0]);
    
    			// query individual member for all of their details, filtering on CN
    			$member_search = ldap_search($ldap, $ldap_dn, "(CN=" . $member_cn . ")");
    			$member_details = ldap_get_entries($ldap, $member_search);
    
    			$group_member_details[] = array($member_details[0]['sn'][0],$member_details[0]['mail'][0]);
    		}
    	}
    
    	ldap_close($ldap);
    
    	return $group_member_details;
    
    } ?>
    
    The Manager Group contains:<br />
    <?php $result = get_members("group name","user name","password");
    
    foreach($result as $e) {
    	echo $e[0] . " - " . $e[1] . "<br />";
    } ?>
    

    Ideally though, you should consider using a PHP LDAP Class for doing more advanced AD queries
    http://www.google.com/search?hl=&q=php+ldap+class

  3. Thanks for this function. I’m having a slight problem with the function in response #5 though.

    When I run it against a group in my AD it returns an array with all the members but it’s empty. Like this:

    Array ( [0] => Array ( [0] => [1] => ) [1] => Array ( [0] => [1] => ) [2] => Array ( [0] => [1] => ) [3] => Array ( [0] => [1] => ) [4] => Array ( [0] => [1] => ) [5] => Array ( [0] => [1] => )

    I have no idea why or how to fix it.

  4. Brig, try print_r($member_list); at line 28 and verify that your first part of the function is working correctly and that the member names are returned

    See if the first array value [0] of $member_list is an array of all the members, if this output is different the following foreach loop (line 34) wont work correctly

    Afterwards, try a print_r($member_details); in that foreach loop to make sure the second ldap query is working – around line 45

    That might give you insight as to where the problem lies

  5. Hi Sam, thanks a lot for you reply.

    I just tried your suggestions. If I put print_r($member_list); at line 28 I get the following:

    Array ( [count] => 1 [0] => Array ( [objectclass] => Array ( [count] => 2 [0] => top [1] => group ) [0] => objectclass [cn] => Array ( [count] => 1 [0] => IM-All_Users ) [1] => cn [member] => Array ( [count] => 543 [0] => CN=Jocasta Anderson,OU=Users,OU=Company,OU=London,OU=UK,DC=domain,DC=pri [1] => CN=Ian Worrad,OU=Users,OU=Company,OU=London,OU=UK,DC=domain,DC=pri [2] => CN=Beatrix Borsos,OU=Users,OU=Dusseldorf,OU=GERMANY,DC=domain,DC=pri [3] => CN=Max Ali,OU=Users,OU=Company,OU=London,OU=UK,DC=domain,DC=pri [4] => CN=Lauren Mortimer,OU=Users,OU=Company,OU=London,OU=UK,DC=domain,DC=pri [5] => CN=Michelle Brown,OU=Users,OU=Contracts Admin,OU=IT,OU=London,OU=UK,DC=domain,DC=pri [6] => CN=Louise McAleer,OU=Users,OU=Company,OU=London,OU=UK,DC=domain,DC=pri……..

    So I get all the users in thr group I’m looking for.

    When I try print_r($member_details); at line 45 I get the following:

    Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 ) Array ( [count] => 0 )…….

    Not sure why it doesn’t pick up the details when I can return all the members.

    I really appreciate your help!

  6. Worked it out. The problem is that our users in AD are not all located in a single OU.

    When I change

    $member_search = ldap_search($ldap, $ldap_dn, “(CN=” . $member_cn . “)”);

    on line 43 to

    $member_search = ldap_search($ldap, $base_dn, “(CN=” . $member_cn . “)”);

    Where $base_dn is the path to one of my user OU’s it starts to work.

    Just have to figure out how to query all the OU’s now. If it’s at all possible, I’m not sure yet.

    Thanks a lot for this function Sam and your help!

  7. Brig,

    Ah yes that’s right
    If the OU is different from the group’s OU then the inner ldap query needs to have a different base_dn
    Because it’s not that way for my environment, I wasn’t thinking of that situation

    To query all the members that could be in multiple OU’s, try leaving it blank (just doing the DC’s) or just putting the outer-most OU (provided that there is one)

    • Thanks Brig,

      I will also post it here

      <?php
      
      function explode_dn($dn, $with_attributes=0)
      {
          $result = ldap_explode_dn($dn, $with_attributes);
          foreach($result as $key => $value) $result[$key] = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $value);
          return $result;
      }
      
      function get_members($group,$user,$password) {
      	$ldap_host = "LDAPSERVER";
      	$ldap_dn = "OU=some_group,OU=some_group,DC=company,DC=com";
      	$base_dn = "DC=company,DC=com";
      	$ldap_usr_dom = "@company.com";
      	$ldap = ldap_connect($ldap_host);
      
      	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION,3);
      	ldap_set_option($ldap, LDAP_OPT_REFERRALS,0);
      
      	ldap_bind($ldap, $user . $ldap_usr_dom, $password);
      	$results = ldap_search($ldap,$ldap_dn, "cn=" . $group);
      	$member_list = ldap_get_entries($ldap, $results);
      
      	$dirty = 0;
      	$group_member_details = array();
      
      	foreach($member_list[0]['member'] as $member) {
      		if($dirty == 0) {
      			$dirty = 1;
      		} else {
      			$member_dn = explode_dn($member);
      			$member_cn = str_replace("CN=","",$member_dn[0]);
      			$member_search = ldap_search($ldap, $base_dn, "(CN=" . $member_cn . ")");
      			$member_details = ldap_get_entries($ldap, $member_search);
      			$group_member_details[] = array($member_details[0]['givenname'][0],$member_details[0]['sn'][0],$member_details[0]['telephonenumber'][0],$member_details[0]['othertelephone'][0]);
      		}
      	}
      	ldap_close($ldap);
      	return $group_member_details;
      }
      
      // Specify the group from where to get members and a username and password with rights to query it
      $result = get_members("groupname","username","password");
      
      $xml = simplexml_load_string("<?xml version='1.0'?>\n<AddressBook></AddressBook>");
      $version = $xml->addChild('version', '1');
      
      foreach($result as $e) {
      	$contact = $xml->addChild('Contact');
      	$contact->addChild('FirstName', $e[0]);
      	$contact->addChild('LastName', $e[1]);
      	$phone = $contact->addChild('Phone');
      	if ($e[3] == '') {
                      $phone->addChild('phonenumber', '0');
              } else {
                      $phone->addChild('phonenumber', $e[3]);
              }
      	$phone->addChild('accountindex', '0');
      	$phone = $contact->addChild('Phone');
      	if ($e[2] == '') {
      		$phone->addChild('phonenumber', '0');
      	} else {
      		$phone->addChild('phonenumber', $e[2]);
      	}
      	$phone->addChild('accountindex', '1');
      	$contact->addChild('Group', '0');
      	$contact->addChild('PhotoUrl', 'empty');
      }
      
      $xml->asXML('phonebook.xml');
      
      ?>
    • You just need to change the LDAP search string

      In the original example it’s:

      $results = ldap_search($ldap,$ldap_dn, "cn=" . $group);

      You would change this to something like:

      $results = ldap_search($ldap,$ldap_dn, "ou=" . $group);

      You could also provide the $ldap_dn to the OU that you want, and put in a * for your search string to return everything in that OU, like this:

      $results = ldap_search($ldap,$ldap_dn, "cn=*");
      • I tried your suggestion.
        $results = ldap_search($ldap,$ldap_dn, “ou=” . $group); not working but when I use the $results = ldap_search($ldap,$ldap_dn, “cn=*”); works and I see the outputs through print_r($member_list); But there is a problem.
        member in line 34 is an attribut of the group object. The OU dosen’t have this. So second ldap query is empty print_r($member_details); dosen’t show anything.

        • Hans,

          If you want to get everyone in a CN like ‘Users’, you can simplify things a bit:

          < ?php
          // Active Directory server
          $ldap_host = "ad.host";
          
          // Active Directory DN
          $ldap_dn = "CN=Users,DC=ad,DC=host";
          
          // Domain, for purposes of constructing $user
          $ldap_usr_dom = "@ad.host";
          
          // AD user
          $user = "test";
          $password = "password1234!";
          
          // connect and search ldap
          $ldap = ldap_connect($ldap_host) or die("Could not connect to LDAP");
          @ldap_bind($ldap, $user . $ldap_usr_dom, $password) or die("Could not bind to LDAP");
          $results = ldap_search($ldap,$ldap_dn, "(&(objectClass=user))");
          $entries = ldap_get_entries($ldap, $results);
          
          $i = 0;
          foreach($entries as $u) {
          	if($i != 0) echo $u['samaccountname'][0] . "";
          	$i++;
          }
          ?>
          
    • Hans,

      I haven’t tested this but you should be able to put:

      ldap_sort($ldap, $results, 'cn');

      Between lines 26 and 27, so it looks like:

      $results = ldap_search($ldap,$ldap_dn, "cn=" . $group);
      ldap_sort($ldap, $results, 'cn');
      $entries = ldap_get_entries($ldap, $results);

      Where ‘cn’ is the parameter you want to sort by.

      You could also use PHP functions to sort the output array, see http://www.php.net/manual/en/array.sorting.php for options

  8. Sam thanks for your suggestions and help. I put sort($group_member_details); between lines Line 46 and 47 and the output array was sorted.

  9. The first code works for me if I put a Group name it returns the users in the group. However, I need the last code that you have that gets everyone in a OU like ‘TestUsers’. However, that last code just doesnt seem to work. It does not return anything.

    Any ideas why?

    • See if you are getting any errors:
      Make sure error_reporting and display_errors is enabled for your PHP installation
      Remove the @ in front of the ldap_bind on line 17

      Also verify that your $ldap_dn variable is correctly formed

      • I am not getting any errors at all. error_reporting is enabled for my PHP installation

        I tried removing the @ in front of the ldap_bind on line 17 also no luck.

        The $ldap_dn variable is definately correctly formed because its the same one I use for your main code and that works fine. And if I change the password for the account specified, i get a message saying cannot bind. So it definately binds correctly. It Just does not output anything.

        • Ahmed,

          I have tested the code again with my AD installation

          I was able to query members of an OU (as well as an OU inside of an OU) with no issues
          Using, for example, $ldap_dn = “OU=TestUsers,DC=ad,DC=myserver”;

          Verify that your DN is the correct path to the OU you are trying to query

          How complex is your OU structure?

  10. Thanks for your reply Sam. It now works great :)

    You are correct the issue was with the DN. I used the example you just gave and modified it and it worked. Thanks.

  11. Hi sam, can you help me?

    I cannot retrieve records.

    Results:
    
    Array
    (
        [count] => 1
        [0] => Array
            (
                [objectclass] => Array
                    (
                        [count] => 2
                        [0] => top
                        [1] => container
                    )
    
                [0] => objectclass
                [cn] => Array
                    (
                        [count] => 1
                        [0] => Users
                    )
    
                [1] => cn
                [description] => Array
                    (
                        [count] => 1
                        [0] => Default container for upgraded user accounts
                    )
    
                [2] => description
                [distinguishedname] => Array
                    (
                        [count] => 1
                        [0] => CN=Users,DC=sdb,DC=sucden,DC=sp
                    )
    
                [3] => distinguishedname
                [instancetype] => Array
                    (
                        [count] => 1
                        [0] => 4
                    )
    
                [4] => instancetype
                [whencreated] => Array
                    (
                        [count] => 1
                        [0] => 20090921145941.0Z
                    )
    
                [5] => whencreated
                [whenchanged] => Array
                    (
                        [count] => 1
                        [0] => 20090921145941.0Z
                    )
    
                [6] => whenchanged
                [usncreated] => Array
                    (
                        [count] => 1
                        [0] => 4304
                    )
    
                [7] => usncreated
                [usnchanged] => Array
                    (
                        [count] => 1
                        [0] => 4304
                    )
    
                [8] => usnchanged
                [showinadvancedviewonly] => Array
                    (
                        [count] => 1
                        [0] => FALSE
                    )
    
                [9] => showinadvancedviewonly
                [name] => Array
                    (
                        [count] => 1
                        [0] => Users
                    )
    
                [10] => name
                [objectguid] => Array
                    (
                        [count] => 1
                        [0] => ÈÂi%ÇBA«ÌN‚ã­ó5
                    )
    
                [11] => objectguid
                [systemflags] => Array
                    (
                        [count] => 1
                        [0] => -1946157056
                    )
    
                [12] => systemflags
                [objectcategory] => Array
                    (
                        [count] => 1
                        [0] => CN=Container,CN=Schema,CN=Configuration,DC=sdb,DC=sucden,DC=sp
                    )
    
                [13] => objectcategory
                [iscriticalsystemobject] => Array
                    (
                        [count] => 1
                        [0] => TRUE
                    )
    
                [14] => iscriticalsystemobject
                [count] => 15
                [dn] => CN=Users,DC=sdb,DC=sucden,DC=sp
            )
    )
    

    CONFIG:

    $ldap_host = “SERVER”;
    $ldap_dn = “CN=Users,DC=sdb,DC=sucden,DC=sp”;
    $base_dn = “DC=sdb,DC=sucden,DC=sp”;
    $ldap_usr_dom = “@sdb.sucden.sp”;

    Regards.

  12. function get_members($group,$user,$password) {
        $ldap_host = "SERVER";
        $ldap_dn = "CN=Users,DC=sdb,DC=sucden,DC=sp";
        $base_dn = "DC=sdb,DC=sucden,DC=sp";
        $ldap_usr_dom = "@sdb.sucden.sp";
        $ldap = ldap_connect($ldap_host);
    
        ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION,3);
        ldap_set_option($ldap, LDAP_OPT_REFERRALS,0);
    
        ldap_bind($ldap, $user . $ldap_usr_dom, $password);
        $results = ldap_search($ldap,$ldap_dn, "cn=" . $group);
        $member_list = ldap_get_entries($ldap, $results);
    
        $dirty = 0;
        $group_member_details = array();
    
        foreach($member_list[0]['member'] as $member) {
            if($dirty == 0) {
                $dirty = 1;
            } else {
                $member_dn = explode_dn($member);
                $member_cn = str_replace("CN=","",$member_dn[0]);
                $member_search = ldap_search($ldap, $base_dn, "(CN=" . $member_cn . ")");
                $member_details = ldap_get_entries($ldap, $member_search);
                $group_member_details[] = array($member_details[0]['givenname'][0],$member_details[0]['sn'][0],$member_details[0]['telephonenumber'][0],$member_details[0]['othertelephone'][0]);
            }
        }
        ldap_close($ldap);
        return $group_member_details;
    }
    
    // Specify the group from where to get members and a username and password with rights to query it
    $result = get_members("Users","joao","XXXXXX");
    print_r($result);
    
  13. Hi there.
    I am trying to modify your code to return the samaccountname (username) of each user, rather than their canonical name, but not having much luck!

    From what i understand, i think i will have to return the list of members as you already have, and then search LDAP again to match the canonical name to the samaccount name, but maybe there is an easier way ?

    Thanks,

    Dan.

    • You should be able to tweak the LDAP query to get a list of groups

      Try something like (objectcategory=group)(samaccountname=*)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>