public function groupMembersResursive($current_member_entries, &$all_member_dns, &$tested_group_ids, $level, $max_levels, $object_classes = FALSE) {

    if (!$this->groupGroupEntryMembershipsConfigured || !is_array($current_member_entries) || count($current_member_entries) == 0) {
      return FALSE;
    }
    if (isset($current_member_entries['count'])) {
      unset($current_member_entries['count']);
    };

    foreach ($current_member_entries as $i => $member_entry) {
      //dpm("groupMembersResursive:member_entry $i, level=$level < max_levels=$max_levels"); dpm($member_entry);
      // 1.  Add entry itself if of the correct type to $all_member_dns
      $objectClassMatch = (!$object_classes || (count(array_intersect(array_values($member_entry['objectclass']), $object_classes)) > 0));
      $objectIsGroup = in_array($this->groupObjectClass, array_values($member_entry['objectclass']));
      if ($objectClassMatch && !in_array($member_entry['dn'], $all_member_dns)) { // add member
        $all_member_dns[] = $member_entry['dn'];
      }

      // 2. If its a group, keep recurse the group for descendants
      if ($objectIsGroup && $level < $max_levels) {
        if ($this->groupMembershipsAttrMatchingUserAttr == 'dn') {
          $group_id = $member_entry['dn'];
        }
        else {
          $group_id = $member_entry[$this->groupMembershipsAttrMatchingUserAttr][0];
        }
        // 3. skip any groups that have already been tested
        if (!in_array($group_id, $tested_group_ids)) {
          $tested_group_ids[] = $group_id;
          $member_ids = $member_entry[$this->groupMembershipsAttr];
          if (isset($member_ids['count'])) {
            unset($member_ids['count']);
          };
          $ors = array();
          foreach ($member_ids as $i => $member_id) {
            $ors[] =  $this->groupMembershipsAttr . '=' . ldap_pear_escape_filter_value($member_id); // @todo this would be replaced by query template
          }

          if (count($ors)) {
            $query_for_child_members = '(|(' . join(")(", $ors) . '))';  // e.g. (|(cn=group1)(cn=group2)) or   (|(dn=cn=group1,ou=blah...)(dn=cn=group2,ou=blah...))
            if (count($object_classes)) { // add or on object classe, otherwise get all object classes
              $object_classes_ors = array('(objectClass=' . $this->groupObjectClass . ')');
              foreach ($object_classes as $object_class) {
                $object_classes_ors[] = '(objectClass=' . $object_class . ')';
              }
              $query_for_child_members = '&(|' . join($object_classes_ors) . ')(' . $query_for_child_members . ')';
            }
            foreach ($this->basedn as $base_dn) {  // need to search on all basedns one at a time
              $child_member_entries = $this->search($base_dn, $query_for_child_members, array('objectclass', $this->groupMembershipsAttr, $this->groupMembershipsAttrMatchingUserAttr));
              if ($child_member_entries !== FALSE) {
                $this->groupMembersResursive($child_member_entries, $all_member_dns, $tested_group_ids, $level + 1, $max_levels, $object_classes);
              }
            }
          }
        }
      }
    }
  }
public function groupMembersResursive($current_member_entries, &$all_member_dns, &$tested_group_ids, $level, $max_levels, $object_classes = FALSE) {

    if (!$this->groupGroupEntryMembershipsConfigured || !is_array($current_member_entries) || count($current_member_entries) == 0) {
      return FALSE;
    }
    if (isset($current_member_entries['count'])) {
      unset($current_member_entries['count']);
    };

    foreach ($current_member_entries as $i => $member_entry) {
      //dpm("groupMembersResursive:member_entry $i, level=$level < max_levels=$max_levels"); dpm($member_entry);
      // 1.  Add entry itself if of the correct type to $all_member_dns
      $objectClassMatch = (!$object_classes || (count(array_intersect(array_values($member_entry['objectclass']), $object_classes)) > 0));
      $objectIsGroup = in_array($this->groupObjectClass, array_values($member_entry['objectclass']));
      if ($objectClassMatch && !in_array($member_entry['dn'], $all_member_dns)) { // add member
        $all_member_dns[] = $member_entry['dn'];
      }

      // 2. If its a group, keep recurse the group for descendants
      if ($objectIsGroup && $level < $max_levels) {
        if ($this->groupMembershipsAttrMatchingUserAttr == 'dn') {
          $group_id = $member_entry['dn'];
        }
        else {
          $group_id = $member_entry[$this->groupMembershipsAttrMatchingUserAttr][0];
        }
        // 3. skip any groups that have already been tested
        if (!in_array($group_id, $tested_group_ids)) {
          $tested_group_ids[] = $group_id;
          $member_ids = $member_entry[$this->groupMembershipsAttr];
          if (isset($member_ids['count'])) {
            unset($member_ids['count']);
          };
          $ors = array();
          foreach ($member_ids as $i => $member_id) {
            $ors[] =  $this->groupMembershipsAttr . '=' . ldap_pear_escape_filter_value($member_id); // @todo this would be replaced by query template
          }

          if (count($ors)) {
            $query_for_child_members = '(|(' . join(")(", $ors) . '))';  // e.g. (|(cn=group1)(cn=group2)) or   (|(dn=cn=group1,ou=blah...)(dn=cn=group2,ou=blah...))
            if (count($object_classes)) { // add or on object classe, otherwise get all object classes
              $object_classes_ors = array('(objectClass=' . $this->groupObjectClass . ')');
              foreach ($object_classes as $object_class) {
                $object_classes_ors[] = '(objectClass=' . $object_class . ')';
              }
              $query_for_child_members = '&(|' . join($object_classes_ors) . ')(' . $query_for_child_members . ')';
            }
            foreach ($this->basedn as $base_dn) {  // need to search on all basedns one at a time
              $child_member_entries = $this->search($base_dn, $query_for_child_members, array('objectclass', $this->groupMembershipsAttr, $this->groupMembershipsAttrMatchingUserAttr));
              if ($child_member_entries !== FALSE) {
                $this->groupMembersResursive($child_member_entries, $all_member_dns, $tested_group_ids, $level + 1, $max_levels, $object_classes);
              }
            }
          }
        }
      }
    }
  }
public function groupMembersResursive ( $ current_member_entries , & $ all_member_dns , & $ tested_group_ids , $ level , $ max_levels , $ object_classes = FALSE ) { if ( ! $ this -> groupGroupEntryMembershipsConfigured || ! is_array ( $ current_member_entries ) || count ( $ current_member_entries ) == 0 ) { return FALSE ; } if ( isset ( $ current_member_entries [ 'count' ] ) ) { unset ( $ current_member_entries [ 'count' ] ) ; } ; foreach ( $ current_member_entries as $ i => $ member_entry ) { //dpm("groupMembersResursive:member_entry $i, level=$level < max_levels=$max_levels"); dpm($member_entry); // 1.  Add entry itself if of the correct type to $all_member_dns $ objectClassMatch = ( ! $ object_classes || ( count ( array_intersect ( array_values ( $ member_entry [ 'objectclass' ] ) , $ object_classes ) ) > 0 ) ) ; $ objectIsGroup = in_array ( $ this -> groupObjectClass , array_values ( $ member_entry [ 'objectclass' ] ) ) ; if ( $ objectClassMatch && ! in_array ( $ member_entry [ 'dn' ] , $ all_member_dns ) ) { // add member $ all_member_dns [ ] = $ member_entry [ 'dn' ] ; } // 2. If its a group, keep recurse the group for descendants if ( $ objectIsGroup && $ level < $ max_levels ) { if ( $ this -> groupMembershipsAttrMatchingUserAttr == 'dn' ) { $ group_id = $ member_entry [ 'dn' ] ; } else { $ group_id = $ member_entry [ $ this -> groupMembershipsAttrMatchingUserAttr ] [ 0 ] ; } // 3. skip any groups that have already been tested if ( ! in_array ( $ group_id , $ tested_group_ids ) ) { $ tested_group_ids [ ] = $ group_id ; $ member_ids = $ member_entry [ $ this -> groupMembershipsAttr ] ; if ( isset ( $ member_ids [ 'count' ] ) ) { unset ( $ member_ids [ 'count' ] ) ; } ; $ ors = array ( ) ; foreach ( $ member_ids as $ i => $ member_id ) { $ ors [ ] = $ this -> groupMembershipsAttr . '=' . ldap_pear_escape_filter_value ( $ member_id ) ; // @todo this would be replaced by query template } if ( count ( $ ors ) ) { $ query_for_child_members = '(|(' . join ( ")(" , $ ors ) . '))' ; // e.g. (|(cn=group1)(cn=group2)) or   (|(dn=cn=group1,ou=blah...)(dn=cn=group2,ou=blah...)) if ( count ( $ object_classes ) ) { // add or on object classe, otherwise get all object classes $ object_classes_ors = array ( '(objectClass=' . $ this -> groupObjectClass . ')' ) ; foreach ( $ object_classes as $ object_class ) { $ object_classes_ors [ ] = '(objectClass=' . $ object_class . ')' ; } $ query_for_child_members = '&(|' . join ( $ object_classes_ors ) . ')(' . $ query_for_child_members . ')' ; } foreach ( $ this -> basedn as $ base_dn ) { // need to search on all basedns one at a time $ child_member_entries = $ this -> search ( $ base_dn , $ query_for_child_members , array ( 'objectclass' , $ this -> groupMembershipsAttr , $ this -> groupMembershipsAttrMatchingUserAttr ) ) ; if ( $ child_member_entries !== FALSE ) { $ this -> groupMembersResursive ( $ child_member_entries , $ all_member_dns , $ tested_group_ids , $ level + 1 , $ max_levels , $ object_classes ) ; } } } } } } }
NOT IMPLEMENTED
recurse through all child groups and add members.

@param array $current_group_entries of ldap group entries that are starting point.  should include at least 1 entry.
@param array $all_group_dns as array of all groups user is a member of.  MIXED CASE VALUES
@param array $tested_group_ids as array of tested group dn, cn, uid, etc.  MIXED CASE VALUES
whether these value are dn, cn, uid, etc depends on what attribute members, uniquemember, memberUid contains
whatever attribute is in $this->$tested_group_ids to avoid redundant recursing
@param int $level of recursion
@param int $max_levels as max recursion allowed
NOT IMPLEMENTED recurse through all child groups and add members .