From: Jan Schneider Date: Fri, 17 Sep 2010 11:18:26 +0000 (+0200) Subject: Cleanup X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=360f827930ea4cca6ffa4a744bee048fe619457f;p=horde.git Cleanup --- diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php index 258d702fd..9c4fc5bdb 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php @@ -66,8 +66,7 @@ implements Horde_Kolab_Server_Query_Interface { try { $filter = $this->_criteria->convert($this); - $result = $filter->asString(); - return $result; + return (string)$filter; } catch (Horde_Kolab_Server_Exception $e) { return ''; } diff --git a/framework/Ldap/lib/Horde/Ldap.php b/framework/Ldap/lib/Horde/Ldap.php index 6ac2c598c..25c50f0b8 100644 --- a/framework/Ldap/lib/Horde/Ldap.php +++ b/framework/Ldap/lib/Horde/Ldap.php @@ -131,6 +131,7 @@ class Horde_Ldap public function __construct($config = array()) { $this->setConfig($config); + $this->bind(); } /** @@ -344,7 +345,7 @@ class Horde_Ldap * If the above call failed, we try an v2 bind here and set the * version afterwards (with checking to the rootDSE). */ try { - $msg = $this->bind(); + $this->bind(); } catch (Exception $e) { /* The bind failed, discard link and save error msg. * Then record the host as down and try next one. */ @@ -524,8 +525,8 @@ class Horde_Ldap public function add(Horde_Ldap_Entry $entry) { /* Rebind as the write DN. */ - if (!empty($this->writedn)) { - $this->bind($this->writedn, $this->writepw); + if (!empty($this->_config['writedn'])) { + $this->bind($this->_config['writedn'], $this->_config['writepw']); } /* Continue attempting the add operation in a loop until we get a @@ -541,7 +542,9 @@ class Horde_Ldap if (@ldap_add($link, $entry->dn(), $entry->getValues())) { /* Entry successfully added, we should update its Horde_Ldap * reference in case it is not set so far (fresh entry). */ - if (!($entry->getLDAP() instanceof Horde_Ldap)) { + try { + $entry->getLDAP(); + } catch (Horde_Ldap_Exception $e) { $entry->setLDAP($this); } /* Store that the entry is present inside the directory. */ @@ -552,13 +555,11 @@ class Horde_Ldap /* We have a failure. What kind? We may be able to reconnect and * try again. */ $error_code = @ldap_errno($link); - $error_name = $this->errorMessage($error_code); - - if ($error_name != 'LDAP_OPERATIONS_ERROR' | + if ($this->errorName($error_code) != 'LDAP_OPERATIONS_ERROR' | !$this->_config['auto_reconnect']) { /* Errors other than the above are just passed back to the user * so he may react upon them. */ - throw new Horde_Ldap_Exception('Could not add entry ' . $entry->dn() . ' ' . $error_name, $error_code); + throw new Horde_Ldap_Exception('Could not add entry ' . $entry->dn() . ': ' . ldap_err2str($error_code), $error_code); } /* The server has disconnected before trying the operation. We @@ -586,16 +587,17 @@ class Horde_Ldap } /* Re-bind as the write DN if not using searchdn credentials. */ - if (!empty($this->writedn)) { - $this->bind($this->writedn, $this->writepw); + if (!empty($this->_config['writedn'])) { + $this->bind($this->_config['writedn'], $this->_config['writepw']); } /* Recursive delete searches for children and calls delete for them. */ if ($recursive) { $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0); - if (@ldap_count_entries($this->_link, $result)) { + if ($result && @ldap_count_entries($this->_link, $result)) { for ($subentry = @ldap_first_entry($this->_link, $result); - $subentry = @ldap_next_entry($this->_link, $subentry);) { + $subentry; + $subentry = @ldap_next_entry($this->_link, $subentry)) { $this->delete(@ldap_get_dn($this->_link, $subentry), true); } } @@ -611,7 +613,8 @@ class Horde_Ldap throw new Horde_Ldap_Exception('Could not add entry ' . $dn . ' no valid LDAP connection could be found.'); } - if (@ldap_delete($link, $dn)) { + $s = @ldap_delete($link, $dn); + if ($s) { /* Entry successfully deleted. */ return; } @@ -619,24 +622,23 @@ class Horde_Ldap /* We have a failure. What kind? We may be able to reconnect and * try again. */ $error_code = @ldap_errno($link); - $error_name = $this->errorMessage($error_code); - if ($this->errorMessage($error_code) == 'LDAP_OPERATIONS_ERROR' && + if ($this->errorName($error_code) == 'LDAP_OPERATIONS_ERROR' && $this->_config['auto_reconnect']) { /* The server has disconnected before trying the operation. We * should try again, possibly with a different server. */ $this->_link = false; $this->_reconnect(); - } elseif ($error_code == 66) { + } elseif ($this->errorName($error_code) == 'LDAP_NOT_ALLOWED_ON_NONLEAF') { /* Subentries present, server refused to delete. * Deleting subentries is the clients responsibility, but 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. */ - throw new Horde_Ldap_Exception('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.', $error_code); } else { /* Errors other than the above catched are just passed back to * the user so he may react upon them. */ - throw new Horde_Ldap_Exception('Could not delete entry ' . $dn . ' ' . $error_name, $error_code); + throw new Horde_Ldap_Exception('Could not delete entry ' . $dn . ': ' . ldap_err2str($error_code), $error_code); } } } @@ -681,8 +683,8 @@ class Horde_Ldap public function modify($entry, $parms = array()) { /* Re-bind as the write DN. */ - if (!empty($this->writedn)) { - $this->bind($this->writedn, $this->writepw); + if (!empty($this->_config['writedn'])) { + $this->bind($this->_config['writedn'], $this->_config['writepw']); } if (is_string($entry)) { @@ -711,9 +713,9 @@ class Horde_Ldap /* We have a failure. What kind? We may be able to * reconnect and try again. */ $error_code = $e->getCode(); - $error_name = $this->errorMessage($error_code); + $error_name = $this->errorName($error_code); - if ($this->errorMessage($error_code) != 'LDAP_OPERATIONS_ERROR' || + if ($this->errorName($error_code) != 'LDAP_OPERATIONS_ERROR' || !$this->_config['auto_reconnect']) { /* Errors other than the above catched are just passed * back to the user so he may react upon them. */ @@ -784,7 +786,7 @@ class Horde_Ldap } if ($filter instanceof Horde_Ldap_Filter) { /* Convert Horde_Ldap_Filter to string representation. */ - $filter = $filter->asString(); + $filter = (string)$filter; } /* Setting search parameters. */ @@ -832,27 +834,23 @@ class Horde_Ldap $sizelimit, $timelimit); - if ($err = @ldap_errno($link)) { - if ($err == 32) { - /* Errorcode 32 = no such object, i.e. a nullresult. */ - return new Horde_Ldap_Search ($search, $this, $attributes); + if ($errno = @ldap_errno($link)) { + $err = $this->errorName($errno); + if ($err == 'LDAP_NO_SUCH_OBJECT' || + $err == 'LDAP_SIZELIMIT_EXCEEDED') { + return new Horde_Ldap_Search($search, $this, $attributes); } - if ($err == 4) { - /* Errorcode 4 = sizelimit exeeded. */ - return new Horde_Ldap_Search ($search, $this, $attributes); - } - if ($err == 87) { + if ($err == 'LDAP_FILTER_ERROR') { /* Bad search filter. */ - throw new Horde_Ldap_Exception($this->errorMessage($err) . '($filter)', $err); + throw new Horde_Ldap_Exception(ldap_err2str($errno) . ' ($filter)', $errno); } - if (($err == 1) && ($this->_config['auto_reconnect'])) { - /* Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a - * reconnect. */ + if ($err == 'LDAP_OPERATIONS_ERROR' && + $this->_config['auto_reconnect']) { $this->_link = false; $this->_reconnect(); } else { $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope"; - throw new Horde_Ldap_Exception($this->errorMessage($err) . $msg, $err); + throw new Horde_Ldap_Exception(ldap_err2str($errno) . $msg, $errno); } } else { return new Horde_Ldap_Search($search, $this, $attributes); @@ -881,12 +879,9 @@ class Horde_Ldap } $err = @ldap_errno($this->_link); if ($err) { - $msg = @ldap_err2str($err); - } else { - $err = 1000; - $msg = $this->errorMessage($err); + throw new Horde_Ldap_Exception(ldap_err2str($err), $err); } - throw new Horde_Ldap_Exception($msg, $err); + throw new Horde_Ldap_Exception('Unknown error'); } /** @@ -910,12 +905,9 @@ class Horde_Ldap } $err = @ldap_errno($this->_link); if ($err) { - $msg = @ldap_err2str($err); - } else { - $err = 1000; - $msg = $this->errorMessage($err); + throw new Horde_Ldap_Exception(ldap_err2str($err), $err); } - throw new Horde_Ldap_Exception($msg, $err); + throw new Horde_Ldap_Exception('Unknown error'); } /** @@ -956,10 +948,10 @@ class Horde_Ldap /* 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 Horde_Ldap_RootDSE::fetch() seems - * like a problem at copiyng the object inside PHP?? - * Additionally, this is not always reproducable... */ + * TODO: Why is this so horribly slow? $this->rootDSE() is very fast, + * as well as Horde_Ldap_RootDse(). Seems like a problem at copying the + * object inside PHP?? Additionally, this is not always + * reproducable... */ if (!$force) { $rootDSE = $this->rootDSE(); $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); @@ -968,6 +960,7 @@ class Horde_Ldap } $check_ok = in_array($version, $supported_versions); } + $check_ok = true; if ($force || $check_ok) { return $this->setOption('LDAP_OPT_PROTOCOL_VERSION', $version); @@ -1009,11 +1002,11 @@ class Horde_Ldap if (@ldap_count_entries($this->_link, $result)) { return true; } - if (ldap_errno($this->_link) == 32) { + if ($this->errorName(@ldap_errno($this->_link)) == 'LDAP_NO_SUCH_OBJECT') { return false; } - if (ldap_errno($this->_link) != 0) { - throw new Horde_Ldap_Exception(ldap_error($this->_link), ldap_errno($this->_link)); + if (@ldap_errno($this->_link)) { + throw new Horde_Ldap_Exception(@ldap_error($this->_link), @ldap_errno($this->_link)); } return false; } @@ -1161,7 +1154,7 @@ class Horde_Ldap * * @return string The description for the error. */ - public function errorMessage($errorcode) + public static function errorName($errorcode) { $errorMessages = array( 0x00 => 'LDAP_SUCCESS', @@ -1240,7 +1233,7 @@ class Horde_Ldap * * @param array $attrs Array of attributes to search for. * - * @return Horde_Ldap_RootDSE Horde_Ldap_RootDSE object + * @return Horde_Ldap_RootDse Horde_Ldap_RootDse object * @throws Horde_Ldap_Exception */ public function rootDSE(array $attrs = array()) @@ -1250,7 +1243,7 @@ class Horde_Ldap /* See if we need to fetch a fresh object, or if we already * requested this object with the same attributes. */ if (!isset($this->_rootDSECache[$attrs_signature])) { - $this->_rootDSECache[$attrs_signature] = Horde_Ldap_RootDSE::fetch($this, $attrs); + $this->_rootDSECache[$attrs_signature] = new Horde_Ldap_RootDse($this, $attrs); } return $this->_rootDSECache[$attrs_signature]; @@ -1286,9 +1279,9 @@ class Horde_Ldap /* 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 - * Horde_Ldap_Schema::fetch(). */ + * Horde_Ldap_Schema. */ $this->_schema = new Horde_Ldap_Exception('Schema not initialized'); - $this->_schema = Horde_Ldap_Schema::fetch($this, $dn); + $this->_schema = new Horde_Ldap_Schema($this, $dn); /* If schema caching is active, advise the cache to store * the schema. */ diff --git a/framework/Ldap/lib/Horde/Ldap/Entry.php b/framework/Ldap/lib/Horde/Ldap/Entry.php index 9ec6c3193..fb8387b19 100644 --- a/framework/Ldap/lib/Horde/Ldap/Entry.php +++ b/framework/Ldap/lib/Horde/Ldap/Entry.php @@ -277,7 +277,11 @@ class Horde_Ldap_Entry is_resource($this->_link)) { /* Fetch schema. */ if ($this->_ldap instanceof Horde_Ldap) { - $schema = $this->_ldap->schema(); + try { + $schema = $this->_ldap->schema(); + } catch (Horde_Ldap_Exception $e) { + $schema = null; + } } /* Fetch attributes. */ @@ -626,9 +630,6 @@ class Horde_Ldap_Entry { /* Ensure we have a valid LDAP object. */ $ldap = $this->getLDAP(); - if (!($ldap instanceof Horde_Ldap)) { - throw new Horde_Ldap_Exception('The entries LDAP object is not valid'); - } /* Get and check link. */ $link = $ldap->getLink(); @@ -742,7 +743,7 @@ class Horde_Ldap_Entry public function getLDAP() { if (!($this->_ldap instanceof Horde_Ldap)) { - throw new Horde_Ldap_Exception('LDAP is not a valid Horde_Ldap object'); + throw new Horde_Ldap_Exception('ldap property is not a valid Horde_Ldap object'); } return $this->_ldap; } diff --git a/framework/Ldap/lib/Horde/Ldap/Filter.php b/framework/Ldap/lib/Horde/Ldap/Filter.php index cc8aa8508..de84c238c 100644 --- a/framework/Ldap/lib/Horde/Ldap/Filter.php +++ b/framework/Ldap/lib/Horde/Ldap/Filter.php @@ -1,481 +1,415 @@ - * @author Ben Klang - * @copyright 2009 Benedikt Hallinger, The Horde Project - * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 - */ - -/** - * Includes - */ -#require_once 'PEAR.php'; -#require_once 'Util.php'; - -/** - * Object representation of a part of a LDAP filter. + * A filter is built using several independent filter objects which are + * combined afterwards. This object works in two modes, depending how the + * object is created. * - * This Class is not completely compatible to the PERL interface! + * If the object is created using the {@link create()} method, then this is a + * leaf-object. If the object is created using the {@link combine()} method, + * then this is a container object. * - * The purpose of this class is, that users can easily build LDAP filters - * without having to worry about right escaping etc. - * A Filter is built using several independent filter objects - * which are combined afterwards. This object works in two - * modes, depending how the object is created. - * If the object is created using the {@link create()} method, then this is a leaf-object. - * If the object is created using the {@link combine()} method, then this is a container object. + * LDAP filters are defined in RFC 2254. * - * LDAP filters are defined in RFC-2254 and can be found under - * {@link http://www.ietf.org/rfc/rfc2254.txt} + * @see http://www.ietf.org/rfc/rfc2254.txt * - * Here a quick copy&paste example: + * A short example: * - * $filter0 = Horde_Ldap_Filter::create('stars', 'equals', '***'); + * $filter0 = Horde_Ldap_Filter::create('stars', 'equals', '***'); * $filter_not0 = Horde_Ldap_Filter::combine('not', $filter0); * - * $filter1 = Horde_Ldap_Filter::create('gn', 'begins', 'bar'); - * $filter2 = Horde_Ldap_Filter::create('gn', 'ends', 'baz'); - * $filter_comp = Horde_Ldap_Filter::combine('or',array($filter_not0, $filter1, $filter2)); + * $filter1 = Horde_Ldap_Filter::create('gn', 'begins', 'bar'); + * $filter2 = Horde_Ldap_Filter::create('gn', 'ends', 'baz'); + * $filter_comp = Horde_Ldap_Filter::combine('or', array($filter_not0, $filter1, $filter2)); * - * echo $filter_comp->asString(); - * // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar *)(gn= *baz)) + * echo (string)$filter_comp; + * // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz)) * // The stars in $filter0 are treaten as real stars unless you disable escaping. * * - * @category Net - * @package Horde_Ldap - * @author Benedikt Hallinger - * @license http://www.gnu.org/copyleft/lesser.html LGPL - * @link http://pear.php.net/package/Horde_Ldap/ + * @category Horde + * @package Ldap + * @author Benedikt Hallinger + * @author Jan Schneider + * @copyright 2009 Benedikt Hallinger + * @copyright 2010 The Horde Project + * @license http://www.gnu.org/copyleft/lesser.html LGPL */ -class Horde_Ldap_Filter extends PEAR +class Horde_Ldap_Filter { /** - * Storage for combination of filters + * Storage for combination of filters. * - * This variable holds a array of filter objects - * that should be combined by this filter object. + * This variable holds a array of filter objects that should be combined by + * this filter object. * - * @access protected * @var array */ - protected $_subfilters = array(); + protected $_filters = array(); /** - * Match of this filter + * Operator for sub-filters. * - * If this is a leaf filter, then a matching rule is stored, - * if it is a container, then it is a logical operator - * - * @access protected * @var string */ - protected $_match; + protected $_operator; /** - * Single filter + * Single filter. * - * If we operate in leaf filter mode, - * then the constructing method stores - * the filter representation here + * If this is a leaf filter, the filter representation is store here. * - * @acces private * @var string */ protected $_filter; /** - * Create a new Horde_Ldap_Filter object and parse $filter. + * Constructor. * - * This is for PERL Net::LDAP interface. * Construction of Horde_Ldap_Filter objects should happen through either * {@link create()} or {@link combine()} which give you more control. - * However, you may use the perl iterface if you already have generated filters. - * - * @param string $filter LDAP filter string + * However, you may use the constructor if you already have generated + * filters. * - * @see parse() + * @param array $params List of object parameters */ - public function __construct($filter = false) + protected function __construct(array $params) { - // The optional parameter must remain here, because otherwise create() crashes - if (false !== $filter) { - $filter_o = self::parse($filter); - if (PEAR::isError($filter_o)) { - $this->_filter = $filter_o; // assign error, so asString() can report it - } else { - $this->_filter = $filter_o->asString(); + foreach ($params as $param => $value) { + if (in_array($param, array('filter', 'filters', 'operator'))) { + $this->{'_' . $param} = $value; } } } /** - * Constructor of a new part of a LDAP filter. + * Creates a new part of an LDAP filter. * * The following matching rules exists: - * - equals: One of the attributes values is exactly $value - * Please note that case sensitiviness is depends on the - * attributes syntax configured in the server. - * - begins: One of the attributes values must begin with $value - * - ends: One of the attributes values must end with $value - * - contains: One of the attributes values must contain $value - * - present | any: The attribute can contain any value but must be existent - * - greater: The attributes value is greater than $value - * - less: The attributes value is less than $value - * - greaterOrEqual: The attributes value is greater or equal than $value - * - lessOrEqual: The attributes value is less or equal than $value - * - approx: One of the attributes values is similar to $value - * - * If $escape is set to true (default) then $value will be escaped - * properly. If it is set to false then $value will be treaten as raw filter value string. - * You should escape yourself using {@link Horde_Ldap_Util::escape_filter_value()}! + * - equals: One of the attributes values is exactly $value. + * Please note that case sensitiviness depends on the + * attributes syntax configured in the server. + * - begins: One of the attributes values must begin with $value. + * - ends: One of the attributes values must end with $value. + * - contains: One of the attributes values must contain $value. + * - present | any: The attribute can contain any value but must exist. + * - greater: The attributes value is greater than $value. + * - less: The attributes value is less than $value. + * - greaterOrEqual: The attributes value is greater or equal than $value. + * - lessOrEqual: The attributes value is less or equal than $value. + * - approx: One of the attributes values is similar to $value. + * + * If $escape is set to true then $value will be escaped. If set to false + * then $value will be treaten as a raw filter value string. You should + * then escape it yourself using {@link + * Horde_Ldap_Util::escape_filter_value()}. * * Examples: * - * // This will find entries that contain an attribute "sn" that ends with "foobar": - * $filter = new Horde_Ldap_Filter('sn', 'ends', 'foobar'); + * // This will find entries that contain an attribute "sn" that ends with + * // "foobar": + * $filter = Horde_Ldap_Filter::create('sn', 'ends', 'foobar'); * - * // This will find entries that contain an attribute "sn" that has any value set: - * $filter = new Horde_Ldap_Filter('sn', 'any'); + * // This will find entries that contain an attribute "sn" that has any + * // value set: + * $filter = Horde_Ldap_Filter::create('sn', 'any'); * * - * @param string $attr_name Name of the attribute the filter should apply to - * @param string $match Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any) - * @param string $value (optional) if given, then this is used as a filter - * @param boolean $escape Should $value be escaped? (default: yes, see {@link Horde_Ldap_Util::escape_filter_value()} for detailed information) + * @param string $attribute Name of the attribute the filter should apply + * to. + * @param string $match Matching rule (equals, begins, ends, contains, + * greater, less, greaterOrEqual, lessOrEqual, + * approx, any). + * @param string $value If given, then this is used as a filter value. + * @param boolean $escape Should $value be escaped? * - * @return Horde_Ldap_Filter|Horde_Ldap_Error + * @return Horde_Ldap_Filter + * @throws Horde_Ldap_Exception */ - public static function &create($attr_name, $match, $value = '', $escape = true) + public static function create($attribute, $match, $value = '', + $escape = true) { - $leaf_filter = new Horde_Ldap_Filter(); if ($escape) { $array = Horde_Ldap_Util::escape_filter_value(array($value)); $value = $array[0]; } - switch (strtolower($match)) { + + switch (Horde_String::lower($match)) { case 'equals': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')'; + $filter = '(' . $attribute . '=' . $value . ')'; break; case 'begins': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)'; + $filter = '(' . $attribute . '=' . $value . '*)'; break; case 'ends': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')'; + $filter = '(' . $attribute . '=*' . $value . ')'; break; case 'contains': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)'; + $filter = '(' . $attribute . '=*' . $value . '*)'; break; case 'greater': - $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')'; + $filter = '(' . $attribute . '>' . $value . ')'; break; case 'less': - $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')'; + $filter = '(' . $attribute . '<' . $value . ')'; break; case 'greaterorequal': case '>=': - $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')'; + $filter = '(' . $attribute . '>=' . $value . ')'; break; case 'lessorequal': case '<=': - $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')'; + $filter = '(' . $attribute . '<=' . $value . ')'; break; case 'approx': case '~=': - $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')'; + $filter = '(' . $attribute . '~=' . $value . ')'; break; case 'any': - case 'present': // alias that may improve user code readability - $leaf_filter->_filter = '(' . $attr_name . '=*)'; + case 'present': + $filter = '(' . $attribute . '=*)'; break; default: - throw new Horde_Ldap_Exception('Horde_Ldap_Filter create error: matching rule "' . $match . '" not known!'); + throw new Horde_Ldap_Exception('Matching rule "' . $match . '" unknown'); } - return $leaf_filter; + + return new Horde_Ldap_Filter(array('filter' => $filter)); + } /** - * Combine two or more filter objects using a logical operator + * Combines two or more filter objects using a logical operator. + * + * Example: + * + * $filter = Horde_Ldap_Filter::combine('or', array($filter1, $filter2)); + * * - * This static method combines two or more filter objects and returns one single - * filter object that contains all the others. - * Call this method statically: $filter = Horde_Ldap_Filter('or', array($filter1, $filter2)) - * If the array contains filter strings instead of filter objects, we will try to parse them. + * If the array contains filter strings instead of filter objects, they + * will be parsed. * - * @param string $log_op The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!" - * @param array|Horde_Ldap_Filter $filters array with Horde_Ldap_Filter objects + * @param string $operator + * The logical operator, either "and", "or", "not" or the logical + * equivalents "&", "|", "!". + * @param array|Horde_Ldap_Filter|string $filters + * Array with Horde_Ldap_Filter objects and/or strings or a single + * filter when using the "not" operator. * - * @return Horde_Ldap_Filter|Horde_Ldap_Error - * @static + * @return Horde_Ldap_Filter + * @throws Horde_Ldap_Exception */ - public static function &combine($log_op, $filters) + public static function combine($operator, $filters) { - // substitude named operators to logical operators - if ($log_op == 'and') $log_op = '&'; - if ($log_op == 'or') $log_op = '|'; - if ($log_op == 'not') $log_op = '!'; + // Substitute named operators with logical operators. + switch ($operator) { + case 'and': $operator = '&'; break; + case 'or': $operator = '|'; break; + case 'not': $operator = '!'; break; + } - // tests for sane operation - if ($log_op == '!') { - // Not-combination, here we only accept one filter object or filter string + // Tests for sane operation. + switch ($operator) { + case '!': + // Not-combination, here we only accept one filter object or filter + // string. if ($filters instanceof Horde_Ldap_Filter) { $filters = array($filters); // force array } elseif (is_string($filters)) { - try { - $filter_o = self::parse($filters); - } catch (Exception $e) { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: '.$e->getMessage()); - } - $filters = array($filter_o); + $filters = array(self::parse($filters)); } elseif (is_array($filters)) { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: operator is "not" but $filter is an array!'); + throw new Horde_Ldap_Exception('Operator is "not" but $filter is an array'); } else { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: operator is "not" but $filter is not a valid Horde_Ldap_Filter nor a filter string!'); + throw new Horde_Ldap_Exception('Operator is "not" but $filter is not a valid Horde_Ldap_Filter nor a filter string'); } - } elseif ($log_op == '&' || $log_op == '|') { + break; + + case '&': + case '|': if (!is_array($filters) || count($filters) < 2) { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: parameter $filters is not an array or contains less than two Horde_Ldap_Filter objects!'); + throw new Horde_Ldap_Exception('Parameter $filters is not an array or contains less than two Horde_Ldap_Filter objects'); } - } else { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: logical operator is not known!'); + break; + + default: + throw new Horde_Ldap_Exception('Logical operator is unknown'); } - $combined_filter = new Horde_Ldap_Filter(); - foreach ($filters as $key => $testfilter) { // check for errors + foreach ($filters as $key => $testfilter) { + // Check for errors. if (is_string($testfilter)) { - // string found, try to parse into an filter object - $filter_o = self::parse($testfilter); - $filters[$key] = $filter_o; - } elseif (!$testfilter instanceof Horde_Ldap_Filter) { - throw new Horde_Ldap_Exception('Horde_Ldap_Filter combine error: invalid object passed in array $filters!'); + // String found, try to parse into an filter object. + $filters[$key] = self::parse($testfilter); + } elseif (!($testfilter instanceof Horde_Ldap_Filter)) { + throw new Horde_Ldap_Exception('Invalid object passed in array $filters!'); } } - $combined_filter->_subfilters = $filters; - $combined_filter->_match = $log_op; - return $combined_filter; + return new Horde_Ldap_Filter(array('filters' => $filters, + 'operator' => $operator)); } /** - * Parse FILTER into a Horde_Ldap_Filter object + * Parses a string into a Horde_Ldap_Filter object. * - * This parses an filter string into Horde_Ldap_Filter objects. + * @todo Leaf-mode: Do we need to escape at all? what about *-chars? Check + * for the need of encoding values, tackle problems (see code comments). * - * @param string $FILTER The filter string + * @param string $filter An LDAP filter string. * - * @access static - * @return Horde_Ldap_Filter|Horde_Ldap_Error - * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments) + * @return Horde_Ldap_Filter + * @throws Horde_Ldap_Exception */ - public static function parse($FILTER) + public static function parse($filter) { - if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) { - if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) { - // Subfilter processing: pass subfilters to parse() and combine - // the objects using the logical operator detected - // we have now something like "&(...)(...)(...)" but at least one part ("!(...)"). - // Each subfilter could be an arbitary complex subfilter. - - // extract logical operator and filter arguments - $log_op = substr($matches[1], 0, 1); - $remaining_component = substr($matches[1], 1); - - // split $remaining_component into individual subfilters - // we cannot use split() for this, because we do not know the - // complexiness of the subfilter. Thus, we look trough the filter - // string and just recognize ending filters at the first level. - // We record the index number of the char and use that information - // later to split the string. - $sub_index_pos = array(); - $prev_char = ''; // previous character looked at - $level = 0; // denotes the current bracket level we are, - // >1 is too deep, 1 is ok, 0 is outside any - // subcomponent - for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) { - $cur_char = substr($remaining_component, $curpos, 1); - - // rise/lower bracket level - if ($cur_char == '(' && $prev_char != '\\') { - $level++; - } elseif ($cur_char == ')' && $prev_char != '\\') { - $level--; - } - - if ($cur_char == '(' && $prev_char == ')' && $level == 1) { - array_push($sub_index_pos, $curpos); // mark the position for splitting - } - $prev_char = $cur_char; - } - - // now perform the splits. To get also the last part, we - // need to add the "END" index to the split array - array_push($sub_index_pos, strlen($remaining_component)); - $subfilters = array(); - $oldpos = 0; - foreach ($sub_index_pos as $s_pos) { - $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos); - array_push($subfilters, $str_part); - $oldpos = $s_pos; - } - - // some error checking... - if (count($subfilters) == 1) { - // only one subfilter found - } elseif (count($subfilters) > 1) { - // several subfilters found - if ($log_op == "!") { - throw new Horde_Ldap_Exception("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!"); - } - } else { - // this should not happen unless the user specified a wrong filter - throw new Horde_Ldap_Exception("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!"); - } - - // Now parse the subfilters into objects and combine them using the operator - $subfilters_o = array(); - foreach ($subfilters as $s_s) { - $o = self::parse($s_s); - array_push($subfilters_o, self::parse($s_s)); - } - - $filter_o = self::combine($log_op, $subfilters_o); - return $filter_o; - - } else { - // This is one leaf filter component, do some syntax checks, then escape and build filter_o - // $matches[1] should be now something like "foo=bar" + if (!preg_match('/^\((.+?)\)$/', $filter, $matches)) { + throw new Horde_Ldap_Exception('Invalid filter syntax, filter components must be enclosed in round brackets'); + } - // detect multiple leaf components - // [TODO] Maybe this will make problems with filters containing brackets inside the value - if (stristr($matches[1], ')(')) { - throw new Horde_Ldap_Exception("Filter parsing error: invalid filter syntax - multiple leaf components detected!"); - } else { - $filter_parts = preg_split('/(?|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE); - if (count($filter_parts) != 3) { - throw new Horde_Ldap_Exception("Filter parsing error: invalid filter syntax - unknown matching rule used"); - } else { - $filter_o = new Horde_Ldap_Filter(); - // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special? - // I think, those prevent escaping! We need to check against PERL Net::LDAP! - // $value_arr = Horde_Ldap_Util::escape_filter_value(array($filter_parts[2])); - // $value = $value_arr[0]; - $value = $filter_parts[2]; - $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')'; - return $filter_o; - } - } - } + if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) { + return self::_parseCombination($matches[1]); } else { - // ERROR: Filter components must be enclosed in round brackets - throw new Horde_Ldap_Exception("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets"); + return self::_parseLeaf($matches[1]); } } /** - * Get the string representation of this filter + * Parses combined subfilter strings. * - * This method runs through all filter objects and creates - * the string representation of the filter. If this - * filter object is a leaf filter, then it will return - * the string representation of this filter. + * Passes subfilters to parse() and combines the objects using the logical + * operator detected. Each subfilter could be an arbitary complex + * subfilter. * - * @return string|Horde_Ldap_Error + * @param string $filter An LDAP filter string. + * + * @return Horde_Ldap_Filter + * @throws Horde_Ldap_Exception */ - public function asString() + protected static function _parseCombination($filter) { - if ($this->isLeaf()) { - $return = $this->_filter; - } else { - $return = ''; - foreach ($this->_subfilters as $filter) { - $return = $return.$filter->asString(); + // Extract logical operator and filter arguments. + $operator = substr($filter, 0, 1); + $filter = substr($filter, 1); + + // Split $filter into individual subfilters. We cannot use split() for + // this, because we do not know the complexiness of the + // subfilter. Thus, we look trough the filter string and just recognize + // ending filters at the first level. We record the index number of the + // char and use that information later to split the string. + $sub_index_pos = array(); + // Previous character looked at. + $prev_char = ''; + // Denotes the current bracket level we are, >1 is too deep, 1 is ok, 0 + // is outside any subcomponent. + $level = 0; + for ($curpos = 0; $curpos < strlen($filter); $curpos++) { + $cur_char = $filter{$curpos}; + + // Rise/lower bracket level. + if ($cur_char == '(' && $prev_char != '\\') { + $level++; + } elseif ($cur_char == ')' && $prev_char != '\\') { + $level--; + } + + if ($cur_char == '(' && $prev_char == ')' && $level == 1) { + // Mark the position for splitting. + array_push($sub_index_pos, $curpos); } - $return = '(' . $this->_match . $return . ')'; + $prev_char = $cur_char; } - return $return; - } - /** - * Alias for perl interface as_string() - * - * @see asString() - * @return string|Horde_Ldap_Error - */ - public function as_string() - { - return $this->asString(); - } + // Now perform the splits. To get the last part too, we need to add the + // "END" index to the split array. + array_push($sub_index_pos, strlen($filter)); + $subfilters = array(); + $oldpos = 0; + foreach ($sub_index_pos as $s_pos) { + $str_part = substr($filter, $oldpos, $s_pos - $oldpos); + array_push($subfilters, $str_part); + $oldpos = $s_pos; + } - /** - * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given - * - * This method is only for compatibility to the perl interface. - * However, the original method was called "print" but due to PHP language restrictions, - * we can't have a print() method. - * - * @param resource $FH (optional) A filehandle resource - * - * @return true|Horde_Ldap_Error - */ - public function printMe($FH = false) - { - if (!is_resource($FH)) { - $filter_str = $this->asString(); - print($filter_str); - } else { - $filter_str = $this->asString(); - $res = @fwrite($FH, $this->asString()); - if ($res == false) { - throw new Horde_Ldap_Exception("Unable to write filter string to filehandle \$FH!"); + // Some error checking... + if (count($subfilters) == 1) { + // Only one subfilter found. + } elseif (count($subfilters) > 1) { + // Several subfilters found. + if ($operator == '!') { + throw new Horde_Ldap_Exception('Invalid filter syntax: NOT operator detected but several arguments given'); } + } else { + // This should not happen unless the user specified a wrong filter. + throw new Horde_Ldap_Exception('Invalid filter syntax: got operator ' . $operator . ' but no argument'); + } + + // Now parse the subfilters into objects and combine them using the + // operator. + $subfilters_o = array(); + foreach ($subfilters as $s_s) { + $o = self::parse($s_s); + array_push($subfilters_o, self::parse($s_s)); + } + if (count($subfilters_o) == 1) { + $subfilters_o = $subfilters_o[0]; } - return true; + + return self::combine($operator, $subfilters_o); } /** - * This can be used to escape a string to provide a valid LDAP-Filter. - * - * LDAP will only recognise certain characters as the - * character istself if they are properly escaped. This is - * what this method does. - * The method can be called statically, so you can use it outside - * for your own purposes (eg for escaping only parts of strings) + * Parses a single leaf component. * - * In fact, this is just a shorthand to {@link Horde_Ldap_Util::escape_filter_value()}. - * For upward compatibiliy reasons you are strongly encouraged to use the escape - * methods provided by the Horde_Ldap_Util class. + * @param string $filter An LDAP filter string. * - * @param string $value Any string who should be escaped - * - * @static - * @return string The string $string, but escaped - * @deprecated Do not use this method anymore, instead use Horde_Ldap_Util::escape_filter_value() directly + * @return Horde_Ldap_Filter + * @throws Horde_Ldap_Exception */ - public static function escape($value) + protected static function _parseLeaf($filter) { - $return = Horde_Ldap_Util::escape_filter_value(array($value)); - return $return[0]; + // Detect multiple leaf components. + // [TODO] Maybe this will make problems with filters containing + // brackets inside the value. + if (strpos($filter, ')(')) { + throw new Horde_Ldap_Exception('Invalid filter syntax: multiple leaf components detected'); + } + + $filter_parts = preg_split('/(?|<|>=|<=)/', $filter, 2, PREG_SPLIT_DELIM_CAPTURE); + if (count($filter_parts) != 3) { + throw new Horde_Ldap_Exception('Invalid filter syntax: unknown matching rule used'); + } + + // [TODO]: Do we need to escape at all? what about *-chars user provide + // and that should remain special? I think, those prevent + // escaping! We need to check against PERL Net::LDAP! + // $value_arr = Horde_Ldap_Util::escape_filter_value(array($filter_parts[2])); + // $value = $value_arr[0]; + + return new Horde_Ldap_Filter(array('filter' => '(' . $filter_parts[0] . $filter_parts[1] . $filter_parts[2] . ')')); } /** - * Is this a container or a leaf filter object? + * Returns the string representation of this filter. + * + * This method runs through all filter objects and creates the string + * representation of the filter. * - * @access protected - * @return boolean + * @return string */ - protected function isLeaf() + public function __toString() { - if (count($this->_subfilters) > 0) { - return false; // Container! - } else { - return true; // Leaf! + if (!count($this->_filters)) { + return $this->_filter; + } + + $return = ''; + foreach ($this->_filters as $filter) { + $return .= (string)$filter; } + + return '(' . $this->_operator . $return . ')'; } } -?> diff --git a/framework/Ldap/lib/Horde/Ldap/Ldif.php b/framework/Ldap/lib/Horde/Ldap/Ldif.php index 96e2fa2cc..e90a87d1c 100644 --- a/framework/Ldap/lib/Horde/Ldap/Ldif.php +++ b/framework/Ldap/lib/Horde/Ldap/Ldif.php @@ -36,7 +36,7 @@ * @see http://www.ietf.org/rfc/rfc2849.txt * @todo LDAPv3 controls are not implemented yet */ -class Horde_Ldap_LDIF +class Horde_Ldap_Ldif { /** * Options. @@ -183,7 +183,7 @@ class Horde_Ldap_LDIF return; } - switch ($imode) { + switch ($mode) { case 'r': if (!file_exists($file)) { throw new Horde_Ldap_Exception('Unable to open ' . $file . ' for reading: file not found'); diff --git a/framework/Ldap/lib/Horde/Ldap/RootDse.php b/framework/Ldap/lib/Horde/Ldap/RootDse.php index 31b5e690c..0b7d35da4 100644 --- a/framework/Ldap/lib/Horde/Ldap/RootDse.php +++ b/framework/Ldap/lib/Horde/Ldap/RootDse.php @@ -1,64 +1,36 @@ + * @author Jan Schneider * @copyright 2009 Jan Wagner - * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 - * @version SVN: $Id: RootDSE.php 286718 2009-08-03 07:30:49Z beni $ - * @link http://pear.php.net/package/Horde_Ldap/ - */ - -/** - * Includes - */ -#require_once 'PEAR.php'; - -/** - * Getting the rootDSE entry of a LDAP server - * - * @category Net - * @package Horde_Ldap - * @author Jan Wagner - * @license http://www.gnu.org/copyleft/lesser.html LGPL - * @link http://pear.php.net/package/Horde_Ldap2/ + * @copyright 2010 The Horde Project + * @license http://www.gnu.org/copyleft/lesser.html LGPL */ -class Horde_Ldap_RootDSE +class Horde_Ldap_RootDse { /** - * @access protected * @var object Horde_Ldap_Entry - **/ - protected $_entry; - - /** - * Class constructor - * - * @param Horde_Ldap_Entry &$entry Horde_Ldap_Entry object of the RootDSE */ - protected function __construct(&$entry) - { - $this->_entry = $entry; - } + protected $_entry; /** - * Fetches a RootDSE object from an LDAP connection + * Constructor. * - * @param Horde_Ldap $ldap Directory from which the RootDSE should be fetched - * @param array $attrs Array of attributes to search for + * Fetches a RootDSE object from an LDAP connection. * - * @access static - * @return Horde_Ldap_RootDSE + * @param Horde_Ldap $ldap Directory from which the RootDSE should be + * fetched. + * @param array $attrs Array of attributes to search for. * * @throws Horde_Ldap_Exception */ - public static function fetch(Horde_Ldap $ldap, $attrs = null) + public function __construct(Horde_Ldap $ldap, $attrs = null) { - if (is_array($attrs) && count($attrs) > 0 ) { + if (is_array($attrs) && count($attrs)) { $attributes = $attrs; } else { $attributes = array('vendorName', @@ -69,52 +41,39 @@ class Horde_Ldap_RootDSE 'supportedControl', 'supportedSASLMechanisms', 'supportedLDAPVersion', - 'subschemaSubentry' ); + 'subschemaSubentry'); } - $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base')); + $result = $ldap->search('', '(objectClass=*)', + array('attributes' => $attributes, + 'scope' => 'base')); $entry = $result->shiftEntry(); - if (false === $entry) { + if (!$entry) { throw new Horde_Ldap_Exception('Could not fetch RootDSE entry'); } - $ret = new Horde_Ldap_RootDSE($entry); - return $ret; + $this->_entry = $entry; } /** - * Gets the requested attribute value - * - * Same usuage as {@link Horde_Ldap_Entry::getValue()} + * Returns the requested attribute value. * - * @param string $attr Attribute name - * @param array $options Array of options + * @see Horde_Ldap_Entry::getValue() * - * @access public - * @return mixed Horde_Ldap_Error object or attribute values - * @see Horde_Ldap_Entry::get_value() - */ - public function getValue($attr = '', $options = '') - { - return $this->_entry->get_value($attr, $options); - } - - /** - * Alias function of getValue() for perl-ldap interface + * @param string $attr Attribute name. + * @param array $options Array of options. * - * @see getValue() - * @return mixed + * @return string|array Attribute value(s). + * @throws Horde_Ldap_Exception */ - public function get_value() + public function getValue($attr, $options = '') { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'getValue' ), $args); + return $this->_entry->getValue($attr, $options); } /** - * Determines if the extension is supported + * Determines if the extension is supported. * - * @param array $oids Array of oids to check + * @param array $oids Array of OIDs to check. * - * @access public * @return boolean */ public function supportedExtension($oids) @@ -123,23 +82,10 @@ class Horde_Ldap_RootDSE } /** - * Alias function of supportedExtension() for perl-ldap interface + * Determines if the version is supported. * - * @see supportedExtension() - * @return boolean - */ - public function supported_extension() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'supportedExtension'), $args); - } - - /** - * Determines if the version is supported + * @param array $versions Versions to check. * - * @param array $versions Versions to check - * - * @access public * @return boolean */ public function supportedVersion($versions) @@ -148,23 +94,10 @@ class Horde_Ldap_RootDSE } /** - * Alias function of supportedVersion() for perl-ldap interface - * - * @see supportedVersion() - * @return boolean - */ - public function supported_version() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedVersion'), $args); - } - - /** - * Determines if the control is supported + * Determines if the control is supported. * - * @param array $oids Control oids to check + * @param array $oids Control OIDs to check. * - * @access public * @return boolean */ public function supportedControl($oids) @@ -173,23 +106,10 @@ class Horde_Ldap_RootDSE } /** - * Alias function of supportedControl() for perl-ldap interface + * Determines if the sasl mechanism is supported. * - * @see supportedControl() - * @return boolean - */ - public function supported_control() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedControl' ), $args); - } - - /** - * Determines if the sasl mechanism is supported + * @param array $mechlist SASL mechanisms to check. * - * @param array $mechlist SASL mechanisms to check - * - * @access public * @return boolean */ public function supportedSASLMechanism($mechlist) @@ -198,37 +118,25 @@ class Horde_Ldap_RootDSE } /** - * Alias function of supportedSASLMechanism() for perl-ldap interface + * Checks for existance of value in attribute. * - * @see supportedSASLMechanism() - * @return boolean - */ - public function supported_sasl_mechanism() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args); - } - - /** - * Checks for existance of value in attribute - * - * @param array $values values to check - * @param string $attr attribute name + * @param array $values Values to check. + * @param string $attr Attribute name. * - * @access protected * @return boolean */ protected function checkAttr($values, $attr) { - if (!is_array($values)) $values = array($values); + if (!is_array($values)) { + $values = array($values); + } foreach ($values as $value) { - if (!@in_array($value, $this->get_value($attr, 'all'))) { + if (!in_array($value, $this->get_value($attr, 'all'))) { return false; } } + return true; } } - -?> diff --git a/framework/Ldap/lib/Horde/Ldap/Schema.php b/framework/Ldap/lib/Horde/Ldap/Schema.php index 26e95c26d..eb56f444b 100644 --- a/framework/Ldap/lib/Horde/Ldap/Schema.php +++ b/framework/Ldap/lib/Horde/Ldap/Schema.php @@ -1,36 +1,5 @@ - * @author Benedikt Hallinger - * @copyright 2009 Jan Wagner, Benedikt Hallinger - * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 - * @version SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $ - * @link http://pear.php.net/package/Horde_Ldap/ - * @todo see the comment at the end of the file - */ - -/** - * Syntax definitions - * - * Please don't forget to add binary attributes to isBinary() below - * to support proper value fetching from Horde_Ldap_Entry - */ -define('HORDE_LDAP_SYNTAX_BOOLEAN', '1.3.6.1.4.1.1466.115.121.1.7'); -define('HORDE_LDAP_SYNTAX_DIRECTORY_STRING', '1.3.6.1.4.1.1466.115.121.1.15'); -define('HORDE_LDAP_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12'); -define('HORDE_LDAP_SYNTAX_INTEGER', '1.3.6.1.4.1.1466.115.121.1.27'); -define('HORDE_LDAP_SYNTAX_JPEG', '1.3.6.1.4.1.1466.115.121.1.28'); -define('HORDE_LDAP_SYNTAX_NUMERIC_STRING', '1.3.6.1.4.1.1466.115.121.1.36'); -define('HORDE_LDAP_SYNTAX_OID', '1.3.6.1.4.1.1466.115.121.1.38'); -define('HORDE_LDAP_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40'); - -/** * Load an LDAP Schema and provide information * * This class takes a Subschema entry, parses this information @@ -38,36 +7,50 @@ define('HORDE_LDAP_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40'); * inspired by perl-ldap( http://perl-ldap.sourceforge.net). * You will find portions of their implementation in here. * - * @category Net - * @package Horde_Ldap - * @author Jan Wagner - * @author Benedikt Hallinger - * @license http://www.gnu.org/copyleft/lesser.html LGPL - * @link http://pear.php.net/package/Horde_Ldap2/ + * @category Horde + * @package Ldap + * @author Jan Wagner + * @author Benedikt Hallinger + * @author Jan Schneider + * @copyright 2009 Jan Wagner, Benedikt Hallinger + * @copyright 2010 The Horde Project + * @license http://www.gnu.org/copyleft/lesser.html LGPL */ class Horde_Ldap_Schema { /** - * Map of entry types to ldap attributes of subschema entry + * Syntax definitions. + * + * Please don't forget to add binary attributes to isBinary() below to + * support proper value fetching from Horde_Ldap_Entry. + */ + const SYNTAX_BOOLEAN = '1.3.6.1.4.1.1466.115.121.1.7'; + const SYNTAX_DIRECTORY_STRING = '1.3.6.1.4.1.1466.115.121.1.15'; + const SYNTAX_DISTINGUISHED_NAME = '1.3.6.1.4.1.1466.115.121.1.12'; + const SYNTAX_INTEGER = '1.3.6.1.4.1.1466.115.121.1.27'; + const SYNTAX_JPEG = '1.3.6.1.4.1.1466.115.121.1.28'; + const SYNTAX_NUMERIC_STRING = '1.3.6.1.4.1.1466.115.121.1.36'; + const SYNTAX_OID = '1.3.6.1.4.1.1466.115.121.1.38'; + const SYNTAX_OCTET_STRING = '1.3.6.1.4.1.1466.115.121.1.40'; + + /** + * Map of entry types to LDAP attributes of subschema entry. * - * @access public * @var array */ public $types = array( - 'attribute' => 'attributeTypes', - 'ditcontentrule' => 'dITContentRules', - 'ditstructurerule' => 'dITStructureRules', - 'matchingrule' => 'matchingRules', - 'matchingruleuse' => 'matchingRuleUse', - 'nameform' => 'nameForms', - 'objectclass' => 'objectClasses', - 'syntax' => 'ldapSyntaxes' - ); + 'attribute' => 'attributeTypes', + 'ditcontentrule' => 'dITContentRules', + 'ditstructurerule' => 'dITStructureRules', + 'matchingrule' => 'matchingRules', + 'matchingruleuse' => 'matchingRuleUse', + 'nameform' => 'nameForms', + 'objectclass' => 'objectClasses', + 'syntax' => 'ldapSyntaxes' ); /** * Array of entries belonging to this type * - * @access protected * @var array */ protected $_attributeTypes = array(); @@ -81,143 +64,139 @@ class Horde_Ldap_Schema /** - * hash of all fetched oids + * Hash of all fetched OIDs. * - * @access protected * @var array */ protected $_oids = array(); /** - * Tells if the schema is initialized + * Whether the schema is initialized. * - * @access protected - * @var boolean * @see parse(), get() + * @var boolean */ protected $_initialized = false; /** - * Fetch the Schema from an LDAP connection + * Constructor. + * + * Fetches the Schema from an LDAP connection. * - * @param Horde_Ldap $ldap LDAP connection - * @param string $dn (optional) Subschema entry dn + * @param Horde_Ldap $ldap LDAP connection. + * @param string $dn Subschema entry DN. * - * @access public - * @return Horde_Ldap_Schema|Horde_Ldap_Error + * @throws Horde_Ldap_Exception */ - public function fetch(Horde_Ldap $ldap, $dn = null) + public function __construct(Horde_Ldap $ldap, $dn = null) { - $schema_o = new Horde_Ldap_Schema(); - if (is_null($dn)) { - // get the subschema entry via root dse + // Get the subschema entry via rootDSE. $dse = $ldap->rootDSE(array('subschemaSubentry')); - $base = $dse->getValue('subschemaSubentry', 'single'); - $dn = $base; + $base = $dse->getValue('subschemaSubentry', 'single'); + $dn = $base; } - // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly - // call this entry subSchemaSubentry instead of subschemaSubentry. - // Note the correct case/spelling as per RFC 2251. + // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that + // incorrectly call this entry subSchemaSubentry instead of + // subschemaSubentry. Note the correct case/spelling as per RFC 2251. if (is_null($dn)) { - // get the subschema entry via root dse + // Get the subschema entry via rootDSE. $dse = $ldap->rootDSE(array('subSchemaSubentry')); - $base = $dse->getValue('subSchemaSubentry', 'single'); - $dn = $base; + $base = $dse->getValue('subSchemaSubentry', 'single'); + $dn = $base; } - // Final fallback case where there is no subschemaSubentry attribute - // in the root DSE (this is a bug for an LDAP v3 server so report this - // to your LDAP vendor if you get this far). + // Final fallback in case there is no subschemaSubentry attribute in + // the root DSE (this is a bug for an LDAPv3 server so report this to + // your LDAP vendor if you get this far). if (is_null($dn)) { $dn = 'cn=Subschema'; } - // fetch the subschema entry + // Fetch the subschema entry. $result = $ldap->search($dn, '(objectClass=*)', - array('attributes' => array_values($schema_o->types), - 'scope' => 'base')); + array('attributes' => array_values($this->types), + 'scope' => 'base')); $entry = $result->shiftEntry(); - if (!$entry instanceof Horde_Ldap_Entry) { + if (!($entry instanceof Horde_Ldap_Entry)) { throw new Horde_Ldap_Exception('Could not fetch Subschema entry'); } - $schema_o->parse($entry); - return $schema_o; + $this->parse($entry); } /** - * Return a hash of entries for the given type + * Returns a hash of entries for the given type. * - * Returns a hash of entry for th givene type. Types may be: - * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules, - * matchingruleuses, nameforms, syntaxes + * Types may be: objectclasses, attributes, ditcontentrules, + * ditstructurerules, matchingrules, matchingruleuses, nameforms, syntaxes. * - * @param string $type Type to fetch + * @param string $type Type to fetch. * - * @access public - * @return array|Horde_Ldap_Error Array or Horde_Ldap_Error + * @return array + * @throws Horde_Ldap_Exception */ - public function &getAll($type) + public function getAll($type) { - $map = array('objectclasses' => &$this->_objectClasses, - 'attributes' => &$this->_attributeTypes, - 'ditcontentrules' => &$this->_dITContentRules, - 'ditstructurerules' => &$this->_dITStructureRules, - 'matchingrules' => &$this->_matchingRules, - 'matchingruleuses' => &$this->_matchingRuleUse, - 'nameforms' => &$this->_nameForms, - 'syntaxes' => &$this->_ldapSyntaxes ); - - $key = strtolower($type); - if (!key_exists($key, $map)) { - throw new Horde_Ldap_Exception("Unknown type $type"); - } + $map = array('objectclasses' => $this->_objectClasses, + 'attributes' => $this->_attributeTypes, + 'ditcontentrules' => $this->_dITContentRules, + 'ditstructurerules' => $this->_dITStructureRules, + 'matchingrules' => $this->_matchingRules, + 'matchingruleuses' => $this->_matchingRuleUse, + 'nameforms' => $this->_nameForms, + 'syntaxes' => $this->_ldapSyntaxes); + + $key = Horde_String::lower($type); + if (!isset($map[$key])) { + throw new Horde_Ldap_Exception("Unknown type $type"); + } + return $map[$key]; } /** - * Return a specific entry + * Returns a specific entry. * - * @param string $type Type of name - * @param string $name Name or OID to fetch + * @param string $type Type of name. + * @param string $name Name or OID to fetch. * - * @access public - * @return mixed Entry or Horde_Ldap_Error + * @return mixed + * @throws Horde_Ldap_Exception */ - public function &get($type, $name) + public function get($type, $name) { - if ($this->_initialized) { - $type = strtolower($type); - if (false == key_exists($type, $this->types)) { - throw new Horde_Ldap_Exception("No such type $type"); - } + if (!$this->_initialized) { + return null; + } - $name = strtolower($name); - $type_var = &$this->{'_' . $this->types[$type]}; + $type = Horde_String::lower($type); + if (!isset($this->types[$type])) { + throw new Horde_Ldap_Exception("No such type $type"); + } - if (key_exists($name, $type_var)) { - return $type_var[$name]; - } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) { - return $this->_oids[$name]; - } else { - throw new Horde_Ldap_Exception("Could not find $type $name"); - } - } else { - $return = null; - return $return; + $name = Horde_String::lower($name); + $type_var = $this->{'_' . $this->types[$type]}; + + if (isset($type_var[$name])) { + return $type_var[$name]; } + if (isset($this->_oids[$name]) && + $this->_oids[$name]['type'] == $type) { + return $this->_oids[$name]; + } + throw new Horde_Ldap_Exception("Could not find $type $name"); } /** - * Fetches attributes that MAY be present in the given objectclass + * Fetches attributes that MAY be present in the given objectclass. * - * @param string $oc Name or OID of objectclass + * @param string $oc Name or OID of objectclass. * - * @access public - * @return array|Horde_Ldap_Error Array with attributes or Horde_Ldap_Error + * @return array Array with attributes. + * @throws Horde_Ldap_Exception */ public function may($oc) { @@ -225,12 +204,12 @@ class Horde_Ldap_Schema } /** - * Fetches attributes that MUST be present in the given objectclass + * Fetches attributes that MUST be present in the given objectclass. * - * @param string $oc Name or OID of objectclass + * @param string $oc Name or OID of objectclass. * - * @access public - * @return array|Horde_Ldap_Error Array with attributes or Horde_Ldap_Error + * @return array Array with attributes. + * @throws Horde_Ldap_Exception */ public function must($oc) { @@ -238,81 +217,76 @@ class Horde_Ldap_Schema } /** - * Fetches the given attribute from the given objectclass + * Fetches the given attribute from the given objectclass. * - * @param string $oc Name or OID of objectclass - * @param string $attr Name of attribute to fetch + * @param string $oc Name or OID of objectclass. + * @param string $attr Name of attribute to fetch. * - * @access protected - * @return array|Horde_Ldap_Error The attribute or Horde_Ldap_Error + * @return array The attribute. + * @throws Horde_Ldap_Exception */ protected function _getAttr($oc, $attr) { - $oc = strtolower($oc); - if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) { + $oc = Horde_String::lower($oc); + if (isset($this->_objectClasses[$oc]) && + isset($this->_objectClasses[$oc][$attr])) { return $this->_objectClasses[$oc][$attr]; - } elseif (key_exists($oc, $this->_oids) && - $this->_oids[$oc]['type'] == 'objectclass' && - key_exists($attr, $this->_oids[$oc])) { + } + if (isset($this->_oids[$oc]) && + $this->_oids[$oc]['type'] == 'objectclass' && + isset($this->_oids[$oc][$attr])) { return $this->_oids[$oc][$attr]; - } else { - throw new Horde_Ldap_Exception("Could not find $attr attributes for $oc "); } + throw new Horde_Ldap_Exception("Could not find $attr attributes for $oc "); } /** - * Returns the name(s) of the immediate superclass(es) + * Returns the name(s) of the immediate superclass(es). * - * @param string $oc Name or OID of objectclass + * @param string $oc Name or OID of objectclass. * - * @access public - * @return array|Horde_Ldap_Error Array of names or Horde_Ldap_Error + * @return array + * @throws Horde_Ldap_Exception */ public function superclass($oc) { $o = $this->get('objectclass', $oc); - return (key_exists('sup', $o) ? $o['sup'] : array()); + return isset($o['sup']) ? $o['sup'] : array(); } /** - * Parses the schema of the given Subschema entry + * Parses the schema of the given subschema entry. * - * @param Horde_Ldap_Entry &$entry Subschema entry - * - * @access public - * @return void + * @param Horde_Ldap_Entry $entry Subschema entry. */ - public function parse(&$entry) + public function parse($entry) { foreach ($this->types as $type => $attr) { - // initialize map type to entry + // Initialize map type to entry. $type_var = '_' . $attr; $this->{$type_var} = array(); - // get values for this type - if ($entry->exists($attr)) { - $values = $entry->getValue($attr); - if (is_array($values)) { - foreach ($values as $value) { - - unset($schema_entry); // this was a real mess without it - - // get the schema entry - $schema_entry = $this->_parse_entry($value); - - // set the type - $schema_entry['type'] = $type; - - // save a ref in $_oids - $this->_oids[$schema_entry['oid']] = &$schema_entry; + if (!$entry->exists($attr)) { + continue; + } - // save refs for all names in type map - $names = $schema_entry['aliases']; - array_push($names, $schema_entry['name']); - foreach ($names as $name) { - $this->{$type_var}[strtolower($name)] = &$schema_entry; - } - } + // Get values for this type. + $values = $entry->getValue($attr); + if (!is_array($values)) { + continue; + } + foreach ($values as $value) { + // Get the schema entry. + $schema_entry = $this->_parse_entry($value); + // Set the type. + $schema_entry['type'] = $type; + // Save a ref in $_oids. + $this->_oids[$schema_entry['oid']] = $schema_entry; + // Save refs for all names in type map. + $names = $schema_entry['aliases']; + array_push($names, $schema_entry['name']); + foreach ($names as $name) { + $this->{$type_var}[Horde_String::lower($name)] = $schema_entry; } } } @@ -320,16 +294,15 @@ class Horde_Ldap_Schema } /** - * Parses an attribute value into a schema entry + * Parses an attribute value into a schema entry. * - * @param string $value Attribute value + * @param string $value Attribute value. * - * @access protected - * @return array|false Schema entry array or false + * @return array Schema entry array. */ - protected function &_parse_entry($value) + protected function _parse_entry($value) { - // tokens that have no value associated + // Tokens that have no value associated. $noValue = array('single-value', 'obsolete', 'collective', @@ -338,147 +311,148 @@ class Horde_Ldap_Schema 'structural', 'auxiliary'); - // tokens that can have multiple values + // Tokens that can have multiple values. $multiValue = array('must', 'may', 'sup'); - $schema_entry = array('aliases' => array()); // initilization - - $tokens = $this->_tokenize($value); // get an array of tokens + // Get an array of tokens. + $tokens = $this->_tokenize($value); - // remove surrounding brackets - if ($tokens[0] == '(') array_shift($tokens); - if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-( + // Remove surrounding brackets. + if ($tokens[0] == '(') { + array_shift($tokens); + } + if ($tokens[count($tokens) - 1] == ')') { + array_pop($tokens); + } - $schema_entry['oid'] = array_shift($tokens); // first token is the oid + // First token is the oid. + $schema_entry = array('aliases' => array(), + 'oid' => array_shift($tokens)); - // cycle over the tokens until none are left + // Cycle over the tokens until none are left. while (count($tokens) > 0) { - $token = strtolower(array_shift($tokens)); + $token = Horde_String::lower(array_shift($tokens)); if (in_array($token, $noValue)) { - $schema_entry[$token] = 1; // single value token + // Single value token. + $schema_entry[$token] = 1; } else { - // this one follows a string or a list if it is multivalued + // Follow a string or a list if it is multivalued. if (($schema_entry[$token] = array_shift($tokens)) == '(') { - // this creates the list of values and cycles through the tokens - // until the end of the list is reached ')' + // Create the list of values and cycles through the tokens + // until the end of the list is reached ')'. $schema_entry[$token] = array(); while ($tmp = array_shift($tokens)) { - if ($tmp == ')') break; - if ($tmp != '$') array_push($schema_entry[$token], $tmp); + if ($tmp == ')') { + break; + } + if ($tmp != '$') { + array_push($schema_entry[$token], $tmp); + } } } - // create a array if the value should be multivalued but was not - if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) { + // Create an array if the value should be multivalued but was + // not. + if (in_array($token, $multiValue) && + !is_array($schema_entry[$token])) { $schema_entry[$token] = array($schema_entry[$token]); } } } - // get max length from syntax - if (key_exists('syntax', $schema_entry)) { + + // Get max length from syntax. + if (isset($schema_entry['syntax'])) { if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) { $schema_entry['max_length'] = $matches[1]; } } - // force a name + + // Force a name. if (empty($schema_entry['name'])) { $schema_entry['name'] = $schema_entry['oid']; } - // make one name the default and put the other ones into aliases + + // Make one name the default and put the other ones into aliases. if (is_array($schema_entry['name'])) { $aliases = $schema_entry['name']; $schema_entry['name'] = array_shift($aliases); $schema_entry['aliases'] = $aliases; } + return $schema_entry; } /** - * Tokenizes the given value into an array of tokens + * Tokenizes the given value into an array of tokens. * - * @param string $value String to parse + * @param string $value String to parse. * - * @access protected - * @return array Array of tokens + * @return array Array of tokens. */ protected function _tokenize($value) { - $tokens = array(); // array of tokens - $matches = array(); // matches[0] full pattern match, [1,2,3] subpatterns - - // this one is taken from perl-ldap, modified for php - $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; - - /** - * This one matches one big pattern wherin only one of the three subpatterns matched - * We are interested in the subpatterns that matched. If it matched its value will be - * non-empty and so it is a token. Tokens may be round brackets, a string, or a string - * enclosed by ' - */ - preg_match_all($pattern, $value, $matches); - - for ($i = 0; $i < count($matches[0]); $i++) { // number of tokens (full pattern match) - for ($j = 1; $j < 4; $j++) { // each subpattern - if (null != trim($matches[$j][$i])) { // pattern match in this subpattern - $tokens[$i] = trim($matches[$j][$i]); // this is the token + /* Match one big pattern where only one of the three subpatterns + * matches. We are interested in the subpatterns that matched. If it + * matched its value will be non-empty and so it is a token. Tokens may + * be round brackets, a string, or a string enclosed by ''. */ + preg_match_all("/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x", $value, $matches); + + $tokens = array(); + // Number of tokens (full pattern match). + for ($i = 0; $i < count($matches[0]); $i++) { + // Each subpattern. + for ($j = 1; $j < 4; $j++) { + // Pattern match in this subpattern. + if (null != trim($matches[$j][$i])) { + // This is the token. + $tokens[$i] = trim($matches[$j][$i]); } } } + return $tokens; } /** - * Returns wether a attribute syntax is binary or not + * Returns wether a attribute syntax is binary or not. * - * This method gets used by Horde_Ldap_Entry to decide which - * PHP function needs to be used to fetch the value in the - * proper format (e.g. binary or string) + * This method is used by Horde_Ldap_Entry to decide which PHP function + * needs to be used to fetch the value in the proper format (e.g. binary or + * string). * - * @param string $attribute The name of the attribute (eg.: 'sn') + * @param string $attribute The name of the attribute (eg.: 'sn'). * - * @access public - * @return boolean + * @return boolean True if the attribute is a binary type. */ public function isBinary($attribute) { - $return = false; // default to false - - // This list contains all syntax that should be treaten as - // containing binary values - // The Syntax Definitons go into constants at the top of this page - $syntax_binary = array( - HORDE_LDAP_SYNTAX_OCTET_STRING, - HORDE_LDAP_SYNTAX_JPEG - ); - - // Check Syntax - try { - $attr_s = $this->get('attribute', $attribute); - } catch (Horde_Ldap_Exception $e) { - // Attribute not found in schema - $return = false; // consider attr not binary - } - if (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) { + // All syntax that should be treaten as containing binary values. + $syntax_binary = array(self::SYNTAX_OCTET_STRING, self::SYNTAX_JPEG); + + // Check Syntax. + try { + $attr_s = $this->get('attribute', $attribute); + } catch (Horde_Ldap_Exception $e) { + // Attribute not found in schema, consider attr not binary. + return false; + } + + if (isset($attr_s['syntax']) && + in_array($attr_s['syntax'], $syntax_binary)) { // Syntax is defined as binary in schema - $return = true; - } else { - // Syntax not defined as binary, or not found - // if attribute is a subtype, check superior attribute syntaxes - if (isset($attr_s['sup'])) { - foreach ($attr_s['sup'] as $superattr) { - $return = $this->isBinary($superattr); - if ($return) { - break; // stop checking parents since we are binary - } + return true; + } + + // Syntax not defined as binary, or not found if attribute is a + // subtype, check superior attribute syntaxes. + if (isset($attr_s['sup'])) { + foreach ($attr_s['sup'] as $superattr) { + if ($this->isBinary($superattr)) { + // Stop checking parents since we are binary. + return true; } } } - return $return; + return false; } - - // [TODO] add method that allows us to see to which objectclasses a certain attribute belongs to - // it should return the result structured, e.g. sorted in "may" and "must". Optionally it should - // be able to return it just "flat", e.g. array_merge()d. - // We could use get_all() to achieve this easily, i think } -?> diff --git a/framework/Ldap/lib/Horde/Ldap/Search.php b/framework/Ldap/lib/Horde/Ldap/Search.php index 1d49a333c..035452d11 100644 --- a/framework/Ldap/lib/Horde/Ldap/Search.php +++ b/framework/Ldap/lib/Horde/Ldap/Search.php @@ -1,132 +1,103 @@ * @author Benedikt Hallinger - * @copyright 2009 Tarjej Huse, Benedikt Hallinger - * @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 - * @version SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $ - * @link http://pear.php.net/package/Horde_Ldap/ - */ - -/** - * Includes - */ -#require_once 'PEAR.php'; - -/** - * Result set of an LDAP search - * - * @category Net - * @package Horde_Ldap - * @author Tarjej Huse - * @author Benedikt Hallinger - * @license http://www.gnu.org/copyleft/lesser.html LGPL - * @link http://pear.php.net/package/Horde_Ldap2/ + * @author Jan Schneider + * @copyright 2009 Jan Wagner, Benedikt Hallinger + * @copyright 2010 The Horde Project + * @license http://www.gnu.org/copyleft/lesser.html LGPL */ class Horde_Ldap_Search implements Iterator { /** - * Search result identifier + * Search result identifier. * - * @access protected * @var resource */ protected $_search; /** - * LDAP resource link + * LDAP resource link. * - * @access protected * @var resource */ protected $_link; /** - * Horde_Ldap object + * Horde_Ldap object. * - * A reference of the Horde_Ldap object for passing to Horde_Ldap_Entry + * A reference of the Horde_Ldap object for passing to Horde_Ldap_Entry. * - * @access protected - * @var object Horde_Ldap + * @var Horde_Ldap */ protected $_ldap; /** - * Result entry identifier + * Result entry identifier. * - * @access protected * @var resource */ - protected $_entry = null; + protected $_entry; /** - * The errorcode the search got + * The errorcode from the search. * - * Some errorcodes might be of interest, but might not be best handled as errors. - * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search. - * Incomplete results are returned. If you just want to check if there's anything in the search. - * than this is a point to handle. - * 32 - no such object - search here returns a count of 0. + * Some errorcodes might be of interest that should not be considered + * errors, for example: + * - 4: LDAP_SIZELIMIT_EXCEEDED - indicates a huge search. Incomplete + * results are returned. If you just want to check if there is + * anything returned by the search at all, this could be catched. + * - 32: no such object - search here returns a count of 0. * - * @access protected - * @var int + * @var integer */ - protected $_errorCode = 0; // if not set - sucess! + protected $_errorCode = 0; /** - * Cache for all entries already fetched from iterator interface + * Cache for all entries already fetched from iterator interface. * - * @access protected * @var array */ protected $_iteratorCache = array(); /** - * What attributes we searched for + * Attributes we searched for. * - * The $attributes array contains the names of the searched attributes and gets - * passed from $Horde_Ldap->search() so the Horde_Ldap_Search object can tell - * what attributes was searched for ({@link searchedAttrs()) + * This variable gets set from the constructor and can be retrieved through + * {@link searchedAttributes()}. * - * This variable gets set from the constructor and returned - * from {@link searchedAttrs()} - * - * @access protected * @var array */ protected $_searchedAttrs = array(); /** - * Cache variable for storing entries fetched internally + * Cache variable for storing entries fetched internally. * - * This currently is only used by {@link pop_entry()} + * This currently is only used by {@link pop_entry()}. * - * @access protected * @var array */ protected $_entry_cache = false; /** - * Constructor - * - * @param resource &$search Search result identifier - * @param Horde_Ldap|resource &$ldap Horde_Ldap object or just a LDAP-Link resource - * @param array $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs}) + * Constructor. * - * @access public + * @param resource $search Search result identifier. + * @param Horde_Ldap|resource $ldap Horde_Ldap object or a LDAP link + * resource + * @param array $attributes The searched attribute names, + * see {@link $_searchedAttrs}. */ - public function __construct(&$search, &$ldap, $attributes = array()) + public function __construct($search, $ldap, $attributes = array()) { $this->setSearch($search); if ($ldap instanceof Horde_Ldap) { - $this->_ldap =& $ldap; + $this->_ldap = $ldap; $this->setLink($this->_ldap->getLink()); } else { $this->setLink($ldap); @@ -140,158 +111,141 @@ class Horde_Ldap_Search implements Iterator } /** - * Returns an array of entry objects + * Destructor. + */ + public function __destruct() + { + @ldap_free_result($this->_search); + } + + /** + * Returns all entries from the search result. * - * @return array Array of entry objects. + * @return array All entries. + * @throws Horde_Ldap_Exception */ public function entries() { $entries = array(); - while ($entry = $this->shiftEntry()) { $entries[] = $entry; } - return $entries; } /** - * Get the next entry in the searchresult. + * Get the next entry from the search result. * - * This will return a valid Horde_Ldap_Entry object or false, so - * you can use this method to easily iterate over the entries inside - * a while loop. + * This will return a valid Horde_Ldap_Entry object or false, so you can + * use this method to easily iterate over the entries inside a while loop. * - * @return Horde_Ldap_Entry|false Reference to Horde_Ldap_Entry object or false + * @return Horde_Ldap_Entry|false Reference to Horde_Ldap_Entry object or + * false if no more entries exist. + * @throws Horde_Ldap_Exception */ - public function &shiftEntry() + public function shiftEntry() { - if ($this->count() == 0 ) { - $false = false; - return $false; + if (!$this->count()) { + return false; } if (is_null($this->_entry)) { $this->_entry = @ldap_first_entry($this->_link, $this->_search); $entry = Horde_Ldap_Entry::createConnected($this->_ldap, $this->_entry); - if ($entry instanceof Horde_Ldap_Error) $entry = false; } else { if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) { - $false = false; - return $false; + return false; } $entry = Horde_Ldap_Entry::createConnected($this->_ldap, $this->_entry); - if ($entry instanceof Horde_Ldap_Error) $entry = false; } - return $entry; - } - /** - * Alias function of shiftEntry() for perl-ldap interface - * - * @see shiftEntry() - * @return Horde_Ldap_Entry|false - */ - public function shift_entry() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'shiftEntry' ), $args); + return $entry; } /** - * Retrieve the next entry in the searchresult, but starting from last entry + * Retrieve the next entry in the search result, but starting from last + * entry. * - * This is the opposite to {@link shiftEntry()} and is also very useful - * to be used inside a while loop. + * This is the opposite to {@link shiftEntry()} and is also very useful to + * be used inside a while loop. * * @return Horde_Ldap_Entry|false + * @throws Horde_Ldap_Exception */ public function popEntry() { if (false === $this->_entry_cache) { - // fetch entries into cache if not done so far + // Fetch entries into cache if not done so far. $this->_entry_cache = $this->entries(); } - $return = array_pop($this->_entry_cache); - return (null === $return)? false : $return; + return count($this->_entry_cache) ? array_pop($this->_entry_cache) : false; } /** - * Alias function of popEntry() for perl-ldap interface + * Return entries sorted as array. * - * @see popEntry() - * @return Horde_Ldap_Entry|false - */ - public function pop_entry() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'popEntry' ), $args); - } - - /** - * Return entries sorted as array + * This returns a array with sorted entries and the values. Sorting is done + * with PHPs {@link array_multisort()}. * - * This returns a array with sorted entries and the values. - * Sorting is done with PHPs {@link array_multisort()}. - * This method relies on {@link as_struct()} to fetch the raw data of the entries. + * This method relies on {@link as_struct()} to fetch the raw data of the + * entries. * * Please note that attribute names are case sensitive! * * Usage example: * - * // to sort entries first by location, then by surename, but descending: - * $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC); + * // To sort entries first by location, then by surname, but descending: + * $entries = $search->sorted_as_struct(array('locality', 'sn'), SORT_DESC); * * - * @param array $attrs Array of attribute names to sort; order from left to right. - * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * @todo what about server side sorting as specified in + * http://www.ietf.org/rfc/rfc2891.txt? + * @todo Nuke evil eval(). * - * @return array|Horde_Ldap_Error Array with sorted entries or error - * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt? + * @param array $attrs Attribute names as sort criteria. + * @param integer $order Ordering direction, either constant SORT_ASC or + * SORT_DESC + * + * @return array Sorted entries. + * @throws Horde_Ldap_Exception */ - public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC) + public function sorted_as_struct(array $attrs = array('cn'), + $order = SORT_ASC) { - /* - * Old Code, suitable and fast for single valued sorting - * This code should be used if we know that single valued sorting is desired, - * but we need some method to get that knowledge... - */ + /* Old Code, suitable and fast for single valued sorting. This code + * should be used if we know that single valued sorting is desired, but + * we need some method to get that knowledge... */ /* $attrs = array_reverse($attrs); foreach ($attrs as $attribute) { - if (!ldap_sort($this->_link, $this->_search, $attribute)){ - $this->raiseError("Sorting failed for Attribute " . $attribute); + if (!ldap_sort($this->_link, $this->_search, $attribute)) { + throw new Horde_Ldap_Exception('Sorting failed for attribute ' . $attribute); } } $results = ldap_get_entries($this->_link, $this->_search); - unset($results['count']); //for tidier output + unset($results['count']); if ($order) { return array_reverse($results); - } else { - return $results; - }*/ - - /* - * New code: complete "client side" sorting - */ - // first some parameterchecks - if (!is_array($attrs)) { - return PEAR::raiseError("Sorting failed: Parameterlist must be an array!"); } + return $results; + */ + + /* New code: complete "client side" sorting */ + // First some parameterchecks. if ($order != SORT_ASC && $order != SORT_DESC) { - return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)"); + throw new Horde_Ldap_Exception('Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)'); } - // fetch the entries data + // Fetch the entries data. $entries = $this->as_struct(); - // now sort each entries attribute values - // this is neccessary because later we can only sort by one value, - // so we need the highest or lowest attribute now, depending on the - // selected ordering for that specific attribute + // Now sort each entries attribute values. + // This is neccessary because later we can only sort by one value, so + // we need the highest or lowest attribute now, depending on the + // selected ordering for that specific attribute. foreach ($entries as $dn => $entry) { foreach ($entry as $attr_name => $attr_values) { sort($entries[$dn][$attr_name]); @@ -301,19 +255,20 @@ class Horde_Ldap_Search implements Iterator } } - // reformat entrys array for later use with array_multisort() - $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries + // Reformat entries array for later use with + // array_multisort(). $to_sort will be a numeric array similar to + // ldap_get_entries(). + $to_sort = array(); foreach ($entries as $dn => $entry_attr) { - $row = array(); - $row['dn'] = $dn; + $row = array('dn' => $dn); foreach ($entry_attr as $attr_name => $attr_values) { $row[$attr_name] = $attr_values; } $to_sort[] = $row; } - // Build columns for array_multisort() - // each requested attribute is one row + // Build columns for array_multisort(). Each requested attribute is one + // row. $columns = array(); foreach ($attrs as $attr_name) { foreach ($to_sort as $key => $row) { @@ -321,86 +276,81 @@ class Horde_Ldap_Search implements Iterator } } - // sort the colums with array_multisort, if there is something - // to sort and if we have requested sort columns + // Sort the colums with array_multisort() if there is something to sort + // and if we have requested sort columns. if (!empty($to_sort) && !empty($columns)) { $sort_params = ''; foreach ($attrs as $attr_name) { - $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', '; + $sort_params .= '$columns[\'' . $attr_name . '\'], ' . $order . ', '; } - eval("array_multisort($sort_params \$to_sort);"); // perform sorting + eval("array_multisort($sort_params \$to_sort);"); } return $to_sort; } /** - * Return entries sorted as objects + * Returns entries sorted as objects. * - * This returns a array with sorted Horde_Ldap_Entry objects. - * The sorting is actually done with {@link sorted_as_struct()}. + * This returns a array with sorted Horde_Ldap_Entry objects. The sorting + * is actually done with {@link sorted_as_struct()}. * * Please note that attribute names are case sensitive! - * Also note, that it is (depending on server capabilitys) possible to let - * the server sort your results. This happens through search controls - * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} + * + * Also note that it is (depending on server capabilities) possible to let + * the server sort your results. This happens through search controls and + * is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} * * Usage example: * - * // to sort entries first by location, then by surename, but descending: - * $entries = $search->sorted(array('locality','sn'), SORT_DESC); + * // To sort entries first by location, then by surname, but descending: + * $entries = $search->sorted(array('locality', 'sn'), SORT_DESC); * * - * @param array $attrs Array of sort attributes to sort; order from left to right. - * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * @todo Entry object construction could be faster. Maybe we could use one + * of the factories instead of fetching the entry again. + * + * @param array $attrs Attribute names as sort criteria. + * @param integer $order Ordering direction, either constant SORT_ASC or + * SORT_DESC * - * @return array|Horde_Ldap_Error Array with sorted Horde_Ldap_Entries or error - * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again + * @return array Sorted entries. + * @throws Horde_Ldap_Exception */ public function sorted($attrs = array('cn'), $order = SORT_ASC) { $return = array(); $sorted = $this->sorted_as_struct($attrs, $order); - if (PEAR::isError($sorted)) { - return $sorted; - } foreach ($sorted as $key => $row) { - $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs()); - if (!PEAR::isError($entry)) { - array_push($return, $entry); - } else { - return $entry; - } + $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttributes()); + array_push($return, $entry); } return $return; } /** - * Return entries as array + * Returns entries as array. * - * This method returns the entries and the selected attributes values as - * array. * The first array level contains all found entries where the keys are the - * DNs of the entries. The second level arrays contian the entries attributes - * such that the keys is the lowercased name of the attribute and the values - * are stored in another indexed array. Note that the attribute values are stored - * in an array even if there is no or just one value. + * DNs of the entries. The second level arrays contian the entries + * attributes such that the keys is the lowercased name of the attribute + * and the values are stored in another indexed array. Note that the + * attribute values are stored in an array even if there is no or just one + * value. * * The array has the following structure: * - * $return = array( - * 'cn=foo,dc=example,dc=com' => array( - * 'sn' => array('foo'), - * 'multival' => array('val1', 'val2', 'valN') - * ) - * 'cn=bar,dc=example,dc=com' => array( - * 'sn' => array('bar'), - * 'multival' => array('val1', 'valN') - * ) - * ) + * array( + * 'cn=foo,dc=example,dc=com' => array( + * 'sn' => array('foo'), + * 'multival' => array('val1', 'val2', 'valN')), + * 'cn=bar,dc=example,dc=com' => array( + * 'sn' => array('bar'), + * 'multival' => array('val1', 'valN'))) * * - * @return array associative result array as described above + * @return array Associative result array as described above. + * @throws Horde_Ldap_Exception */ public function as_struct() { @@ -422,39 +372,34 @@ class Horde_Ldap_Search implements Iterator } /** - * Set the search objects resource link + * Sets the search objects resource link * - * @param resource &$search Search result identifier - * - * @access public - * @return void + * @param resource $search Search result identifier. */ - public function setSearch(&$search) + public function setSearch($search) { $this->_search = $search; } /** - * Set the ldap ressource link - * - * @param resource &$link Link identifier + * Sets the LDAP resource link. * - * @access public - * @return void + * @param resource $link LDAP link identifier. */ - public function setLink(&$link) + public function setLink($link) { $this->_link = $link; } /** - * Returns the number of entries in the searchresult + * Returns the number of entries in the search result. * - * @return int Number of entries in search. + * @return integer Number of found entries. */ public function count() { - // this catches the situation where OL returned errno 32 = no such object! + // This catches the situation where OL returned errno 32 = no such + // object! if (!$this->_search) { return 0; } @@ -462,9 +407,9 @@ class Horde_Ldap_Search implements Iterator } /** - * Get the errorcode the object got in its search. + * Returns the errorcode from the search. * - * @return int The ldap error number. + * @return integer The LDAP error number. */ public function getErrorCode() { @@ -472,55 +417,32 @@ class Horde_Ldap_Search implements Iterator } /** - * Destructor + * Returns the attribute names this search selected. * - * @access protected - */ - public function _Horde_Ldap_Search() - { - @ldap_free_result($this->_search); - } - - /** - * Closes search result - * - * @return void - */ - public function done() - { - $this->_Horde_Ldap_Search(); - } - - /** - * Return the attribute names this search selected + * @see $_searchedAttrs * * @return array - * @see $_searchedAttrs - * @access protected */ - protected function searchedAttrs() + protected function searchedAttributes() { return $this->_searchedAttrs; } /** - * Tells if this search exceeds a sizelimit + * Returns wheter this search exceeded a sizelimit. * - * @return boolean + * @return boolean True if the size limit was exceeded. */ public function sizeLimitExceeded() { - return ($this->getErrorCode() == 4); + return $this->getErrorCode() == 4; } + /* SPL Iterator interface methods. This interface allows to use + * Horde_Ldap_Search objects directly inside a foreach loop. */ - /* - * SPL Iterator interface methods. - * This interface allows to use Horde_Ldap_Search - * objects directly inside a foreach loop! - */ /** - * SPL Iterator interface: Return the current element. + * SPL Iterator interface: Returns the current element. * * The SPL Iterator interface allows you to fetch entries inside * a foreach() loop: foreach ($search as $dn => $entry) { ... @@ -528,12 +450,14 @@ class Horde_Ldap_Search implements Iterator * Of course, you may call {@link current()}, {@link key()}, {@link next()}, * {@link rewind()} and {@link valid()} yourself. * - * If the search throwed an error, it returns false. - * False is also returned, if the end is reached - * In case no call to next() was made, we will issue one, - * thus returning the first entry. + * If the search throwed an error, it returns false. False is also + * returned, if the end is reached. + * + * In case no call to next() was made, we will issue one, thus returning + * the first entry. * * @return Horde_Ldap_Entry|false + * @throws Horde_Ldap_Exception */ public function current() { @@ -542,70 +466,69 @@ class Horde_Ldap_Search implements Iterator reset($this->_iteratorCache); } $entry = current($this->_iteratorCache); - return ($entry instanceof Horde_Ldap_Entry)? $entry : false; + return $entry instanceof Horde_Ldap_Entry ? $entry : false; } /** - * SPL Iterator interface: Return the identifying key (DN) of the current entry. + * SPL Iterator interface: Returns the identifying key (DN) of the current + * entry. * * @see current() - * @return string|false DN of the current entry; false in case no entry is returned by current() + * @return string|false DN of the current entry; false in case no entry is + * returned by current(). */ public function key() { $entry = $this->current(); - return ($entry instanceof Horde_Ldap_Entry)? $entry->dn() :false; + return $entry instanceof Horde_Ldap_Entry ? $entry->dn() :false; } /** - * SPL Iterator interface: Move forward to next entry. + * SPL Iterator interface: Moves forward to next entry. * - * After a call to {@link next()}, {@link current()} will return - * the next entry in the result set. + * After a call to {@link next()}, {@link current()} will return the next + * entry in the result set. * * @see current() - * @return void + * @throws Horde_Ldap_Exception */ public function next() { - // fetch next entry. - // if we have no entrys anymore, we add false (which is - // returned by shiftEntry()) so current() will complain. + // Fetch next entry. If we have no entries anymore, we add false (which + // is returned by shiftEntry()) so current() will complain. if (count($this->_iteratorCache) - 1 <= $this->count()) { $this->_iteratorCache[] = $this->shiftEntry(); } - // move on array pointer to current element. - // even if we have added all entries, this will - // ensure proper operation in case we rewind() + // Move array pointer to current element. Even if we have added all + // entries, this will ensure proper operation in case we rewind(). next($this->_iteratorCache); } /** - * SPL Iterator interface: Check if there is a current element after calls to {@link rewind()} or {@link next()}. + * SPL Iterator interface: Checks if there is a current element after calls + * to {@link rewind()} or {@link next()}. * * Used to check if we've iterated to the end of the collection. * * @see current() - * @return boolean FALSE if there's nothing more to iterate over + * @return boolean False if there's nothing more to iterate over. */ public function valid() { - return ($this->current() instanceof Horde_Ldap_Entry); + return $this->current() instanceof Horde_Ldap_Entry; } /** - * SPL Iterator interface: Rewind the Iterator to the first element. + * SPL Iterator interface: Rewinds the Iterator to the first element. * - * After rewinding, {@link current()} will return the first entry in the result set. + * After rewinding, {@link current()} will return the first entry in the + * result set. * * @see current() - * @return void */ public function rewind() { reset($this->_iteratorCache); } } - -?> diff --git a/framework/Ldap/package.xml b/framework/Ldap/package.xml index 5639ca3be..716a688f1 100644 --- a/framework/Ldap/package.xml +++ b/framework/Ldap/package.xml @@ -55,6 +55,14 @@ 1.5.0 + + Exception + pear.horde.org + + + Util + pear.horde.org +