/** * Write the entry or entries to the LDIF file. * * If you want to build an LDIF file containing several entries AND * you want to call write_entry() several times, you must open the filehandle * in append mode ("a"), otherwise you will always get the last entry only. * * @param Net_LDAP_Entry|array $entries Entry or array of entries * * @return void * @todo implement operations on whole entries (adding a whole entry) */ function write_entry($entries) { if (!is_array($entries)) { $entries = array($entries); } foreach ($entries as $entry) { $this->_entrynum++; if (!is_a($entry, 'Net_LDAP_Entry')) { $this->_dropError('Net_LDAP_LDIF error: entry ' . $this->_entrynum . ' is not an Net_LDAP_Entry object'); } else { if ($this->_options['change']) { // LDIF change mode // fetch change information from entry $entry_attrs_changes = $entry->getChanges(); $num_of_changes = count($entry_attrs_changes['add']) + count($entry_attrs_changes['replace']) + count($entry_attrs_changes['delete']); $is_changed = $num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved(); // write version if not done yet // also write DN of entry if ($is_changed) { if (!$this->_version_written) { $this->write_version(); } $this->_writeDN($entry->currentDN()); } // process changes // TODO: consider DN add! if ($entry->willBeDeleted()) { $this->_writeLine("changetype: delete" . PHP_EOL); } elseif ($entry->willBeMoved()) { $this->_writeLine("changetype: modrdn" . PHP_EOL); $olddn = Net_LDAP_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs $oldrdn = array_shift($olddn); $oldparent = implode(',', $olddn); $newdn = Net_LDAP_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs $rdn = array_shift($newdn); $parent = implode(',', $newdn); $this->_writeLine("newrdn: " . $rdn . PHP_EOL); $this->_writeLine("deleteoldrdn: 1" . PHP_EOL); if ($parent !== $oldparent) { $this->_writeLine("newsuperior: " . $parent . PHP_EOL); } // TODO: What if the entry has attribute changes as well? // I think we should check for that and make a dummy // entry with the changes that is written to the LDIF file } elseif ($num_of_changes > 0) { // write attribute change data $this->_writeLine("changetype: modify" . PHP_EOL); foreach ($entry_attrs_changes as $changetype => $entry_attrs) { foreach ($entry_attrs as $attr_name => $attr_values) { $this->_writeLine("{$changetype}: {$attr_name}" . PHP_EOL); if ($attr_values !== null) { $this->_writeAttribute($attr_name, $attr_values, $changetype); } $this->_writeLine("-" . PHP_EOL); } } } // finish this entrys data if we had changes if ($is_changed) { $this->_finishEntry(); } } else { // LDIF-content mode // fetch attributes for further processing $entry_attrs = $entry->getValues(); // sort and put objectclass-attrs to first position if ($this->_options['sort']) { ksort($entry_attrs); if (array_key_exists('objectclass', $entry_attrs)) { $oc = $entry_attrs['objectclass']; unset($entry_attrs['objectclass']); $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs); } } // write data if (!$this->_version_written) { $this->write_version(); } $this->_writeDN($entry->dn()); foreach ($entry_attrs as $attr_name => $attr_values) { $this->_writeAttribute($attr_name, $attr_values); } $this->_finishEntry(); } } } }
/** * Tell if a DN does exist in the directory * * @param string $dn The DN of the object to test * * @return boolean|Net_LDAP_Error */ function dnExists($dn) { if (!is_string($dn)) { return PEAR::raiseError('$dn is expected to be a string but is ' . gettype($dn) . ' ' . get_class($dn)); } // make dn relative to parent $base = Net_LDAP_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (Net_LDAP::isError($base)) { return $base; } $entry_rdn = array_shift($base); if (is_array($entry_rdn)) { // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $entry_rdn is an array! $filter_dn = Net_LDAP_Util::canonical_dn($entry_rdn); } $base = Net_LDAP_Util::canonical_dn($base); $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); if (@ldap_count_entries($this->_link, $result)) { return true; } if (ldap_errno($this->_link) == 32) { return false; } if (ldap_errno($this->_link) != 0) { return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); } return false; }
/** * Update the entry on the directory server * * @access public * @param Net_LDAP $ldap (optional) If you provide a Net_LDAP object, be sure to PASS IT VIA REFERENCE! * @return true|Net_LDAP_Error * @todo Entry rename with a DN containing special characters needs testing! */ function update($ldap = false) { if (!$ldap) { // If object is not provided, then use this entrys ldap object $ldap =& $this->_ldap; } else { if (!is_a($ldap, 'Net_LDAP')) { $ldap = false; // throw error } else { // store the provided ldap object internally, if we haven't got one already if (!$this->_ldap) { $this->_ldap =& $ldap; } } } // ensure we have a valid LDAP object if (!is_a($ldap, 'Net_LDAP')) { return PEAR::raiseError("Need a Net_LDAP object as parameter"); } $link = $ldap->getLink(); /* * Delete the entry */ if (true === $this->_delete) { return $ldap->delete($this); } /* * New entry */ if (true === $this->_new) { $msg = $ldap->add($this); if (Net_LDAP::isError($msg)) { return $msg; } $this->_new = false; $this->_changes['add'] = array(); $this->_changes['delete'] = array(); $this->_changes['replace'] = array(); $this->_original = $this->_attributes; $return = true; return $return; } /* * Rename/move entry */ if (false == is_null($this->_newdn)) { if ($ldap->getLDAPVersion() !== 3) { return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); } // make dn relative to parent (needed for ldap rename) $parent = Net_LDAP_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (Net_LDAP::isError($parent)) { return $parent; } $child = array_shift($parent); // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $child-RDN is an array! if (is_array($child)) { $child = Net_LDAP_Util::canonical_dn($child); } $parent = Net_LDAP_Util::canonical_dn($parent); // rename if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) { return PEAR::raiseError("Entry not renamed: " . @ldap_error($link), @ldap_errno($link)); } // reflect changes to local copy $this->_dn = $this->_newdn; $this->_newdn = null; } /* * Carry out modifications to the entry */ // ADD foreach ($this->_changes["add"] as $attr => $value) { // if attribute exists, add new values if ($this->exists($attr)) { if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not add new values to attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } } else { // new attribute if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not add new attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } } // all went well here, I guess unset($this->_changes["add"][$attr]); } // DELETE foreach ($this->_changes["delete"] as $attr => $value) { // In LDAPv3 you need to specify the old values for deleting if (is_null($value) && $ldap->getLDAPVersion() === 3) { $value = $this->_original[$attr]; } if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not delete attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } unset($this->_changes["delete"][$attr]); } // REPLACE foreach ($this->_changes["replace"] as $attr => $value) { if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not replace attribute {$attr} values: " . @ldap_error($link), @ldap_errno($link)); } unset($this->_changes["replace"][$attr]); } // all went well, so _original (server) becomes _attributes (local copy) $this->_original = $this->_attributes; $return = true; return $return; }
/** * Tell if a dn already exists * * @param string $dn The DN of the object to test * @return boolean */ function dnExists($dn) { // make dn relative to parent $base = Net_LDAP_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (Net_LDAP::isError($base)) { return $base; } $filter = array_shift($base); // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $child-RDN is an array! if (is_array($filter)) { $filter = Net_LDAP_Util::canonical_dn($filter); } $base = Net_LDAP_Util::canonical_dn($base); $result = @ldap_list($this->_link, $base, $filter, array(), 1, 1); if (ldap_errno($this->_link) == 32) { $return = false; return $return; } if (ldap_errno($this->_link) != 0) { PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); } if (@ldap_count_entries($this->_link, $result)) { $return = true; return $return; } $return = false; return $return; }