diff options
Diffstat (limited to 'extlib/Net/LDAP2/Filter.php')
-rw-r--r-- | extlib/Net/LDAP2/Filter.php | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/extlib/Net/LDAP2/Filter.php b/extlib/Net/LDAP2/Filter.php deleted file mode 100644 index 0723edab2..000000000 --- a/extlib/Net/LDAP2/Filter.php +++ /dev/null @@ -1,514 +0,0 @@ -<?php -/* vim: set expandtab tabstop=4 shiftwidth=4: */ -/** -* File containing the Net_LDAP2_Filter interface class. -* -* PHP version 5 -* -* @category Net -* @package Net_LDAP2 -* @author Benedikt Hallinger <beni@php.net> -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; -require_once 'Util.php'; - -/** -* Object representation of a part of a LDAP filter. -* -* This Class is not completely compatible to the PERL interface! -* -* 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 and can be found under -* {@link http://www.ietf.org/rfc/rfc2254.txt} -* -* Here a quick copy&paste example: -* <code> -* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***'); -* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0); -* -* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar'); -* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz'); -* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2)); -* -* echo $filter_comp->asString(); -* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz)) -* // The stars in $filter0 are treaten as real stars unless you disable escaping. -* </code> -* -* @category Net -* @package Net_LDAP2 -* @author Benedikt Hallinger <beni@php.net> -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP2/ -*/ -class Net_LDAP2_Filter extends PEAR -{ - /** - * Storage for combination of filters - * - * This variable holds a array of filter objects - * that should be combined by this filter object. - * - * @access protected - * @var array - */ - protected $_subfilters = array(); - - /** - * Match of this filter - * - * 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; - - /** - * Single filter - * - * If we operate in leaf filter mode, - * then the constructing method stores - * the filter representation here - * - * @acces private - * @var string - */ - protected $_filter; - - /** - * Create a new Net_LDAP2_Filter object and parse $filter. - * - * This is for PERL Net::LDAP interface. - * Construction of Net_LDAP2_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 - * - * @see parse() - */ - public function __construct($filter = false) - { - // 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(); - } - } - } - - /** - * Constructor of a new part of a 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 Net_LDAP2_Util::escape_filter_value()}! - * - * Examples: - * <code> - * // This will find entries that contain an attribute "sn" that ends with "foobar": - * $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar'); - * - * // This will find entries that contain an attribute "sn" that has any value set: - * $filter = new Net_LDAP2_Filter('sn', 'any'); - * </code> - * - * @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 Net_LDAP2_Util::escape_filter_value()} for detailed information) - * - * @return Net_LDAP2_Filter|Net_LDAP2_Error - */ - public static function &create($attr_name, $match, $value = '', $escape = true) - { - $leaf_filter = new Net_LDAP2_Filter(); - if ($escape) { - $array = Net_LDAP2_Util::escape_filter_value(array($value)); - $value = $array[0]; - } - switch (strtolower($match)) { - case 'equals': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')'; - break; - case 'begins': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)'; - break; - case 'ends': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')'; - break; - case 'contains': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)'; - break; - case 'greater': - $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')'; - break; - case 'less': - $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')'; - break; - case 'greaterorequal': - case '>=': - $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')'; - break; - case 'lessorequal': - case '<=': - $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')'; - break; - case 'approx': - case '~=': - $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')'; - break; - case 'any': - case 'present': // alias that may improve user code readability - $leaf_filter->_filter = '(' . $attr_name . '=*)'; - break; - default: - return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!'); - } - return $leaf_filter; - } - - /** - * Combine two or more filter objects using a logical operator - * - * 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 = Net_LDAP2_Filter('or', array($filter1, $filter2)) - * If the array contains filter strings instead of filter objects, we will try to parse them. - * - * @param string $log_op The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!" - * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects - * - * @return Net_LDAP2_Filter|Net_LDAP2_Error - * @static - */ - public static function &combine($log_op, $filters) - { - if (PEAR::isError($filters)) { - return $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 = '!'; - - // tests for sane operation - if ($log_op == '!') { - // Not-combination, here we only accept one filter object or filter string - if ($filters instanceof Net_LDAP2_Filter) { - $filters = array($filters); // force array - } elseif (is_string($filters)) { - $filter_o = self::parse($filters); - if (PEAR::isError($filter_o)) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage()); - return $err; - } else { - $filters = array($filter_o); - } - } elseif (is_array($filters)) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!'); - return $err; - } else { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!'); - return $err; - } - } elseif ($log_op == '&' || $log_op == '|') { - if (!is_array($filters) || count($filters) < 2) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!'); - return $err; - } - } else { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!'); - return $err; - } - - $combined_filter = new Net_LDAP2_Filter(); - foreach ($filters as $key => $testfilter) { // check for errors - if (PEAR::isError($testfilter)) { - return $testfilter; - } elseif (is_string($testfilter)) { - // string found, try to parse into an filter object - $filter_o = self::parse($testfilter); - if (PEAR::isError($filter_o)) { - return $filter_o; - } else { - $filters[$key] = $filter_o; - } - } elseif (!$testfilter instanceof Net_LDAP2_Filter) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!'); - return $err; - } - } - - $combined_filter->_subfilters = $filters; - $combined_filter->_match = $log_op; - return $combined_filter; - } - - /** - * Parse FILTER into a Net_LDAP2_Filter object - * - * This parses an filter string into Net_LDAP2_Filter objects. - * - * @param string $FILTER The filter string - * - * @access static - * @return Net_LDAP2_Filter|Net_LDAP2_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) - */ - 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 == "!") { - return PEAR::raiseError("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 - return PEAR::raiseError("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); - if (PEAR::isError($o)) { - return $o; - } else { - 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" - - // detect multiple leaf components - // [TODO] Maybe this will make problems with filters containing brackets inside the value - if (stristr($matches[1], ')(')) { - return PEAR::raiseError("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) { - return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used"); - } else { - $filter_o = new Net_LDAP2_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 = Net_LDAP2_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; - } - } - } - } else { - // ERROR: Filter components must be enclosed in round brackets - return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets"); - } - } - - /** - * Get the string representation of this filter - * - * 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. - * - * @return string|Net_LDAP2_Error - */ - public function asString() - { - if ($this->isLeaf()) { - $return = $this->_filter; - } else { - $return = ''; - foreach ($this->_subfilters as $filter) { - $return = $return.$filter->asString(); - } - $return = '(' . $this->_match . $return . ')'; - } - return $return; - } - - /** - * Alias for perl interface as_string() - * - * @see asString() - * @return string|Net_LDAP2_Error - */ - public function as_string() - { - return $this->asString(); - } - - /** - * 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|Net_LDAP2_Error - */ - public function printMe($FH = false) - { - if (!is_resource($FH)) { - if (PEAR::isError($FH)) { - return $FH; - } - $filter_str = $this->asString(); - if (PEAR::isError($filter_str)) { - return $filter_str; - } else { - print($filter_str); - } - } else { - $filter_str = $this->asString(); - if (PEAR::isError($filter_str)) { - return $filter_str; - } else { - $res = @fwrite($FH, $this->asString()); - if ($res == false) { - return PEAR::raiseError("Unable to write filter string to filehandle \$FH!"); - } - } - } - return true; - } - - /** - * 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) - * - * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}. - * For upward compatibiliy reasons you are strongly encouraged to use the escape - * methods provided by the Net_LDAP2_Util class. - * - * @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 Net_LDAP2_Util::escape_filter_value() directly - */ - public static function escape($value) - { - $return = Net_LDAP2_Util::escape_filter_value(array($value)); - return $return[0]; - } - - /** - * Is this a container or a leaf filter object? - * - * @access protected - * @return boolean - */ - protected function isLeaf() - { - if (count($this->_subfilters) > 0) { - return false; // Container! - } else { - return true; // Leaf! - } - } -} -?> |