server_id = $server_id; } /** * Create an instance of the tree - this is used when we call this class directly * Tree::getInstance($index) * * @param $server_id * @return object Tree */ static public function getInstance($server_id) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $tree = get_cached_item($server_id,'tree'); if (! $tree) { $server = $_SESSION[APPCONFIG]->getServer($server_id); if (! $server) return null; $treeclass = $_SESSION[APPCONFIG]->getValue('appearance','tree'); $tree = new $treeclass($server_id); # If we are not logged in, just return the empty tree. if (is_null($server->getLogin(null))) return $tree; foreach ($server->getBaseDN(null) as $base) { if ($base) { $tree->addEntry($base); if ($server->getValue('appearance','open_tree')) { $baseEntry = $tree->getEntry($base); $baseEntry->open(); } } } set_cached_item($server_id,'tree','null',$tree); } return $tree; } /** * Get the Server ID for this tree * * @return int Server ID that this tree is for */ protected function getServerID() { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->server_id); return $this->server_id; } /** * Get the server Object for this tree * * @return object Server Object for this tree */ protected function getServer() { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); return $_SESSION[APPCONFIG]->getServer($this->server_id); } /** * Get the entries that are BaseDN entries. * * @return array Base DN entries */ public function getBaseEntries() { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $return = array(); foreach ($this->entries as $details) if ($details->isBaseDN() AND ((! $this->getServer()->getValue('server','hide_noaccess_base')) OR $details->isInLdap())) array_push($return,$details); return $return; } /** * This function will take the DN, convert it to lowercase and strip unnessary * commas. This result will be used as the index for the tree object. * Any display of a DN should use the object->dn entry, not the index. * The reason we need to do this is because: * uid=User A,ou=People,c=AU and * uid=User B, ou=PeOpLe, c=au * are infact in the same branch, but PLA will show them inconsistently. * * @param dn DN to clean * @return dn Lowercase clean DN */ private function indexDN($dn) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $index = strtolower(implode(',',pla_explode_dn($dn))); if (DEBUG_ENABLED) debug_log('Result (%s)',1,0,__FILE__,__LINE__,__METHOD__,$index); return $index; } /** * Get a tree entry * * @param dn DN to retrieve * @return object Tree DN object */ public function getEntry($dn) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $dnlower = $this->indexDN($dn); if (isset($this->entries[$dnlower])) return $this->entries[$dnlower]; else return null; } /** * Add an entry in the tree view ; the entry is added in the * children array of its parent * * @param string $dn the dn of the entry to create */ public function addEntry($dn) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $server = $this->getServer(); $dnlower = $this->indexDN($dn); # @todo Temporarily removed, some non-ascii char DNs that do exist, fail here for some reason? #if (! ($server->dnExists($dn))) # return; if (isset($this->entries[$dnlower])) debug_dump_backtrace('Calling add entry to an entry that ALREADY exists?',1); if (DEBUG_ENABLED) debug_log('New ENTRY (%s).',64,0,__FILE__,__LINE__,__METHOD__,$dn); $tree_factory = new TreeItem($server->getIndex(),$dn); $tree_factory->setObjectClasses($server->getDNAttrValue($dn,'objectClass')); if ((($isleaf = $server->getDNAttrValue($dn,'hassubordinates')) && ! strcasecmp($isleaf[0],'false'))) $tree_factory->setLeaf(); $this->entries[$dnlower] = $tree_factory; # Is this entry in a base entry? if (in_array_ignore_case($dn,$server->getBaseDN(null))) { $this->entries[$dnlower]->setBase(); # If the parent entry is not in the tree, we add it. This routine will in itself # recall this method until we get to the top of the tree (the base). } else { $parent_dn = $server->getContainer($dn); if (DEBUG_ENABLED) debug_log('Parent DNs (%s)',64,0,__FILE__,__LINE__,__METHOD__,$parent_dn); if ($parent_dn) { $parent_entry = $this->getEntry($parent_dn); if (! $parent_entry) { $this->addEntry($parent_dn); $parent_entry = $this->getEntry($parent_dn); } # Update this DN's parent's children list as well. $parent_entry->addChild($dn); } } } /** * Delete an entry from the tree view ; the entry is deleted from the * children array of its parent * * @param dn DN to remote */ public function delEntry($dn) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $server = $this->getServer(); $dnlower = $this->indexDN($dn); if (isset($this->entries[$dnlower])) unset($this->entries[$dnlower]); # Delete entry from parent's children as well. $parent_dn = $server->getContainer($dn); $parent_entry = $this->getEntry($parent_dn); if ($parent_entry) $parent_entry->delChild($dn); } /** * Rename an entry in the tree * * @param dn Old DN * @param dn New DN */ public function renameEntry($dnOLD,$dnNEW) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $server = $this->getServer(); $dnlowerOLD = $this->indexDN($dnOLD); $dnlowerNEW = $this->indexDN($dnNEW); $this->entries[$dnlowerNEW] = $this->entries[$dnlowerOLD]; if ($dnlowerOLD != $dnlowerNEW) unset($this->entries[$dnlowerOLD]); $this->entries[$dnlowerNEW]->rename($dnNEW); # Update the parent's children $parentNEW = $server->getContainer($dnNEW); $parentOLD = $server->getContainer($dnOLD); $parent_entry = $this->getEntry($parentNEW); if ($parent_entry) $parent_entry->addChild($dnNEW); $parent_entry = $this->getEntry($parentOLD); if ($parent_entry) $parent_entry->delChild($dnOLD); } /** * Read the children of a tree entry * * @param dn DN of the entry * @param boolean LDAP Size Limit */ public function readChildren($dn,$nolimit=false) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $server = $this->getServer(); $dnlower = $this->indexDN($dn); if (! isset($this->entries[$dnlower])) debug_dump_backtrace('Reading children on an entry that isnt set? '.$dnlower,true); $ldap['child_limit'] = $nolimit ? 0 : $_SESSION[APPCONFIG]->getValue('search','size_limit'); $ldap['filter'] = $_SESSION[APPCONFIG]->getValue('appearance','tree_filter'); $ldap['deref'] = $_SESSION[APPCONFIG]->getValue('deref','tree'); # Perform the query to get the children. $ldap['children'] = $server->getContainerContents($dn,null,$ldap['child_limit'],$ldap['filter'],$ldap['deref']); if (! count($ldap['children'])) { $this->entries[$dnlower]->unsetSizeLimited(); return; } if (DEBUG_ENABLED) debug_log('Children of (%s) are (%s)',64,0,__FILE__,__LINE__,__METHOD__,$dn,$ldap['children']); # Relax our execution time, it might take some time to load this if ($nolimit) @set_time_limit($_SESSION[APPCONFIG]->getValue('search','time_limit')); $this->entries[$dnlower]->readingChildren(true); foreach ($ldap['children'] as $child) { if (DEBUG_ENABLED) debug_log('Adding (%s)',64,0,__FILE__,__LINE__,__METHOD__,$child); if (! in_array($child,$this->entries[$dnlower]->getChildren())) $this->entries[$dnlower]->addChild($child); } $this->entries[$dnlower]->readingChildren(false); if (count($this->entries[$dnlower]->getChildren()) == $ldap['child_limit']) $this->entries[$dnlower]->setSizeLimited(); else $this->entries[$dnlower]->unsetSizeLimited(); } /** * Return the number of children an entry has. Optionally autoread the child entry. * * @param dn DN of the entry * @param boolean LDAP Size Limit */ protected function readChildrenNumber($dn,$nolimit=false) { if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) debug_log('Entered (%%)',33,0,__FILE__,__LINE__,__METHOD__,$fargs); $dnlower = $this->indexDN($dn); if (! isset($this->entries[$dnlower])) debug_dump_backtrace('Reading children on an entry that isnt set?',true); # Read the entry if we havent got it yet. if (! $this->entries[$dnlower]->isLeaf() && ! $this->entries[$dnlower]->getChildren()) $this->readChildren($dn,$nolimit); return count($this->entries[$dnlower]->getChildren()); } }