From 5e013b2ba7194ffb140123cf354e54721b69e50b Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Thu, 17 Dec 2009 21:58:37 -0500 Subject: [PATCH] Horde-ify Horde_Ldap library. Switch to real exception handling. --- framework/Ldap/lib/Horde/Ldap/Ldap.php | 1438 +++++++++++++++----------------- 1 file changed, 668 insertions(+), 770 deletions(-) diff --git a/framework/Ldap/lib/Horde/Ldap/Ldap.php b/framework/Ldap/lib/Horde/Ldap/Ldap.php index 26f5e7560..38510f97e 100644 --- a/framework/Ldap/lib/Horde/Ldap/Ldap.php +++ b/framework/Ldap/lib/Horde/Ldap/Ldap.php @@ -1,90 +1,76 @@ -* @author Jan Wagner -* @author Del -* @author Benedikt Hallinger -* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ + * File containing the Horde_Ldap interface class. + * + * PHP version 5 + * + * @category Net + * @package Horde_Ldap + * @author Tarjej Huse + * @author Jan Wagner + * @author Del + * @author Benedikt Hallinger + * @author Ben Klang + * @copyright 2009 The Horde Project + * @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger + * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 + */ /** -* Package includes. -*/ -require_once 'PEAR.php'; -require_once 'Net/LDAP2/RootDSE.php'; -require_once 'Net/LDAP2/Schema.php'; -require_once 'Net/LDAP2/Entry.php'; -require_once 'Net/LDAP2/Search.php'; -require_once 'Net/LDAP2/Util.php'; -require_once 'Net/LDAP2/Filter.php'; -require_once 'Net/LDAP2/LDIF.php'; -require_once 'Net/LDAP2/SchemaCache.interface.php'; -require_once 'Net/LDAP2/SimpleFileSchemaCache.php'; - -/** -* Error constants for errors that are not LDAP errors. -*/ -define('NET_LDAP2_ERROR', 1000); + * Package includes. + */ +#require_once 'Net/Ldap/RootDSE.php'; +#require_once 'Net/Ldap/Schema.php'; +#require_once 'Net/Ldap/Entry.php'; +#require_once 'Net/Ldap/Search.php'; +#require_once 'Net/Ldap/Util.php'; +#require_once 'Net/Ldap/Filter.php'; +#require_once 'Net/Ldap/LDIF.php'; +#require_once 'Net/Ldap/SchemaCache.interface.php'; +#require_once 'Net/Ldap/SimpleFileSchemaCache.php'; + +class Horde_Ldap +{ -/** -* Net_LDAP2 Version -*/ -define('NET_LDAP2_VERSION', '2.0.7'); + /** + * Error constants for errors that are not LDAP errors. + */ + const _ERROR = 1000; + + /** + * Library Version + */ + const VERSION = '0.1.0'; -/** -* Net_LDAP2 - manipulate LDAP servers the right way! -* -* @category Net -* @package Net_LDAP2 -* @author Tarjej Huse -* @author Jan Wagner -* @author Del -* @author Benedikt Hallinger -* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP2/ -*/ -class Net_LDAP2 extends PEAR -{ /** - * Class configuration array - * - * host = the ldap host to connect to - * (may be an array of several hosts to try) - * port = the server port - * version = ldap version (defaults to v 3) - * starttls = when set, ldap_start_tls() is run after connecting. - * bindpw = no explanation needed - * binddn = the DN to bind as. - * basedn = ldap base - * options = hash of ldap options to set (opt => val) - * filter = default search filter - * scope = default search scope - * - * Newly added in 2.0.0RC4, for auto-reconnect: - * auto_reconnect = if set to true then the class will automatically - * attempt to reconnect to the LDAP server in certain - * failure conditionswhen attempting a search, or other - * LDAP operation. Defaults to false. Note that if you - * set this to true, calls to search() may block - * indefinitely if there is a catastrophic server failure. - * min_backoff = minimum reconnection delay period (in seconds). - * current_backoff = initial reconnection delay period (in seconds). - * max_backoff = maximum reconnection delay period (in seconds). - * - * @access protected - * @var array - */ + * Class configuration array + * + * host = the ldap host to connect to + * (may be an array of several hosts to try) + * port = the server port + * version = ldap version (defaults to v 3) + * starttls = when set, ldap_start_tls() is run after connecting. + * bindpw = no explanation needed + * binddn = the DN to bind as. + * basedn = ldap base + * options = hash of ldap options to set (opt => val) + * filter = default search filter + * scope = default search scope + * + * Newly added in 2.0.0RC4, for auto-reconnect: + * auto_reconnect = if set to true then the class will automatically + * attempt to reconnect to the LDAP server in certain + * failure conditionswhen attempting a search, or other + * LDAP operation. Defaults to false. Note that if you + * set this to true, calls to search() may block + * indefinitely if there is a catastrophic server failure. + * min_backoff = minimum reconnection delay period (in seconds). + * current_backoff = initial reconnection delay period (in seconds). + * max_backoff = maximum reconnection delay period (in seconds). + * + * @access protected + * @var array + */ protected $_config = array('host' => 'localhost', 'port' => 389, 'version' => 3, @@ -101,146 +87,140 @@ class Net_LDAP2 extends PEAR 'max_backoff' => 32); /** - * List of hosts we try to establish a connection to - * - * @access protected - * @var array - */ + * List of hosts we try to establish a connection to + * + * @access protected + * @var array + */ protected $_host_list = array(); /** - * List of hosts that are known to be down. - * - * @access protected - * @var array - */ + * List of hosts that are known to be down. + * + * @access protected + * @var array + */ protected $_down_host_list = array(); /** - * LDAP resource link. - * - * @access protected - * @var resource - */ + * LDAP resource link. + * + * @access protected + * @var resource + */ protected $_link = false; /** - * Net_LDAP2_Schema object - * - * This gets set and returned by {@link schema()} - * - * @access protected - * @var object Net_LDAP2_Schema - */ + * Horde_Ldap_Schema object + * + * This gets set and returned by {@link schema()} + * + * @access protected + * @var object Horde_Ldap_Schema + */ protected $_schema = null; /** - * Schema cacher function callback - * - * @see registerSchemaCache() - * @var string - */ + * Schema cacher function callback + * + * @see registerSchemaCache() + * @var string + */ protected $_schema_cache = null; /** - * Cache for attribute encoding checks - * - * @access protected - * @var array Hash with attribute names as key and boolean value - * to determine whether they should be utf8 encoded or not. - */ + * Cache for attribute encoding checks + * + * @access protected + * @var array Hash with attribute names as key and boolean value + * to determine whether they should be utf8 encoded or not. + */ protected $_schemaAttrs = array(); /** - * Cache for rootDSE objects - * - * Hash with requested rootDSE attr names as key and rootDSE object as value - * - * Since the RootDSE object itself may request a rootDSE object, - * {@link rootDse()} caches successful requests. - * Internally, Net_LDAP2 needs several lookups to this object, so - * caching increases performance significally. - * - * @access protected - * @var array - */ + * Cache for rootDSE objects + * + * Hash with requested rootDSE attr names as key and rootDSE object as value + * + * Since the RootDSE object itself may request a rootDSE object, + * {@link rootDse()} caches successful requests. + * Internally, Horde_Ldap needs several lookups to this object, so + * caching increases performance significally. + * + * @access protected + * @var array + */ protected $_rootDSE_cache = array(); /** - * Returns the Net_LDAP2 Release version, may be called statically - * - * @static - * @return string Net_LDAP2 version - */ + * Returns the Horde_Ldap Release version, may be called statically + * + * @static + * @return string Horde_Ldap version + */ public static function getVersion() { - return NET_LDAP2_VERSION; + return Horde_Ldap::VERSION; } /** - * Configure Net_LDAP2, connect and bind - * - * Use this method as starting point of using Net_LDAP2 - * to establish a connection to your LDAP server. - * - * Static function that returns either an error object or the new Net_LDAP2 - * object. Something like a factory. Takes a config array with the needed - * parameters. - * - * @param array $config Configuration array - * - * @access public - * @return Net_LDAP2_Error|Net_LDAP2 Net_LDAP2_Error or Net_LDAP2 object - */ + * Configure Horde_Ldap, connect and bind + * + * Use this method as starting point of using Horde_Ldap + * to establish a connection to your LDAP server. + * + * Static function that returns either an error object or the new Horde_Ldap + * object. Something like a factory. Takes a config array with the needed + * parameters. + * + * @param array $config Configuration array + * + * @access public + * @return Horde_Ldap Horde_Ldap object + */ public static function &connect($config = array()) { $ldap_check = self::checkLDAPExtension(); - if (self::iserror($ldap_check)) { - return $ldap_check; - } - @$obj = new Net_LDAP2($config); + $obj = new Horde_Ldap($config); // todo? better errorhandling for setConfig()? // connect and bind with credentials in config - $err = $obj->bind(); - if (self::isError($err)) { - return $err; - } + $obj->bind(); return $obj; } /** - * Net_LDAP2 constructor - * - * Sets the config array - * - * Please note that the usual way of getting Net_LDAP2 to work is - * to call something like: - * $ldap = Net_LDAP2::connect($ldap_config); - * - * @param array $config Configuration array - * - * @access protected - * @return void - * @see $_config - */ + * Horde_Ldap constructor + * + * Sets the config array + * + * Please note that the usual way of getting Horde_Ldap to work is + * to call something like: + * $ldap = Horde_Ldap::connect($ldap_config); + * + * @param array $config Configuration array + * + * @access protected + * @return void + * @see $_config + */ public function __construct($config = array()) { - $this->PEAR('Net_LDAP2_Error'); + $this->PEAR('Horde_Ldap_Error'); $this->setConfig($config); } /** - * Sets the internal configuration array - * - * @param array $config Configuration array - * - * @access protected - * @return void - */ + * Sets the internal configuration array + * + * @param array $config Configuration array + * + * @access protected + * @return void + */ protected function setConfig($config) { // @@ -255,7 +235,7 @@ class Net_LDAP2 extends PEAR if (isset($this->_config[$k])) { $this->_config[$k] = $v; } else { - // map old (Net_LDAP2) parms to new ones + // map old (Net_Ldap) parms to new ones switch($k) { case "dn": $this->_config["binddn"] = $v; @@ -296,22 +276,22 @@ class Net_LDAP2 extends PEAR } /** - * Bind or rebind to the ldap-server - * - * This function binds with the given dn and password to the server. In case - * no connection has been made yet, it will be started and startTLS issued - * if appropiate. - * - * The internal bind configuration is not being updated, so if you call - * bind() without parameters, you can rebind with the credentials - * provided at first connecting to the server. - * - * @param string $dn Distinguished name for binding - * @param string $password Password for binding - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Bind or rebind to the ldap-server + * + * This function binds with the given dn and password to the server. In case + * no connection has been made yet, it will be started and startTLS issued + * if appropiate. + * + * The internal bind configuration is not being updated, so if you call + * bind() without parameters, you can rebind with the credentials + * provided at first connecting to the server. + * + * @param string $dn Distinguished name for binding + * @param string $password Password for binding + * + * @access public + * @return true true on success + */ public function bind($dn = null, $password = null) { // fetch current bind credentials @@ -357,23 +337,23 @@ class Net_LDAP2 extends PEAR $msg = @ldap_bind($this->_link, $dn, $password); } if (false === $msg) { - return PEAR::raiseError("Bind failed: " . - @ldap_error($this->_link), - @ldap_errno($this->_link)); + throw new Horde_Ldap_Exception("Bind failed: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); } } return true; } /** - * Connect to the ldap-server - * - * This function connects to the LDAP server specified in - * the configuration, binds and set up the LDAP protocol as needed. - * - * @access protected - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Connect to the LDAP server + * + * This function connects to the LDAP server specified in + * the configuration, binds and set up the LDAP protocol as needed. + * + * @access protected + * @return true true on success + */ protected function performConnect() { // Note: Connecting is briefly described in RFC1777. @@ -400,13 +380,11 @@ class Net_LDAP2 extends PEAR // Default error message in case all connection attempts // fail but no message is set - $current_error = new PEAR_Error('Unknown connection error'); + $current_error = new Horde_Ldap_Exception('Unknown connection error'); // Catch empty $_host_list arrays. if (!is_array($this->_host_list) || count($this->_host_list) == 0) { - $current_error = PEAR::raiseError('No Servers configured! Please '. - 'pass in an array of servers to Net_LDAP2'); - return $current_error; + throw new Horde_Ldap_Exception('No servers configured'); } // Cycle through the host list. @@ -414,9 +392,7 @@ class Net_LDAP2 extends PEAR // Ensure we have a valid string for host name if (is_array($host)) { - $current_error = PEAR::raiseError('No Servers configured! '. - 'Please pass in an one dimensional array of servers to '. - 'Net_LDAP2! (multidimensional array detected!)'); + $current_error = new Horde_Ldap_Exception('No Servers configured'); continue; } @@ -432,8 +408,7 @@ class Net_LDAP2 extends PEAR // Attempt a connection. $this->_link = @ldap_connect($host, $this->_config['port']); if (false === $this->_link) { - $current_error = PEAR::raiseError('Could not connect to ' . - $host . ':' . $this->_config['port']); + $current_error = new Horde_Ldap_Exception('Could not connect to ' . $host . ':' . $this->_config['port']); $this->_down_host_list[] = $host; continue; } @@ -451,20 +426,17 @@ class Net_LDAP2 extends PEAR // Try to set the configured LDAP version on the connection if LDAP // server needs that before binding (eg OpenLDAP). - // This could be necessary since rfc-1777 states that the protocol version - // has to be set at the bind request. - // We use force here which means that the test in the rootDSE is skipped; - // this is neccessary, because some strict LDAP servers only allow to - // read the LDAP rootDSE (which tells us the supported protocol versions) - // with authenticated clients. + // This could be necessary since rfc-1777 states that the protocol + // version has to be set at the bind request. + // We use force here which means that the test in the rootDSE is + // skipped; this is neccessary, because some strict LDAP servers + // only allow to // read the LDAP rootDSE (which tells us the + // supported protocol versions) with authenticated clients. // This may fail in which case we try again after binding. // In this case, most probably the bind() or setLDAPVersion()-call // below will also fail, providing error messages. $version_set = false; - $ignored_err = $this->setLDAPVersion(0, true); - if (!self::isError($ignored_err)) { - $version_set = true; - } + $this->setLDAPVersion(0, true); // Attempt to bind to the server. If we have credentials configured, // we try to use them, otherwise its an anonymous bind. @@ -474,20 +446,21 @@ class Net_LDAP2 extends PEAR // V2 binds and the above call to setLDAPVersion() failed. // In case the above call failed, we try an V2 bind here and set the // version afterwards (with checking to the rootDSE). - $msg = $this->bind(); - if (self::isError($msg)) { + try { + $msg = $this->bind(); + } catch (Exception $e) { // The bind failed, discard link and save error msg. // Then record the host as down and try next one - if ($msg->getCode() == 0x02 && !$version_set) { + if ($e->getCode() == 0x02 && !$version_set) { // provide a finer grained error message - // if protocol error arieses because of invalid version - $msg = new Net_LDAP2_Error($msg->getMessage(). + // if protocol error arises because of invalid version + $e = new Horde_Ldap_Exception($e->getMessage(). " (could not set LDAP protocol version to ". $this->_config['version'].")", - $msg->getCode()); + $e->getCode()); } $this->_link = false; - $current_error = $msg; + $current_error = $e; $this->_down_host_list[] = $host; continue; } @@ -499,8 +472,10 @@ class Net_LDAP2 extends PEAR // supported. However, some strict LDAP servers only allow // bound suers to read the rootDSE. if (!$version_set) { - if (self::isError($msg = $this->setLDAPVersion())) { - $current_error = $msg; + try { + $this->setLDAPVersion(); + } catch (Exception $e) { + $current_error = $e; $this->_link = false; $this->_down_host_list[] = $host; continue; @@ -512,9 +487,10 @@ class Net_LDAP2 extends PEAR is_array($this->_config['options']) && count($this->_config['options'])) { foreach ($this->_config['options'] as $opt => $val) { - $err = $this->setOption($opt, $val); - if (self::isError($err)) { - $current_error = $err; + try { + $this->setOption($opt, $val); + } catch (Exception $e) { + $current_error = $e; $this->_link = false; $this->_down_host_list[] = $host; continue 2; @@ -529,31 +505,31 @@ class Net_LDAP2 extends PEAR // All connection attempts have failed, return the last error. - return $current_error; + throw $current_error; } /** - * Reconnect to the ldap-server. - * - * In case the connection to the LDAP - * service has dropped out for some reason, this function will reconnect, - * and re-bind if a bind has been attempted in the past. It is probably - * most useful when the server list provided to the new() or connect() - * function is an array rather than a single host name, because in that - * case it will be able to connect to a failover or secondary server in - * case the primary server goes down. - * - * This doesn't return anything, it just tries to re-establish - * the current connection. It will sleep for the current backoff - * period (seconds) before attempting the connect, and if the - * connection fails it will double the backoff period, but not - * try again. If you want to ensure a reconnection during a - * transient period of server downtime then you need to call this - * function in a loop. - * - * @access protected - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Reconnect to the LDAP server. + * + * In case the connection to the LDAP + * service has dropped out for some reason, this function will reconnect, + * and re-bind if a bind has been attempted in the past. It is probably + * most useful when the server list provided to the new() or connect() + * function is an array rather than a single host name, because in that + * case it will be able to connect to a failover or secondary server in + * case the primary server goes down. + * + * This doesn't return anything, it just tries to re-establish + * the current connection. It will sleep for the current backoff + * period (seconds) before attempting the connect, and if the + * connection fails it will double the backoff period, but not + * try again. If you want to ensure a reconnection during a + * transient period of server downtime then you need to call this + * function in a loop. + * + * @access protected + * @return true true on success + */ protected function performReconnect() { @@ -564,7 +540,7 @@ class Net_LDAP2 extends PEAR // Default error message in case all connection attempts // fail but no message is set - $current_error = new PEAR_Error('Unknown connection error'); + $current_error = new Horde_Ldap_Exception('Unknown connection error'); // Sleep for a backoff period in seconds. sleep($this->_config['current_backoff']); @@ -584,8 +560,9 @@ class Net_LDAP2 extends PEAR } // Now we should be able to safely (re-)bind. - $msg = $this->bind(); - if (self::isError($msg)) { + try { + $this->bind(); + } catch (Exception $e) { $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2; if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { $this->_config['current_backoff'] = $this->_config['max_backoff']; @@ -595,7 +572,7 @@ class Net_LDAP2 extends PEAR // by performConnect(). Since we are unable to bind to that host we can safely // assume that it is down or has some other problem. $this->_down_host_list[] = $this->_config['host']; - return $msg; + throw e; } // At this stage we have connected, bound, and set up options, @@ -605,100 +582,90 @@ class Net_LDAP2 extends PEAR } /** - * Starts an encrypted session - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Starts an encrypted session + * + * @access public + * @return true true on success + */ public function startTLS() { // Test to see if the server supports TLS first. // This is done via testing the extensions offered by the server. - // The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported. - $rootDSE = $this->rootDse(); - if (self::isError($rootDSE)) { - return $this->raiseError("Unable to fetch rootDSE entry ". - "to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode()); + // The OID 1.3.6.1.4.1.1466.20037 tells whether TLS is supported. + try { + $rootDSE = $this->rootDse(); + } catch (Exception $e) { + throw new Horde_Ldap_Exception("Unable to fetch rootDSE entry ". + "to see if TLS is supoported: ".$e->getMessage(), $e->getCode()); } - $supported_extensions = $rootDSE->getValue('supportedExtension'); - if (self::isError($supported_extensions)) { - return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ". - "to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode()); + try { + $supported_extensions = $rootDSE->getValue('supportedExtension'); + } catch (Exception $e) { + throw new Horde_Ldap_Exception("Unable to fetch rootDSE attribute 'supportedExtension' ". + "to see if TLS is supoported: ".$e->getMessage(), $e->getCode()); } if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) { if (false === @ldap_start_tls($this->_link)) { - return $this->raiseError("TLS not started: " . - @ldap_error($this->_link), - @ldap_errno($this->_link)); + throw new Horde_Ldap_Exception("TLS not started: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); } return true; } else { - return $this->raiseError("Server reports that it does not support TLS"); + throw new Horde_Ldap_Exception("Server reports that it does not support TLS"); } } /** - * alias function of startTLS() for perl-ldap interface - * - * @return void - * @see startTLS() - */ - public function start_tls() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'startTLS' ), $args); - } - - /** - * Close LDAP connection. - * - * Closes the connection. Use this when the session is over. - * - * @return void - */ + * Close LDAP connection. + * + * Closes the connection. Use this when the session is over. + * + * @return void + */ public function done() { - $this->_Net_LDAP2(); + $this->_Horde_Ldap(); } /** - * Alias for {@link done()} - * - * @return void - * @see done() - */ + * Alias for {@link done()} + * + * @return void + * @see done() + */ public function disconnect() { $this->done(); } /** - * Destructor - * - * @access protected - */ - public function _Net_LDAP2() + * Destructor + * + * @access protected + */ + private function _Horde_Ldap() { @ldap_close($this->_link); } /** - * Add a new entryobject to a directory. - * - * Use add to add a new Net_LDAP2_Entry object to the directory. - * This also links the entry to the connection used for the add, - * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()}) - * - * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry - * - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Add a new entryobject to a directory. + * + * Use add to add a new Horde_Ldap_Entry object to the directory. + * This also links the entry to the connection used for the add, + * if it was a fresh entry ({@link HordeLdap_Entry::createFresh()}) + * + * @param Horde_Ldap_Entry &$entry HordeLdap_Entry + * + * @return true Horde_Ldap_Error object or true + */ public function add(&$entry) { - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.'); + if (!$entry instanceof Horde_Ldap_Entry) { + throw new Horde_Ldap_Exception('Parameter to Horde_Ldap::add() must be a Horde_Ldap_Entry object.'); } // Continue attempting the add operation in a loop until we @@ -711,14 +678,14 @@ class Net_LDAP2 extends PEAR // We do not have a successful connection yet. The call to // getLink() would have kept trying if we wanted one. Go // home now. - return PEAR::raiseError("Could not add entry " . $entry->dn() . + throw new Horde_Ldap_Exception("Could not add entry " . $entry->dn() . " no valid LDAP connection could be found."); } if (@ldap_add($link, $entry->dn(), $entry->getValues())) { // entry successfully added, we should update its $ldap reference // in case it is not set so far (fresh entry) - if (!$entry->getLDAP() instanceof Net_LDAP2) { + if (!$entry->getLDAP() instanceof Horde_Ldap) { $entry->setLDAP($this); } // store, that the entry is present inside the directory @@ -741,34 +708,34 @@ class Net_LDAP2 extends PEAR } else { // Errors other than the above catched are just passed // back to the user so he may react upon them. - return PEAR::raiseError("Could not add entry " . $entry->dn() . " " . - $error_name, - $error_code); + throw new Horde_Ldap_Exception("Could not add entry " . $entry->dn() . " " . + $error_name, + $error_code); } } } } /** - * Delete an entry from the directory - * - * The object may either be a string representing the dn or a Net_LDAP2_Entry - * object. When the boolean paramter recursive is set, all subentries of the - * entry will be deleted as well. - * - * @param string|Net_LDAP2_Entry $dn DN-string or Net_LDAP2_Entry - * @param boolean $recursive Should we delete all children recursive as well? - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Delete an entry from the directory + * + * The object may either be a string representing the dn or a Horde_Ldap_Entry + * object. When the boolean paramter recursive is set, all subentries of the + * entry will be deleted as well. + * + * @param string|Horde_Ldap_Entry $dn DN-string or Horde_Ldap_Entry + * @param boolean $recursive Should we delete all children recursive as well? + * + * @access public + * @return true true on success + */ public function delete($dn, $recursive = false) { - if ($dn instanceof Net_LDAP2_Entry) { + if ($dn instanceof Horde_Ldap_Entry) { $dn = $dn->dn(); } if (false === is_string($dn)) { - return PEAR::raiseError("Parameter is not a string nor an entry object!"); + throw new Horde_Ldap_Exception("Parameter is not a string nor an entry object!"); } // Recursive delete searches for children and calls delete for them if ($recursive) { @@ -791,7 +758,7 @@ class Net_LDAP2 extends PEAR // We do not have a successful connection yet. The call to // getLink() would have kept trying if we wanted one. Go // home now. - return PEAR::raiseError("Could not add entry " . $dn . + throw new Horde_Ldap_Exception("Could not add entry " . $dn . " no valid LDAP connection could be found."); } @@ -818,86 +785,82 @@ class Net_LDAP2 extends PEAR // since the user may not know of the subentries, we do not // force that here but instead notify the developer so he // may take actions himself. - return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them."); + throw new Horde_Ldap_Exception("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them."); } else { // Errors other than the above catched are just passed // back to the user so he may react upon them. - return PEAR::raiseError("Could not delete entry " . $dn . " " . - $error_name, - $error_code); + throw new Horde_Ldap_Exception("Could not delete entry " . $dn . " " . + $error_name, + $error_code); } } } } /** - * Modify an ldapentry directly on the server - * - * This one takes the DN or a Net_LDAP2_Entry object and an array of actions. - * This array should be something like this: - * - * array('add' => array('attribute1' => array('val1', 'val2'), - * 'attribute2' => array('val1')), - * 'delete' => array('attribute1'), - * 'replace' => array('attribute1' => array('val1')), - * 'changes' => array('add' => ..., - * 'replace' => ..., - * 'delete' => array('attribute1', 'attribute2' => array('val1'))) - * - * The changes array is there so the order of operations can be influenced - * (the operations are done in order of appearance). - * The order of execution is as following: - * 1. adds from 'add' array - * 2. deletes from 'delete' array - * 3. replaces from 'replace' array - * 4. changes (add, replace, delete) in order of appearance - * All subarrays (add, replace, delete, changes) may be given at the same time. - * - * The function calls the corresponding functions of an Net_LDAP2_Entry - * object. A detailed description of array structures can be found there. - * - * Unlike the modification methods provided by the Net_LDAP2_Entry object, - * this method will instantly carry out an update() after each operation, - * thus modifying "directly" on the server. - * - * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry - * @param array $parms Array of changes - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Modify an ldapentry directly on the server + * + * This one takes the DN or a Horde_Ldap_Entry object and an array of actions. + * This array should be something like this: + * + * array('add' => array('attribute1' => array('val1', 'val2'), + * 'attribute2' => array('val1')), + * 'delete' => array('attribute1'), + * 'replace' => array('attribute1' => array('val1')), + * 'changes' => array('add' => ..., + * 'replace' => ..., + * 'delete' => array('attribute1', 'attribute2' => array('val1'))) + * + * The changes array is there so the order of operations can be influenced + * (the operations are done in order of appearance). + * The order of execution is as following: + * 1. adds from 'add' array + * 2. deletes from 'delete' array + * 3. replaces from 'replace' array + * 4. changes (add, replace, delete) in order of appearance + * All subarrays (add, replace, delete, changes) may be given at the same time. + * + * The function calls the corresponding functions of an Horde_Ldap_Entry + * object. A detailed description of array structures can be found there. + * + * Unlike the modification methods provided by the Horde_Ldap_Entry object, + * this method will instantly carry out an update() after each operation, + * thus modifying "directly" on the server. + * + * @param string|Horde_Ldap_Entry $entry DN-string or Horde_Ldap_Entry + * @param array $parms Array of changes + * + * @access public + * @return true true on success + */ public function modify($entry, $parms = array()) { if (is_string($entry)) { $entry = $this->getEntry($entry); - if (self::isError($entry)) { - return $entry; - } - } - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError("Parameter is not a string nor an entry object!"); + } + if (!$entry instanceof Horde_Ldap_Entry) { + throw new Horde_Ldap_Exception("Parameter is not a string nor an entry object!"); } // Perform changes mentioned separately foreach (array('add', 'delete', 'replace') as $action) { if (isset($parms[$action])) { $msg = $entry->$action($parms[$action]); - if (self::isError($msg)) { - return $msg; - } + $entry->setLDAP($this); - // Because the @ldap functions are called inside Net_LDAP2_Entry::update(), + // Because the @ldap functions are called inside Horde_Ldap_Entry::update(), // we have to trap the error codes issued from that if we want to support // reconnection. while (true) { - $msg = $entry->update(); - - if (self::isError($msg)) { + try { + $entry->update(); + break; + } catch (Exception $e) { // We have a failure. What type? We may be able to reconnect // and try again. - $error_code = $msg->getCode(); + $error_code = $e->getCode(); $error_name = $this->errorMessage($error_code); if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && @@ -913,11 +876,8 @@ class Net_LDAP2 extends PEAR // Errors other than the above catched are just passed // back to the user so he may react upon them. - return PEAR::raiseError("Could not modify entry: ".$msg->getMessage()); + throw new Horde_Ldap_Exception("Could not modify entry: ".$e->getMessage()); } - } else { - // modification succeedet, evaluate next change - break; } } } @@ -927,16 +887,17 @@ class Net_LDAP2 extends PEAR if (isset($parms['changes']) && is_array($parms['changes'])) { foreach ($parms['changes'] as $action => $value) { - // Because the @ldap functions are called inside Net_LDAP2_Entry::update, + // Because the @ldap functions are called inside Horde_Ldap_Entry::update, // we have to trap the error codes issued from that if we want to support // reconnection. while (true) { - $msg = $this->modify($entry, array($action => $value)); - - if (self::isError($msg)) { + try { + $this->modify($entry, array($action => $value)); + break; + } catch (Exception $e) { // We have a failure. What type? We may be able to reconnect // and try again. - $error_code = $msg->getCode(); + $error_code = $e->getCode(); $error_name = $this->errorMessage($error_code); if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && @@ -953,9 +914,6 @@ class Net_LDAP2 extends PEAR // back to the user so he may react upon them. return $msg; } - } else { - // modification succeedet, evaluate next change - break; } } } @@ -965,65 +923,59 @@ class Net_LDAP2 extends PEAR } /** - * Run a ldap search query - * - * Search is used to query the ldap-database. - * $base and $filter may be ommitted. The one from config will - * then be used. $base is either a DN-string or an Net_LDAP2_Entry - * object in which case its DN willb e used. - * - * Params may contain: - * - * scope: The scope which will be used for searching - * base - Just one entry - * sub - The whole tree - * one - Immediately below $base - * sizelimit: Limit the number of entries returned (default: 0 = unlimited), - * timelimit: Limit the time spent for searching (default: 0 = unlimited), - * attrsonly: If true, the search will only return the attribute names, - * attributes: Array of attribute names, which the entry should contain. - * It is good practice to limit this to just the ones you need. - * [NOT IMPLEMENTED] - * deref: By default aliases are dereferenced to locate the base object for the search, but not when - * searching subordinates of the base object. This may be changed by specifying one of the - * following values: - * - * never - Do not dereference aliases in searching or in locating the base object of the search. - * search - Dereference aliases in subordinates of the base object in searching, but not in - * locating the base object of the search. - * find - * always - * - * Please note, that you cannot override server side limitations to sizelimit - * and timelimit: You can always only lower a given limit. - * - * @param string|Net_LDAP2_Entry $base LDAP searchbase - * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object - * @param array $params Array of options - * - * @access public - * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object - * @todo implement search controls (sorting etc) - */ + * Run a ldap search query + * + * Search is used to query the ldap-database. + * $base and $filter may be ommitted. The one from config will + * then be used. $base is either a DN-string or an Horde_Ldap_Entry + * object in which case its DN willb e used. + * + * Params may contain: + * + * scope: The scope which will be used for searching + * base - Just one entry + * sub - The whole tree + * one - Immediately below $base + * sizelimit: Limit the number of entries returned (default: 0 = unlimited), + * timelimit: Limit the time spent for searching (default: 0 = unlimited), + * attrsonly: If true, the search will only return the attribute names, + * attributes: Array of attribute names, which the entry should contain. + * It is good practice to limit this to just the ones you need. + * [NOT IMPLEMENTED] + * deref: By default aliases are dereferenced to locate the base object for the search, but not when + * searching subordinates of the base object. This may be changed by specifying one of the + * following values: + * + * never - Do not dereference aliases in searching or in locating the base object of the search. + * search - Dereference aliases in subordinates of the base object in searching, but not in + * locating the base object of the search. + * find + * always + * + * Please note, that you cannot override server side limitations to sizelimit + * and timelimit: You can always only lower a given limit. + * + * @param string|Horde_Ldap_Entry $base LDAP searchbase + * @param string|Horde_Ldap_Filter $filter LDAP search filter or a Horde_Ldap_Filter object + * @param array $params Array of options + * + * @access public + * @return Horde_Ldap_Search Horde_Ldap_Search object + * @todo implement search controls (sorting etc) + */ public function search($base = null, $filter = null, $params = array()) { if (is_null($base)) { $base = $this->_config['basedn']; } - if ($base instanceof Net_LDAP2_Entry) { + if ($base instanceof Horde_Ldap_Entry) { $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry } if (is_null($filter)) { $filter = $this->_config['filter']; } - if ($filter instanceof Net_LDAP2_Filter) { - $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation - } - if (PEAR::isError($filter)) { - return $filter; - } - if (PEAR::isError($base)) { - return $base; + if ($filter instanceof Horde_Ldap_Filter) { + $filter = $filter->asString(); // convert Horde_Ldap_Filter to string representation } /* setting searchparameters */ @@ -1072,36 +1024,36 @@ class Net_LDAP2 extends PEAR if ($err = @ldap_errno($link)) { if ($err == 32) { // Errorcode 32 = no such object, i.e. a nullresult. - return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + return $obj = new Horde_Ldap_Search ($search, $this, $attributes); } elseif ($err == 4) { // Errorcode 4 = sizelimit exeeded. - return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + return $obj = new Horde_Ldap_Search ($search, $this, $attributes); } elseif ($err == 87) { // bad search filter - return $this->raiseError($this->errorMessage($err) . "($filter)", $err); + throw new Horde_Ldap_Exception($this->errorMessage($err) . "($filter)", $err); } elseif (($err == 1) && ($this->_config['auto_reconnect'])) { // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect. $this->_link = false; $this->performReconnect(); } else { $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope"; - return $this->raiseError($this->errorMessage($err) . $msg, $err); + throw new Horde_Ldap_Exception($this->errorMessage($err) . $msg, $err); } } else { - return $obj = new Net_LDAP2_Search($search, $this, $attributes); + return $obj = new Horde_Ldap_Search($search, $this, $attributes); } } } /** - * Set an LDAP option - * - * @param string $option Option to set - * @param mixed $value Value to set Option to - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ + * Set an LDAP option + * + * @param string $option Option to set + * @param mixed $value Value to set Option to + * + * @access public + * @return true true on success + */ public function setOption($option, $value) { if ($this->_link) { @@ -1113,27 +1065,27 @@ class Net_LDAP2 extends PEAR if ($err) { $msg = @ldap_err2str($err); } else { - $err = NET_LDAP2_ERROR; + $err = Horde_Ldap::_ERROR; $msg = $this->errorMessage($err); } - return $this->raiseError($msg, $err); + throw new Horde_Ldap_Exception($msg, $err); } } else { - return $this->raiseError("Unkown Option requested"); + throw new Horde_Ldap_Exception("Unkown Option requested"); } } else { - return $this->raiseError("Could not set LDAP option: No LDAP connection"); + throw new Horde_Ldap_Exception("Could not set LDAP option: No LDAP connection"); } } /** - * Get an LDAP option value - * - * @param string $option Option to get - * - * @access public - * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value - */ + * Get an LDAP option value + * + * @param string $option Option to get + * + * @access public + * @return Horde_Ldap_Error|string Horde_Ldap_Error or option value + */ public function getOption($option) { if ($this->_link) { @@ -1145,27 +1097,27 @@ class Net_LDAP2 extends PEAR if ($err) { $msg = @ldap_err2str($err); } else { - $err = NET_LDAP2_ERROR; + $err = Horde_Ldap::_ERROR; $msg = $this->errorMessage($err); } - return $this->raiseError($msg, $err); + throw new Horde_Ldap_Exception($msg, $err); } } else { - $this->raiseError("Unkown Option requested"); + throw new Horde_Ldap_Exception("Unkown Option requested"); } } else { - $this->raiseError("No LDAP connection"); + throw new Horde_Ldap_Exception("No LDAP connection"); } } /** - * Get the LDAP_PROTOCOL_VERSION that is used on the connection. - * - * A lot of ldap functionality is defined by what protocol version the ldap server speaks. - * This might be 2 or 3. - * - * @return int - */ + * Get the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * A lot of ldap functionality is defined by what protocol version the ldap server speaks. + * This might be 2 or 3. + * + * @return int + */ public function getLDAPVersion() { if ($this->_link) { @@ -1177,14 +1129,14 @@ class Net_LDAP2 extends PEAR } /** - * Set the LDAP_PROTOCOL_VERSION that is used on the connection. - * - * @param int $version LDAP-version that should be used - * @param boolean $force If set to true, the check against the rootDSE will be skipped - * - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick! - */ + * Set the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * @param int $version LDAP-version that should be used + * @param boolean $force If set to true, the check against the rootDSE will be skipped + * + * @return true true + * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick! + */ public function setLDAPVersion($version = 0, $force = false) { if (!$version) { @@ -1195,62 +1147,53 @@ class Net_LDAP2 extends PEAR // Check to see if the server supports this version first. // // Todo: Why is this so horribly slow? - // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch() + // $this->rootDse() is very fast, as well as Horde_Ldap_RootDSE::fetch() // seems like a problem at copiyng the object inside PHP?? // Additionally, this is not always reproducable... // if (!$force) { $rootDSE = $this->rootDse(); - if ($rootDSE instanceof Net_LDAP2_Error) { - return $rootDSE; - } else { - $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); - if (is_string($supported_versions)) { - $supported_versions = array($supported_versions); - } - $check_ok = in_array($version, $supported_versions); + $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); + if (is_string($supported_versions)) { + $supported_versions = array($supported_versions); } + $check_ok = in_array($version, $supported_versions); } if ($force || $check_ok) { return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version); } else { - return $this->raiseError("LDAP Server does not support protocol version " . $version); + throw new Horde_Ldap_Exception("LDAP Server does not support protocol version " . $version); } } /** - * Tells if a DN does exist in the directory - * - * @param string|Net_LDAP2_Entry $dn The DN of the object to test - * - * @return boolean|Net_LDAP2_Error - */ + * Tells if a DN does exist in the directory + * + * @param string|Horde_Ldap_Entry $dn The DN of the object to test + * + * @return boolean + */ public function dnExists($dn) { - if (PEAR::isError($dn)) { - return $dn; - } - if ($dn instanceof Net_LDAP2_Entry) { + if ($dn instanceof Horde_Ldap_Entry) { $dn = $dn->dn(); } if (false === is_string($dn)) { - return PEAR::raiseError('Parameter $dn is not a string nor an entry object!'); + throw new Horde_Ldap_Exception('Parameter $dn is not a string nor an entry object!'); } // make dn relative to parent - $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); - if (self::isError($base)) { - return $base; - } + $base = Horde_Ldap_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); + $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_LDAP2_Util::canonical_dn($entry_rdn); + $filter_dn = Horde_Ldap_Util::canonical_dn($entry_rdn); } - $base = Net_LDAP2_Util::canonical_dn($base); + $base = Horde_Ldap_Util::canonical_dn($base); $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); if (@ldap_count_entries($this->_link, $result)) { @@ -1260,21 +1203,21 @@ class Net_LDAP2 extends PEAR return false; } if (ldap_errno($this->_link) != 0) { - return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); + throw new Horde_Ldap_Exception(ldap_error($this->_link), ldap_errno($this->_link)); } return false; } /** - * Get a specific entry based on the DN - * - * @param string $dn DN of the entry that should be fetched - * @param array $attr Array of Attributes to select. If ommitted, all attributes are fetched. - * - * @return Net_LDAP2_Entry|Net_LDAP2_Error Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object - * @todo Maybe check against the shema should be done to be sure the attribute type exists - */ + * Get a specific entry based on the DN + * + * @param string $dn DN of the entry that should be fetched + * @param array $attr Array of Attributes to select. If ommitted, all attributes are fetched. + * + * @return Horde_Ldap_Entry Reference to a Horde_Ldap_Entry object + * @todo Maybe check against the shema should be done to be sure the attribute type exists + */ public function &getEntry($dn, $attr = array()) { if (!is_array($attr)) { @@ -1282,38 +1225,36 @@ class Net_LDAP2 extends PEAR } $result = $this->search($dn, '(objectClass=*)', array('scope' => 'base', 'attributes' => $attr)); - if (self::isError($result)) { - return $result; - } elseif ($result->count() == 0) { - return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found'); + if ($result->count() == 0) { + throw new Horde_Ldap_Exception('Could not fetch entry '.$dn.': no entry found'); } $entry = $result->shiftEntry(); if (false == $entry) { - return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)'); + throw new Horde_Ldap_Exception('Could not fetch entry (error retrieving entry from search result)'); } return $entry; } /** - * Rename or move an entry - * - * This method will instantly carry out an update() after the move, - * so the entry is moved instantly. - * You can pass an optional Net_LDAP2 object. In this case, a cross directory - * move will be performed which deletes the entry in the source (THIS) directory - * and adds it in the directory $target_ldap. - * A cross directory move will switch the Entrys internal LDAP reference so - * updates to the entry will go to the new directory. - * - * Note that if you want to do a cross directory move, you need to - * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty. - * - * @param string|Net_LDAP2_Entry $entry Entry DN or Entry object - * @param string $newdn New location - * @param Net_LDAP2 $target_ldap (optional) Target directory for cross server move; should be passed via reference - * - * @return Net_LDAP2_Error|true - */ + * Rename or move an entry + * + * This method will instantly carry out an update() after the move, + * so the entry is moved instantly. + * You can pass an optional Horde_Ldap object. In this case, a cross directory + * move will be performed which deletes the entry in the source (THIS) directory + * and adds it in the directory $target_ldap. + * A cross directory move will switch the Entrys internal LDAP reference so + * updates to the entry will go to the new directory. + * + * Note that if you want to do a cross directory move, you need to + * pass an Horde_Ldap_Entry object, otherwise the attributes will be empty. + * + * @param string|Horde_Ldap_Entry $entry Entry DN or Entry object + * @param string $newdn New location + * @param Horde_Ldap $target_ldap (optional) Target directory for cross server move; should be passed via reference + * + * @return true + */ public function move($entry, $newdn, $target_ldap = null) { if (is_string($entry)) { @@ -1321,33 +1262,38 @@ class Net_LDAP2 extends PEAR } else { $entry_o =& $entry; } - if (!$entry_o instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)'); + if (!$entry_o instanceof Horde_Ldap_Entry) { + throw new Horde_Ldap_Exception('Parameter $entry is expected to be a Horde_Ldap_Entry object! (If DN was passed, conversion failed)'); } - if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) { - return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!'); + if (null !== $target_ldap && !$target_ldap instanceof Horde_Ldap) { + throw new Horde_Ldap_Exception('Parameter $target_ldap is expected to be a Horde_Ldap object!'); } if ($target_ldap && $target_ldap !== $this) { // cross directory move if (is_string($entry)) { - return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object'); + throw new Horde_Ldap_Exception('Unable to perform cross directory move: operation requires a Horde_Ldap_Entry object'); } if ($target_ldap->dnExists($newdn)) { - return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory'); + throw new Horde_Ldap_Exception('Unable to perform cross directory move: entry does exist in target directory'); } $entry_o->dn($newdn); - $res = $target_ldap->add($entry_o); - if (self::isError($res)) { - return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory'); + try { + $target_ldap->add($entry_o); + } catch (Exception $e) { + throw new Horde_Ldap_Exception('Unable to perform cross directory move: '.$e->getMessage().' in target directory'); } - $res = $this->delete($entry_o->currentDN()); - if (self::isError($res)) { - $res2 = $target_ldap->delete($entry_o); // undo add - if (self::isError($res2)) { + + try { + $this->delete($entry_o->currentDN()); + } catch (Exception $e) { + try { + $add_error_string = ''; + $target_ldap->delete($entry_o); // undo add + } catch (Exception $e) { $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.'; } - return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string); + throw new Horde_Ldap_Exception('Unable to perform cross directory move: '.$e->getMessage().' in source directory. '.$add_error_string); } $entry_o->setLDAP($target_ldap); return true; @@ -1360,46 +1306,42 @@ class Net_LDAP2 extends PEAR } /** - * Copy an entry to a new location - * - * The entry will be immediately copied. - * Please note that only attributes you have - * selected will be copied. - * - * @param Net_LDAP2_Entry &$entry Entry object - * @param string $newdn New FQF-DN of the entry - * - * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry - */ + * Copy an entry to a new location + * + * The entry will be immediately copied. + * Please note that only attributes you have + * selected will be copied. + * + * @param Horde_Ldap_Entry &$entry Entry object + * @param string $newdn New FQF-DN of the entry + * + * @return Horde_Ldap_Entry Error Message or reference to the copied entry + */ public function ©(&$entry, $newdn) { - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!'); + if (!$entry instanceof Horde_Ldap_Entry) { + throw new Horde_Ldap_Exception('Parameter $entry is expected to be a Horde_Ldap_Entry object'); } - $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues()); + $newentry = Horde_Ldap_Entry::createFresh($newdn, $entry->getValues()); $result = $this->add($newentry); - if ($result instanceof Net_LDAP2_Error) { - return $result; - } else { - return $newentry; - } + return $newentry; } /** - * Returns the string for an ldap errorcode. - * - * Made to be able to make better errorhandling - * Function based on DB::errorMessage() - * Tip: The best description of the errorcodes is found here: - * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html - * - * @param int $errorcode Error code - * - * @return string The errorstring for the error. - */ + * Returns the string for an ldap errorcode. + * + * Made to be able to make better errorhandling + * Function based on DB::errorMessage() + * Tip: The best description of the errorcodes is found here: + * http://www.directory-info.com/Ldap/LDAPErrorCodes.html + * + * @param int $errorcode Error code + * + * @return string The errorstring for the error. + */ public function errorMessage($errorcode) { $errorMessages = array( @@ -1464,29 +1406,29 @@ class Net_LDAP2 extends PEAR 0x5f => "LDAP_MORE_RESULTS_TO_RETURN", 0x60 => "LDAP_CLIENT_LOOP", 0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED", - 1000 => "Unknown Net_LDAP2 Error" + 1000 => "Unknown Error" ); return isset($errorMessages[$errorcode]) ? $errorMessages[$errorcode] : - $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')'; + $errorMessages[Horde_Ldap::_ERROR] . ' (' . $errorcode . ')'; } /** - * Gets a rootDSE object - * - * This either fetches a fresh rootDSE object or returns it from - * the internal cache for performance reasons, if possible. - * - * @param array $attrs Array of attributes to search for - * - * @access public - * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object - */ + * Gets a rootDSE object + * + * This either fetches a fresh rootDSE object or returns it from + * the internal cache for performance reasons, if possible. + * + * @param array $attrs Array of attributes to search for + * + * @access public + * @return Horde_Ldap_RootDSE Horde_Ldap_RootDSE object + */ public function &rootDse($attrs = null) { if ($attrs !== null && !is_array($attrs)) { - return PEAR::raiseError('Parameter $attr is expected to be an array!'); + throw new Horde_Ldap_Exception('Parameter $attr is expected to be an array'); } $attrs_signature = serialize($attrs); @@ -1494,10 +1436,7 @@ class Net_LDAP2 extends PEAR // see if we need to fetch a fresh object, or if we already // requested this object with the same attributes if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) { - $rootdse =& Net_LDAP2_RootDSE::fetch($this, $attrs); - if ($rootdse instanceof Net_LDAP2_Error) { - return $rootdse; - } + $rootdse =& Horde_Ldap_RootDSE::fetch($this, $attrs); // search was ok, store rootDSE in cache $this->_rootDSE_cache[$attrs_signature] = $rootdse; @@ -1506,12 +1445,12 @@ class Net_LDAP2 extends PEAR } /** - * Alias function of rootDse() for perl-ldap interface - * - * @access public - * @see rootDse() - * @return Net_LDAP2_Error|Net_LDAP2_RootDSE - */ + * Alias function of rootDse() for perl-ldap interface + * + * @access public + * @see rootDse() + * @return Horde_Ldap_RootDSE + */ public function &root_dse() { $args = func_get_args(); @@ -1519,28 +1458,24 @@ class Net_LDAP2 extends PEAR } /** - * Get a schema object - * - * @param string $dn (optional) Subschema entry dn - * - * @access public - * @return Net_LDAP2_Schema|Net_LDAP2_Error Net_LDAP2_Schema or Net_LDAP2_Error object - */ + * Get a schema object + * + * @param string $dn (optional) Subschema entry dn + * + * @access public + * @return Horde_Ldap_Schema Horde_Ldap_Schema object + */ public function &schema($dn = null) { - // Schema caching by Knut-Olav Hoven // If a schema caching object is registered, we use that to fetch // a schema object. // See registerSchemaCache() for more info on this. + // FIXME: Convert to Horde_Cache if ($this->_schema === null) { if ($this->_schema_cache) { $cached_schema = $this->_schema_cache->loadSchema(); - if ($cached_schema instanceof Net_LDAP2_Error) { - return $cached_schema; // route error to client - } else { - if ($cached_schema instanceof Net_LDAP2_Schema) { - $this->_schema = $cached_schema; - } + if ($cached_schema instanceof Horde_Ldap_Schema) { + $this->_schema = $cached_schema; } } } @@ -1550,143 +1485,141 @@ class Net_LDAP2 extends PEAR if ($this->_schema === null) { // store a temporary error message so subsequent calls to schema() can // detect, that we are fetching the schema already. - // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch() - $this->_schema = new Net_LDAP2_Error('Schema not initialized'); - $this->_schema = Net_LDAP2_Schema::fetch($this, $dn); + // Otherwise we will get an infinite loop at Horde_Ldap_Schema::fetch() + $this->_schema = new Horde_Ldap_Exception('Schema not initialized'); + $this->_schema = Horde_Ldap_Schema::fetch($this, $dn); // If schema caching is active, advise the cache to store the schema if ($this->_schema_cache) { $caching_result = $this->_schema_cache->storeSchema($this->_schema); - if ($caching_result instanceof Net_LDAP2_Error) { - return $caching_result; // route error to client - } } } return $this->_schema; } /** - * Enable/disable persistent schema caching - * - * Sometimes it might be useful to allow your scripts to cache - * the schema information on disk, so the schema is not fetched - * every time the script runs which could make your scripts run - * faster. - * - * This method allows you to register a custom object that - * implements your schema cache. Please see the SchemaCache interface - * (SchemaCache.interface.php) for informations on how to implement this. - * To unregister the cache, pass null as $cache parameter. - * - * For ease of use, Net_LDAP2 provides a simple file based cache - * which is used in the example below. You may use this, for example, - * to store the schema in a linux tmpfs which results in the schema - * beeing cached inside the RAM which allows nearly instant access. - * - * // Create the simple file cache object that comes along with Net_LDAP2 - * $mySchemaCache_cfg = array( - * 'path' => '/tmp/Net_LDAP2_Schema.cache', - * 'max_age' => 86400 // max age is 24 hours (in seconds) - * ); - * $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg); - * $ldap = new Net_LDAP2::connect(...); - * $ldap->registerSchemaCache($mySchemaCache); // enable caching - * // now each call to $ldap->schema() will get the schema from disk! - * - * - * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface - * - * @return true|Net_LDAP2_Error - */ + * Enable/disable persistent schema caching + * + * Sometimes it might be useful to allow your scripts to cache + * the schema information on disk, so the schema is not fetched + * every time the script runs which could make your scripts run + * faster. + * + * This method allows you to register a custom object that + * implements your schema cache. Please see the SchemaCache interface + * (SchemaCache.interface.php) for informations on how to implement this. + * To unregister the cache, pass null as $cache parameter. + * + * For ease of use, Horde_Ldap provides a simple file based cache + * which is used in the example below. You may use this, for example, + * to store the schema in a linux tmpfs which results in the schema + * beeing cached inside the RAM which allows nearly instant access. + * + * // Create the simple file cache object that comes along with Horde_Ldap + * $mySchemaCache_cfg = array( + * 'path' => '/tmp/Horde_Ldap_Schema.cache', + * 'max_age' => 86400 // max age is 24 hours (in seconds) + * ); + * $mySchemaCache = new Horde_Ldap_SimpleFileSchemaCache($mySchemaCache_cfg); + * $ldap = new Horde_Ldap::connect(...); + * $ldap->registerSchemaCache($mySchemaCache); // enable caching + * // now each call to $ldap->schema() will get the schema from disk! + * + * + * @param Horde_Ldap_SchemaCache|null $cache Object implementing the Horde_Ldap_SchemaCache interface + * + * @return true|Horde_Ldap_Error + * FIXME: Convert to Horde_Cache + */ public function registerSchemaCache($cache) { if (is_null($cache) - || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) { + || (is_object($cache) && in_array('Horde_Ldap_SchemaCache', class_implements($cache))) ) { $this->_schema_cache = $cache; return true; } else { - return new Net_LDAP2_Error('Custom schema caching object is either no '. - 'valid object or does not implement the Net_LDAP2_SchemaCache interface!'); + throw new Horde_Ldap_Exception('Custom schema caching object is either no '. + 'valid object or does not implement the Horde_Ldap_SchemaCache interface!'); } } /** - * Checks if phps ldap-extension is loaded - * - * If it is not loaded, it tries to load it manually using PHPs dl(). - * It knows both windows-dll and *nix-so. - * - * @static - * @return Net_LDAP2_Error|true - */ + * Checks if PHP's LDAP extension is loaded + * + * If it is not loaded, it tries to load it manually using PHP's dl(). + * It knows both windows-dll and *nix-so. + * + * @static + * @return true + */ public static function checkLDAPExtension() { if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { - return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package."); + throw new Horde_Ldap_Exception("Unable to locate PHP LDAP extension. Please install it before using the Horde_Ldap package."); } else { return true; } } /** - * Encodes given attributes to UTF8 if needed by schema - * - * This function takes attributes in an array and then checks against the schema if they need - * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and - * can be used for adding or modifying. - * - * $attributes is expected to be an array with keys describing - * the attribute names and the values as the value of this attribute: - * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); - * - * @param array $attributes Array of attributes - * - * @access public - * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error - */ + * Encodes given attributes to UTF8 if needed by schema + * + * This function takes attributes in an array and then checks against the schema if they need + * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and + * can be used for adding or modifying. + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); + * + * @param array $attributes Array of attributes + * + * @access public + * @return array|Horde_Ldap_Error Array of UTF8 encoded attributes or Error + */ public function utf8Encode($attributes) { return $this->utf8($attributes, 'utf8_encode'); } /** - * Decodes the given attribute values if needed by schema - * - * $attributes is expected to be an array with keys describing - * the attribute names and the values as the value of this attribute: - * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); - * - * @param array $attributes Array of attributes - * - * @access public - * @see utf8Encode() - * @return array|Net_LDAP2_Error Array with decoded attribute values or Error - */ + * Decodes the given attribute values if needed by schema + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); + * + * @param array $attributes Array of attributes + * + * @access public + * @see utf8Encode() + * @return array|Horde_Ldap_Error Array with decoded attribute values or Error + */ public function utf8Decode($attributes) { return $this->utf8($attributes, 'utf8_decode'); } /** - * Encodes or decodes attribute values if needed - * - * @param array $attributes Array of attributes - * @param array $function Function to apply to attribute values - * - * @access protected - * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error - */ + * Encodes or decodes attribute values if needed + * + * @param array $attributes Array of attributes + * @param array $function Function to apply to attribute values + * + * @access protected + * @return array|Horde_Ldap_Error Array of attributes with function applied to values or Error + */ protected function utf8($attributes, $function) { if (!is_array($attributes) || array_key_exists(0, $attributes)) { - return PEAR::raiseError('Parameter $attributes is expected to be an associative array'); + throw new Horde_Ldap_Exception('Parameter $attributes is expected to be an associative array'); } if (!$this->_schema) { $this->_schema = $this->schema(); } - if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) { + if (!$this->_link || !function_exists($function)) { return $attributes; } @@ -1696,8 +1629,9 @@ class Net_LDAP2 extends PEAR if (!isset($this->_schemaAttrs[$k])) { - $attr = $this->_schema->get('attribute', $k); - if (self::isError($attr)) { + try { + $attr = $this->_schema->get('attribute', $k); + } catch (Exception $e) { continue; } @@ -1728,13 +1662,13 @@ class Net_LDAP2 extends PEAR } /** - * Get the LDAP link resource. It will loop attempting to - * re-establish the connection if the connection attempt fails and - * auto_reconnect has been turned on (see the _config array documentation). - * - * @access public - * @return resource LDAP link - */ + * Get the LDAP link resource. It will loop attempting to + * re-establish the connection if the connection attempt fails and + * auto_reconnect has been turned on (see the _config array documentation). + * + * @access public + * @return resource LDAP link + */ public function &getLink() { if ($this->_config['auto_reconnect']) { @@ -1752,40 +1686,4 @@ class Net_LDAP2 extends PEAR } return $this->_link; } -} - -/** -* Net_LDAP2_Error implements a class for reporting portable LDAP error messages. -* -* @category Net -* @package Net_LDAP2 -* @author Tarjej Huse -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_Error extends PEAR_Error -{ - /** - * Net_LDAP2_Error constructor. - * - * @param string $message String with error message. - * @param integer $code Net_LDAP2 error code - * @param integer $mode what "error mode" to operate in - * @param mixed $level what error level to use for $mode & PEAR_ERROR_TRIGGER - * @param mixed $debuginfo additional debug info, such as the last query - * - * @access public - * @see PEAR_Error - */ - public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN, - $level = E_USER_NOTICE, $debuginfo = null) - { - if (is_int($code)) { - $this->PEAR_Error($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo); - } else { - $this->PEAR_Error("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo); - } - } -} - -?> +} \ No newline at end of file -- 2.11.0