Updated LDAP2 extlib to latest version.
This commit is contained in:
parent
a6545d09b8
commit
ee41bc560c
|
@ -13,7 +13,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
|
* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $
|
* @version SVN: $Id: LDAP2.php 332308 2013-12-09 09:15:47Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ define('NET_LDAP2_ERROR', 1000);
|
||||||
/**
|
/**
|
||||||
* Net_LDAP2 Version
|
* Net_LDAP2 Version
|
||||||
*/
|
*/
|
||||||
define('NET_LDAP2_VERSION', '2.0.7');
|
define('NET_LDAP2_VERSION', '2.1.0');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Net_LDAP2 - manipulate LDAP servers the right way!
|
* Net_LDAP2 - manipulate LDAP servers the right way!
|
||||||
|
@ -612,30 +612,47 @@ class Net_LDAP2 extends PEAR
|
||||||
*/
|
*/
|
||||||
public function startTLS()
|
public function startTLS()
|
||||||
{
|
{
|
||||||
// Test to see if the server supports TLS first.
|
/* Test to see if the server supports TLS first.
|
||||||
// This is done via testing the extensions offered by the server.
|
This is done via testing the extensions offered by the server.
|
||||||
// The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported.
|
The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported.
|
||||||
|
Note, that not all servers allow to feth either the rootDSE or
|
||||||
|
attributes over an unencrypted channel, so we must ignore errors. */
|
||||||
$rootDSE = $this->rootDse();
|
$rootDSE = $this->rootDse();
|
||||||
if (self::isError($rootDSE)) {
|
if (self::isError($rootDSE)) {
|
||||||
return $this->raiseError("Unable to fetch rootDSE entry ".
|
/* IGNORE this error, because server may refuse fetching the
|
||||||
"to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode());
|
RootDSE over an unencrypted connection. */
|
||||||
}
|
//return $this->raiseError("Unable to fetch rootDSE entry ".
|
||||||
|
//"to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode());
|
||||||
$supported_extensions = $rootDSE->getValue('supportedExtension');
|
|
||||||
if (self::isError($supported_extensions)) {
|
|
||||||
return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ".
|
|
||||||
"to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) {
|
|
||||||
if (false === @ldap_start_tls($this->_link)) {
|
|
||||||
return $this->raiseError("TLS not started: " .
|
|
||||||
@ldap_error($this->_link),
|
|
||||||
@ldap_errno($this->_link));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return $this->raiseError("Server reports that it does not support TLS");
|
/* Fetch suceeded, see, if the server supports TLS. Again, we
|
||||||
|
ignore errors, because the server may refuse to return
|
||||||
|
attributes over unencryted connections. */
|
||||||
|
$supported_extensions = $rootDSE->getValue('supportedExtension');
|
||||||
|
if (self::isError($supported_extensions)) {
|
||||||
|
/* IGNORE error, because server may refuse attribute
|
||||||
|
returning over an unencrypted connection. */
|
||||||
|
//return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ".
|
||||||
|
//"to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode());
|
||||||
|
} else {
|
||||||
|
// fetch succeedet, lets see if the server supports it.
|
||||||
|
// if not, then drop an error. If supported, then do nothing,
|
||||||
|
// because then we try to issue TLS afterwards.
|
||||||
|
if (!in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) {
|
||||||
|
return $this->raiseError("Server reports that it does not support TLS.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to establish TLS.
|
||||||
|
if (false === @ldap_start_tls($this->_link)) {
|
||||||
|
// Starting TLS failed. This may be an error, or because
|
||||||
|
// the server does not support it but did not enable us to
|
||||||
|
// detect that above.
|
||||||
|
return $this->raiseError("TLS could not be started: " .
|
||||||
|
@ldap_error($this->_link),
|
||||||
|
@ldap_errno($this->_link));
|
||||||
|
} else {
|
||||||
|
return true; // TLS is started now.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,7 +745,7 @@ class Net_LDAP2 extends PEAR
|
||||||
// We have a failure. What type? We may be able to reconnect
|
// We have a failure. What type? We may be able to reconnect
|
||||||
// and try again.
|
// and try again.
|
||||||
$error_code = @ldap_errno($link);
|
$error_code = @ldap_errno($link);
|
||||||
$error_name = $this->errorMessage($error_code);
|
$error_name = Net_LDAP2::errorMessage($error_code);
|
||||||
|
|
||||||
if (($error_name === 'LDAP_OPERATIONS_ERROR') &&
|
if (($error_name === 'LDAP_OPERATIONS_ERROR') &&
|
||||||
($this->_config['auto_reconnect'])) {
|
($this->_config['auto_reconnect'])) {
|
||||||
|
@ -802,9 +819,9 @@ class Net_LDAP2 extends PEAR
|
||||||
// We have a failure. What type?
|
// We have a failure. What type?
|
||||||
// We may be able to reconnect and try again.
|
// We may be able to reconnect and try again.
|
||||||
$error_code = @ldap_errno($link);
|
$error_code = @ldap_errno($link);
|
||||||
$error_name = $this->errorMessage($error_code);
|
$error_name = Net_LDAP2::errorMessage($error_code);
|
||||||
|
|
||||||
if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
||||||
($this->_config['auto_reconnect'])) {
|
($this->_config['auto_reconnect'])) {
|
||||||
// The server has become disconnected before trying the
|
// The server has become disconnected before trying the
|
||||||
// operation. We should try again, possibly with a
|
// operation. We should try again, possibly with a
|
||||||
|
@ -898,9 +915,9 @@ class Net_LDAP2 extends PEAR
|
||||||
// We have a failure. What type? We may be able to reconnect
|
// We have a failure. What type? We may be able to reconnect
|
||||||
// and try again.
|
// and try again.
|
||||||
$error_code = $msg->getCode();
|
$error_code = $msg->getCode();
|
||||||
$error_name = $this->errorMessage($error_code);
|
$error_name = Net_LDAP2::errorMessage($error_code);
|
||||||
|
|
||||||
if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
||||||
($this->_config['auto_reconnect'])) {
|
($this->_config['auto_reconnect'])) {
|
||||||
|
|
||||||
// The server has become disconnected before trying the
|
// The server has become disconnected before trying the
|
||||||
|
@ -937,9 +954,9 @@ class Net_LDAP2 extends PEAR
|
||||||
// We have a failure. What type? We may be able to reconnect
|
// We have a failure. What type? We may be able to reconnect
|
||||||
// and try again.
|
// and try again.
|
||||||
$error_code = $msg->getCode();
|
$error_code = $msg->getCode();
|
||||||
$error_name = $this->errorMessage($error_code);
|
$error_name = Net_LDAP2::errorMessage($error_code);
|
||||||
|
|
||||||
if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
|
||||||
($this->_config['auto_reconnect'])) {
|
($this->_config['auto_reconnect'])) {
|
||||||
|
|
||||||
// The server has become disconnected before trying the
|
// The server has become disconnected before trying the
|
||||||
|
@ -1078,14 +1095,14 @@ class Net_LDAP2 extends PEAR
|
||||||
return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
|
return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
|
||||||
} elseif ($err == 87) {
|
} elseif ($err == 87) {
|
||||||
// bad search filter
|
// bad search filter
|
||||||
return $this->raiseError($this->errorMessage($err) . "($filter)", $err);
|
return $this->raiseError(Net_LDAP2::errorMessage($err) . "($filter)", $err);
|
||||||
} elseif (($err == 1) && ($this->_config['auto_reconnect'])) {
|
} elseif (($err == 1) && ($this->_config['auto_reconnect'])) {
|
||||||
// Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect.
|
// Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect.
|
||||||
$this->_link = false;
|
$this->_link = false;
|
||||||
$this->performReconnect();
|
$this->performReconnect();
|
||||||
} else {
|
} else {
|
||||||
$msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope";
|
$msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope";
|
||||||
return $this->raiseError($this->errorMessage($err) . $msg, $err);
|
return $this->raiseError(Net_LDAP2::errorMessage($err) . $msg, $err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return $obj = new Net_LDAP2_Search($search, $this, $attributes);
|
return $obj = new Net_LDAP2_Search($search, $this, $attributes);
|
||||||
|
@ -1114,7 +1131,7 @@ class Net_LDAP2 extends PEAR
|
||||||
$msg = @ldap_err2str($err);
|
$msg = @ldap_err2str($err);
|
||||||
} else {
|
} else {
|
||||||
$err = NET_LDAP2_ERROR;
|
$err = NET_LDAP2_ERROR;
|
||||||
$msg = $this->errorMessage($err);
|
$msg = Net_LDAP2::errorMessage($err);
|
||||||
}
|
}
|
||||||
return $this->raiseError($msg, $err);
|
return $this->raiseError($msg, $err);
|
||||||
}
|
}
|
||||||
|
@ -1146,7 +1163,7 @@ class Net_LDAP2 extends PEAR
|
||||||
$msg = @ldap_err2str($err);
|
$msg = @ldap_err2str($err);
|
||||||
} else {
|
} else {
|
||||||
$err = NET_LDAP2_ERROR;
|
$err = NET_LDAP2_ERROR;
|
||||||
$msg = $this->errorMessage($err);
|
$msg = Net_LDAP2::errorMessage($err);
|
||||||
}
|
}
|
||||||
return $this->raiseError($msg, $err);
|
return $this->raiseError($msg, $err);
|
||||||
}
|
}
|
||||||
|
@ -1239,30 +1256,21 @@ class Net_LDAP2 extends PEAR
|
||||||
return PEAR::raiseError('Parameter $dn is not a string nor an entry object!');
|
return PEAR::raiseError('Parameter $dn is not a string nor an entry object!');
|
||||||
}
|
}
|
||||||
|
|
||||||
// make dn relative to parent
|
// search LDAP for that DN by performing a baselevel search for any
|
||||||
$base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false));
|
// object. We can only find the DN in question this way, or nothing.
|
||||||
if (self::isError($base)) {
|
$s_opts = array(
|
||||||
return $base;
|
'scope' => 'base',
|
||||||
}
|
'sizelimit' => 1,
|
||||||
$entry_rdn = array_shift($base);
|
'attributes' => '1.1' // select no attrs
|
||||||
if (is_array($entry_rdn)) {
|
);
|
||||||
// maybe the dn consist of a multivalued RDN, we must build the dn in this case
|
$search = $this->search($dn, '(objectClass=*)', $s_opts);
|
||||||
// because the $entry_rdn is an array!
|
|
||||||
$filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn);
|
|
||||||
}
|
|
||||||
$base = Net_LDAP2_Util::canonical_dn($base);
|
|
||||||
|
|
||||||
$result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1);
|
if (self::isError($search)) {
|
||||||
if (@ldap_count_entries($this->_link, $result)) {
|
return $search;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (ldap_errno($this->_link) == 32) {
|
|
||||||
return false;
|
// retun wehter the DN exists; that is, we found an entry
|
||||||
}
|
return ($search->count() == 0)? false : true;
|
||||||
if (ldap_errno($this->_link) != 0) {
|
|
||||||
return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1400,7 +1408,7 @@ class Net_LDAP2 extends PEAR
|
||||||
*
|
*
|
||||||
* @return string The errorstring for the error.
|
* @return string The errorstring for the error.
|
||||||
*/
|
*/
|
||||||
public function errorMessage($errorcode)
|
public static function errorMessage($errorcode)
|
||||||
{
|
{
|
||||||
$errorMessages = array(
|
$errorMessages = array(
|
||||||
0x00 => "LDAP_SUCCESS",
|
0x00 => "LDAP_SUCCESS",
|
||||||
|
@ -1629,7 +1637,7 @@ class Net_LDAP2 extends PEAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes given attributes to UTF8 if needed by schema
|
* Encodes given attributes from ISO-8859-1 to UTF-8 if needed by schema
|
||||||
*
|
*
|
||||||
* This function takes attributes in an array and then checks against the schema if they need
|
* This function takes attributes in an array and then checks against the schema if they need
|
||||||
* UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and
|
* UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and
|
||||||
|
@ -1650,7 +1658,7 @@ class Net_LDAP2 extends PEAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes the given attribute values if needed by schema
|
* Decodes the given attribute values from UTF-8 to ISO-8859-1 if needed by schema
|
||||||
*
|
*
|
||||||
* $attributes is expected to be an array with keys describing
|
* $attributes is expected to be an array with keys describing
|
||||||
* the attribute names and the values as the value of this attribute:
|
* the attribute names and the values as the value of this attribute:
|
||||||
|
@ -1668,7 +1676,7 @@ class Net_LDAP2 extends PEAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes or decodes attribute values if needed
|
* Encodes or decodes UTF-8/ISO-8859-1 attribute values if needed by schema
|
||||||
*
|
*
|
||||||
* @param array $attributes Array of attributes
|
* @param array $attributes Array of attributes
|
||||||
* @param array $function Function to apply to attribute values
|
* @param array $function Function to apply to attribute values
|
||||||
|
@ -1701,7 +1709,10 @@ class Net_LDAP2 extends PEAR
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) {
|
// Encoding is needed if this is a DIR_STR. We assume also
|
||||||
|
// needed encoding in case the schema contains no syntax
|
||||||
|
// information (he does not need to, see rfc2252, 4.2)
|
||||||
|
if (!array_key_exists('syntax', $attr) || false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) {
|
||||||
$encode = true;
|
$encode = true;
|
||||||
} else {
|
} else {
|
||||||
$encode = false;
|
$encode = false;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger
|
* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: Entry.php 286787 2009-08-04 06:03:12Z beni $
|
* @version SVN: $Id: Entry.php 332301 2013-12-09 08:17:14Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
* Includes
|
* Includes
|
||||||
*/
|
*/
|
||||||
require_once 'PEAR.php';
|
require_once 'PEAR.php';
|
||||||
require_once 'Util.php';
|
require_once 'Net/LDAP2/Util.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representation of a directory entry
|
* Object representation of a directory entry
|
||||||
|
@ -309,7 +309,7 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
public function dn($dn = null)
|
public function dn($dn = null)
|
||||||
{
|
{
|
||||||
if (false == is_null($dn)) {
|
if (false == is_null($dn)) {
|
||||||
if (is_null($this->_dn)) {
|
if (is_null($this->_dn) ) {
|
||||||
$this->_dn = $dn;
|
$this->_dn = $dn;
|
||||||
} else {
|
} else {
|
||||||
$this->_newdn = $dn;
|
$this->_newdn = $dn;
|
||||||
|
@ -419,6 +419,7 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
* The returned hash has the form
|
* The returned hash has the form
|
||||||
* <code>array('attributename' => 'single value',
|
* <code>array('attributename' => 'single value',
|
||||||
* 'attributename' => array('value1', value2', value3'))</code>
|
* 'attributename' => array('value1', value2', value3'))</code>
|
||||||
|
* Only attributes present at the entry will be returned.
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @return array Hash of all attributes with their values
|
* @return array Hash of all attributes with their values
|
||||||
|
@ -437,31 +438,59 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
*
|
*
|
||||||
* The first parameter is the name of the attribute
|
* The first parameter is the name of the attribute
|
||||||
* The second parameter influences the way the value is returned:
|
* The second parameter influences the way the value is returned:
|
||||||
* 'single': only the first value is returned as string
|
* 'single': only the first value is returned as string
|
||||||
* 'all': all values including the value count are returned in an
|
* 'all': all values are returned in an array
|
||||||
* array
|
|
||||||
* 'default': in all other cases an attribute value with a single value is
|
* 'default': in all other cases an attribute value with a single value is
|
||||||
* returned as string, if it has multiple values it is returned
|
* returned as string, if it has multiple values it is returned
|
||||||
* as an array (without value count)
|
* as an array
|
||||||
*
|
*
|
||||||
* @param string $attr Attribute name
|
* If the attribute is not set at this entry (no value or not defined in
|
||||||
* @param string $option Option
|
* schema), "false" is returned when $option is 'single', an empty string if
|
||||||
|
* 'default', and an empty array when 'all'.
|
||||||
|
*
|
||||||
|
* You may use Net_LDAP2_Schema->checkAttribute() to see if the attribute
|
||||||
|
* is defined for the objectClasses of this entry.
|
||||||
|
*
|
||||||
|
* @param string $attr Attribute name
|
||||||
|
* @param string $option Option
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @return string|array|PEAR_Error string, array or PEAR_Error
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
public function getValue($attr, $option = null)
|
public function getValue($attr, $option = null)
|
||||||
{
|
{
|
||||||
$attr = $this->getAttrName($attr);
|
$attr = $this->getAttrName($attr);
|
||||||
|
|
||||||
if (false == array_key_exists($attr, $this->_attributes)) {
|
// return depending on set $options
|
||||||
return PEAR::raiseError("Unknown attribute ($attr) requested");
|
if (!array_key_exists($attr, $this->_attributes)) {
|
||||||
}
|
// attribute not set
|
||||||
|
switch ($option) {
|
||||||
|
case 'single':
|
||||||
|
$value = false;
|
||||||
|
break;
|
||||||
|
case 'all':
|
||||||
|
$value = array();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$value = '';
|
||||||
|
}
|
||||||
|
|
||||||
$value = $this->_attributes[$attr];
|
} else {
|
||||||
|
// attribute present
|
||||||
if ($option == "single" || (count($value) == 1 && $option != 'all')) {
|
switch ($option) {
|
||||||
$value = array_shift($value);
|
case 'single':
|
||||||
|
$value = $this->_attributes[$attr][0];
|
||||||
|
break;
|
||||||
|
case 'all':
|
||||||
|
$value = $this->_attributes[$attr];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$value = $this->_attributes[$attr];
|
||||||
|
if (count($value) == 1) {
|
||||||
|
$value = array_shift($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
|
@ -529,6 +558,9 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
if (false == is_array($attr)) {
|
if (false == is_array($attr)) {
|
||||||
return PEAR::raiseError("Parameter must be an array");
|
return PEAR::raiseError("Parameter must be an array");
|
||||||
}
|
}
|
||||||
|
if ($this->isNew()) {
|
||||||
|
$this->setAttributes($attr);
|
||||||
|
}
|
||||||
foreach ($attr as $k => $v) {
|
foreach ($attr as $k => $v) {
|
||||||
$k = $this->getAttrName($k);
|
$k = $this->getAttrName($k);
|
||||||
if (false == is_array($v)) {
|
if (false == is_array($v)) {
|
||||||
|
@ -547,11 +579,12 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
$this->_attributes[$k] = $v;
|
$this->_attributes[$k] = $v;
|
||||||
}
|
}
|
||||||
// save changes for update()
|
// save changes for update()
|
||||||
if (empty($this->_changes["add"][$k])) {
|
if (!isset($this->_changes["add"][$k])) {
|
||||||
$this->_changes["add"][$k] = array();
|
$this->_changes["add"][$k] = array();
|
||||||
}
|
}
|
||||||
$this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v));
|
$this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v));
|
||||||
}
|
}
|
||||||
|
|
||||||
$return = true;
|
$return = true;
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
@ -760,6 +793,14 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
$this->_changes['replace'] = array();
|
$this->_changes['replace'] = array();
|
||||||
$this->_original = $this->_attributes;
|
$this->_original = $this->_attributes;
|
||||||
|
|
||||||
|
// In case the "new" entry was moved after creation, we must
|
||||||
|
// adjust the internal DNs as the entry was already created
|
||||||
|
// with the most current DN.
|
||||||
|
if (false == is_null($this->_newdn)) {
|
||||||
|
$this->_dn = $this->_newdn;
|
||||||
|
$this->_newdn = null;
|
||||||
|
}
|
||||||
|
|
||||||
$return = true;
|
$return = true;
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
@ -785,7 +826,8 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
$parent = Net_LDAP2_Util::canonical_dn($parent);
|
$parent = Net_LDAP2_Util::canonical_dn($parent);
|
||||||
|
|
||||||
// rename/move
|
// rename/move
|
||||||
if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) {
|
if (false == @ldap_rename($link, $this->_dn, $child, $parent, false)) {
|
||||||
|
|
||||||
return PEAR::raiseError("Entry not renamed: " .
|
return PEAR::raiseError("Entry not renamed: " .
|
||||||
@ldap_error($link), @ldap_errno($link));
|
@ldap_error($link), @ldap_errno($link));
|
||||||
}
|
}
|
||||||
|
@ -795,51 +837,55 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Carry out modifications to the entry
|
* Retrieve a entry that has all attributes we need so that the list of changes to build is created accurately
|
||||||
*/
|
*/
|
||||||
|
$fullEntry = $ldap->getEntry( $this->dn() );
|
||||||
|
if ( Net_LDAP2::isError($fullEntry) ) {
|
||||||
|
return PEAR::raiseError("Could not retrieve a full set of attributes to reconcile changes with");
|
||||||
|
}
|
||||||
|
$modifications = array();
|
||||||
|
|
||||||
// ADD
|
// ADD
|
||||||
foreach ($this->_changes["add"] as $attr => $value) {
|
foreach ($this->_changes["add"] as $attr => $value) {
|
||||||
// if attribute exists, add new values
|
// if attribute exists, we need to combine old and new values
|
||||||
if ($this->exists($attr)) {
|
if ($fullEntry->exists($attr)) {
|
||||||
if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) {
|
$currentValue = $fullEntry->getValue($attr, "all");
|
||||||
return PEAR::raiseError("Could not add new values to attribute $attr: " .
|
$value = array_merge( $currentValue, $value );
|
||||||
@ldap_error($link), @ldap_errno($link));
|
}
|
||||||
}
|
|
||||||
} else {
|
$modifications[$attr] = $value;
|
||||||
// new attribute
|
|
||||||
if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
|
|
||||||
return PEAR::raiseError("Could not add new attribute $attr: " .
|
|
||||||
@ldap_error($link), @ldap_errno($link));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// all went well here, I guess
|
|
||||||
unset($this->_changes["add"][$attr]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
foreach ($this->_changes["delete"] as $attr => $value) {
|
foreach ($this->_changes["delete"] as $attr => $value) {
|
||||||
// In LDAPv3 you need to specify the old values for deleting
|
// In LDAPv3 you need to specify the old values for deleting
|
||||||
if (is_null($value) && $ldap->getLDAPVersion() === 3) {
|
if (is_null($value) && $ldap->getLDAPVersion() === 3) {
|
||||||
$value = $this->_original[$attr];
|
$value = $fullEntry->getValue($attr);
|
||||||
}
|
}
|
||||||
if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) {
|
if (!is_array($value)) {
|
||||||
return PEAR::raiseError("Could not delete attribute $attr: " .
|
$value = array($value);
|
||||||
@ldap_error($link), @ldap_errno($link));
|
|
||||||
}
|
}
|
||||||
unset($this->_changes["delete"][$attr]);
|
|
||||||
|
// Find out what is missing from $value and exclude it
|
||||||
|
$currentValue = isset($modifications[$attr]) ? $modifications[$attr] : $fullEntry->getValue($attr, "all");
|
||||||
|
$modifications[$attr] = array_values( array_diff( $currentValue, $value ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// REPLACE
|
// REPLACE
|
||||||
foreach ($this->_changes["replace"] as $attr => $value) {
|
foreach ($this->_changes["replace"] as $attr => $value) {
|
||||||
if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
|
$modifications[$attr] = $value;
|
||||||
return PEAR::raiseError("Could not replace attribute $attr values: " .
|
|
||||||
@ldap_error($link), @ldap_errno($link));
|
|
||||||
}
|
|
||||||
unset($this->_changes["replace"][$attr]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// all went well, so _original (server) becomes _attributes (local copy)
|
// COMMIT
|
||||||
$this->_original = $this->_attributes;
|
if (false === @ldap_modify($link, $this->dn(), $modifications)) {
|
||||||
|
return PEAR::raiseError("Could not modify the entry: " . @ldap_error($link), @ldap_errno($link));
|
||||||
|
}
|
||||||
|
|
||||||
|
// all went well, so _original (server) becomes _attributes (local copy), reset _changes too...
|
||||||
|
$this->_changes['add'] = array();
|
||||||
|
$this->_changes['delete'] = array();
|
||||||
|
$this->_changes['replace'] = array();
|
||||||
|
$this->_original = $this->_attributes;
|
||||||
|
|
||||||
$return = true;
|
$return = true;
|
||||||
return $return;
|
return $return;
|
||||||
|
@ -964,11 +1010,6 @@ class Net_LDAP2_Entry extends PEAR
|
||||||
|
|
||||||
// fetch attribute values
|
// fetch attribute values
|
||||||
$attr = $this->getValue($attr_name, 'all');
|
$attr = $this->getValue($attr_name, 'all');
|
||||||
if (Net_LDAP2::isError($attr)) {
|
|
||||||
return $attr;
|
|
||||||
} else {
|
|
||||||
unset($attr['count']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform preg_match() on all values
|
// perform preg_match() on all values
|
||||||
$match = false;
|
$match = false;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Benedikt Hallinger
|
* @copyright 2009 Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $
|
* @version SVN: $Id: Filter.php 332305 2013-12-09 08:51:41Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
* Includes
|
* Includes
|
||||||
*/
|
*/
|
||||||
require_once 'PEAR.php';
|
require_once 'PEAR.php';
|
||||||
require_once 'Util.php';
|
require_once 'Net/LDAP2/Util.php';
|
||||||
|
require_once 'Net/LDAP2/Entry.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representation of a part of a LDAP filter.
|
* Object representation of a part of a LDAP filter.
|
||||||
|
@ -134,6 +135,9 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
* - lessOrEqual: The attributes value is less or equal than $value
|
* - lessOrEqual: The attributes value is less or equal than $value
|
||||||
* - approx: One of the attributes values is similar to $value
|
* - approx: One of the attributes values is similar to $value
|
||||||
*
|
*
|
||||||
|
* Negation ("not") can be done by prepending the above operators with the
|
||||||
|
* "not" or "!" keyword, see example below.
|
||||||
|
*
|
||||||
* If $escape is set to true (default) then $value will be escaped
|
* 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.
|
* 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()}!
|
* You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}!
|
||||||
|
@ -141,10 +145,13 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
* Examples:
|
* Examples:
|
||||||
* <code>
|
* <code>
|
||||||
* // This will find entries that contain an attribute "sn" that ends with "foobar":
|
* // This will find entries that contain an attribute "sn" that ends with "foobar":
|
||||||
* $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar');
|
* $filter = Net_LDAP2_Filter::create('sn', 'ends', 'foobar');
|
||||||
*
|
*
|
||||||
* // This will find entries that contain an attribute "sn" that has any value set:
|
* // This will find entries that contain an attribute "sn" that has any value set:
|
||||||
* $filter = new Net_LDAP2_Filter('sn', 'any');
|
* $filter = Net_LDAP2_Filter::create('sn', 'any');
|
||||||
|
*
|
||||||
|
* // This will build a negated equals filter:
|
||||||
|
* $filter = Net_LDAP2_Filter::create('sn', 'not equals', 'foobar');
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @param string $attr_name Name of the attribute the filter should apply to
|
* @param string $attr_name Name of the attribute the filter should apply to
|
||||||
|
@ -161,8 +168,22 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
$array = Net_LDAP2_Util::escape_filter_value(array($value));
|
$array = Net_LDAP2_Util::escape_filter_value(array($value));
|
||||||
$value = $array[0];
|
$value = $array[0];
|
||||||
}
|
}
|
||||||
switch (strtolower($match)) {
|
|
||||||
|
$match = strtolower($match);
|
||||||
|
|
||||||
|
// detect negation
|
||||||
|
$neg_matches = array();
|
||||||
|
$negate_filter = false;
|
||||||
|
if (preg_match('/^(?:not|!)[\s_-](.+)/', $match, $neg_matches)) {
|
||||||
|
$negate_filter = true;
|
||||||
|
$match = $neg_matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// build basic filter
|
||||||
|
switch ($match) {
|
||||||
case 'equals':
|
case 'equals':
|
||||||
|
case '=':
|
||||||
|
case '==':
|
||||||
$leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')';
|
$leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')';
|
||||||
break;
|
break;
|
||||||
case 'begins':
|
case 'begins':
|
||||||
|
@ -175,9 +196,11 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
$leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)';
|
$leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)';
|
||||||
break;
|
break;
|
||||||
case 'greater':
|
case 'greater':
|
||||||
|
case '>':
|
||||||
$leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')';
|
$leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')';
|
||||||
break;
|
break;
|
||||||
case 'less':
|
case 'less':
|
||||||
|
case '<':
|
||||||
$leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')';
|
$leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')';
|
||||||
break;
|
break;
|
||||||
case 'greaterorequal':
|
case 'greaterorequal':
|
||||||
|
@ -199,6 +222,12 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
default:
|
default:
|
||||||
return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!');
|
return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// negate if requested
|
||||||
|
if ($negate_filter) {
|
||||||
|
$leaf_filter = Net_LDAP2_Filter::combine('!', $leaf_filter);
|
||||||
|
}
|
||||||
|
|
||||||
return $leaf_filter;
|
return $leaf_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,10 +236,10 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
*
|
*
|
||||||
* This static method combines two or more filter objects and returns one single
|
* This static method combines two or more filter objects and returns one single
|
||||||
* filter object that contains all the others.
|
* filter object that contains all the others.
|
||||||
* Call this method statically: $filter = Net_LDAP2_Filter('or', array($filter1, $filter2))
|
* Call this method statically: $filter = Net_LDAP2_Filter::combine('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, we will try to parse them.
|
||||||
*
|
*
|
||||||
* @param string $log_op The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!"
|
* @param string $log_op The locical operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!"
|
||||||
* @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects
|
* @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects
|
||||||
*
|
*
|
||||||
* @return Net_LDAP2_Filter|Net_LDAP2_Error
|
* @return Net_LDAP2_Filter|Net_LDAP2_Error
|
||||||
|
@ -241,8 +270,13 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
$filters = array($filter_o);
|
$filters = array($filter_o);
|
||||||
}
|
}
|
||||||
} elseif (is_array($filters)) {
|
} elseif (is_array($filters)) {
|
||||||
$err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!');
|
if (count($filters) != 1) {
|
||||||
return $err;
|
$err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!');
|
||||||
|
return $err;
|
||||||
|
} elseif (!($filters[0] instanceof Net_LDAP2_Filter)) {
|
||||||
|
$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;
|
||||||
|
}
|
||||||
} else {
|
} 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!');
|
$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;
|
return $err;
|
||||||
|
@ -294,6 +328,17 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
public static function parse($FILTER)
|
public static function parse($FILTER)
|
||||||
{
|
{
|
||||||
if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) {
|
if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) {
|
||||||
|
// Check for right bracket syntax: count of unescaped opening
|
||||||
|
// brackets must match count of unescaped closing brackets.
|
||||||
|
// At this stage we may have:
|
||||||
|
// 1. one filter component with already removed outer brackets
|
||||||
|
// 2. one or more subfilter components
|
||||||
|
$c_openbracks = preg_match_all('/(?<!\\\\)\(/' , $matches[1], $notrelevant);
|
||||||
|
$c_closebracks = preg_match_all('/(?<!\\\\)\)/' , $matches[1], $notrelevant);
|
||||||
|
if ($c_openbracks != $c_closebracks) {
|
||||||
|
return PEAR::raiseError("Filter parsing error: invalid filter syntax - opening brackets do not match close brackets!");
|
||||||
|
}
|
||||||
|
|
||||||
if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) {
|
if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) {
|
||||||
// Subfilter processing: pass subfilters to parse() and combine
|
// Subfilter processing: pass subfilters to parse() and combine
|
||||||
// the objects using the logical operator detected
|
// the objects using the logical operator detected
|
||||||
|
@ -378,7 +423,7 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
if (stristr($matches[1], ')(')) {
|
if (stristr($matches[1], ')(')) {
|
||||||
return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!");
|
return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!");
|
||||||
} else {
|
} else {
|
||||||
$filter_parts = preg_split('/(?<!\\\\)(=|=~|>|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE);
|
$filter_parts = Net_LDAP2_Util::split_attribute_string($matches[1], true, true);
|
||||||
if (count($filter_parts) != 3) {
|
if (count($filter_parts) != 3) {
|
||||||
return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used");
|
return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used");
|
||||||
} else {
|
} else {
|
||||||
|
@ -510,5 +555,121 @@ class Net_LDAP2_Filter extends PEAR
|
||||||
return true; // Leaf!
|
return true; // Leaf!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter entries using this filter or see if a filter matches
|
||||||
|
*
|
||||||
|
* @todo Currently slow and naive implementation with preg_match, could be optimized (esp. begins, ends filters etc)
|
||||||
|
* @todo Currently only "="-based matches (equals, begins, ends, contains, any) implemented; Implement all the stuff!
|
||||||
|
* @todo Implement expert code with schema checks in case $entry is connected to a directory
|
||||||
|
* @param array|Net_LDAP2_Entry The entry (or array with entries) to check
|
||||||
|
* @param array If given, the array will be appended with entries who matched the filter. Return value is true if any entry matched.
|
||||||
|
* @return int|Net_LDAP2_Error Returns the number of matched entries or error
|
||||||
|
*/
|
||||||
|
function matches(&$entries, &$results=array()) {
|
||||||
|
$numOfMatches = 0;
|
||||||
|
|
||||||
|
if (!is_array($entries)) {
|
||||||
|
$all_entries = array(&$entries);
|
||||||
|
} else {
|
||||||
|
$all_entries = &$entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($all_entries as $entry) {
|
||||||
|
// look at the current entry and see if filter matches
|
||||||
|
|
||||||
|
$entry_matched = false;
|
||||||
|
// if this is not a single component, do calculate all subfilters,
|
||||||
|
// then assert the partial results with the given combination modifier
|
||||||
|
if (!$this->isLeaf()) {
|
||||||
|
|
||||||
|
// get partial results from subfilters
|
||||||
|
$partial_results = array();
|
||||||
|
foreach ($this->_subfilters as $filter) {
|
||||||
|
$partial_results[] = $filter->matches($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate partial results using this filters combination rule
|
||||||
|
switch ($this->_match) {
|
||||||
|
case '!':
|
||||||
|
// result is the neagtive result of the assertion
|
||||||
|
$entry_matched = !$partial_results[0];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
// all partial results have to be boolean-true
|
||||||
|
$entry_matched = !in_array(false, $partial_results);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
// at least one partial result has to be true
|
||||||
|
$entry_matched = in_array(true, $partial_results);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Leaf filter: assert given entry
|
||||||
|
// [TODO]: Could be optimized to avoid preg_match especially with "ends", "begins" etc
|
||||||
|
|
||||||
|
// Translate the LDAP-match to some preg_match expression and evaluate it
|
||||||
|
list($attribute, $match, $assertValue) = $this->getComponents();
|
||||||
|
switch ($match) {
|
||||||
|
case '=':
|
||||||
|
$regexp = '/^'.str_replace('*', '.*', $assertValue).'$/i'; // not case sensitive unless specified by schema
|
||||||
|
$entry_matched = $entry->pregMatch($regexp, $attribute);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// [TODO]: implement <, >, <=, >= and =~
|
||||||
|
// -------------------------------------
|
||||||
|
|
||||||
|
default:
|
||||||
|
$err = PEAR::raiseError("Net_LDAP2_Filter match error: unsupported match rule '$match'!");
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// process filter matching result
|
||||||
|
if ($entry_matched) {
|
||||||
|
$numOfMatches++;
|
||||||
|
$results[] = $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $numOfMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve this leaf-filters attribute, match and value component.
|
||||||
|
*
|
||||||
|
* For leaf filters, this returns array(attr, match, value).
|
||||||
|
* Match is be the logical operator, not the text representation,
|
||||||
|
* eg "=" instead of "equals". Note that some operators are really
|
||||||
|
* a combination of operator+value with wildcard, like
|
||||||
|
* "begins": That will return "=" with the value "value*"!
|
||||||
|
*
|
||||||
|
* For non-leaf filters this will drop an error.
|
||||||
|
*
|
||||||
|
* @todo $this->_match is not always available and thus not usable here; it would be great if it would set in the factory methods and constructor.
|
||||||
|
* @return array|Net_LDAP2_Error
|
||||||
|
*/
|
||||||
|
function getComponents() {
|
||||||
|
if ($this->isLeaf()) {
|
||||||
|
$raw_filter = preg_replace('/^\(|\)$/', '', $this->_filter);
|
||||||
|
$parts = Net_LDAP2_Util::split_attribute_string($raw_filter, true, true);
|
||||||
|
if (count($parts) != 3) {
|
||||||
|
return PEAR::raiseError("Net_LDAP2_Filter getComponents() error: invalid filter syntax - unknown matching rule used");
|
||||||
|
} else {
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return PEAR::raiseError('Net_LDAP2_Filter getComponents() call is invalid for non-leaf filters!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Benedikt Hallinger
|
* @copyright 2009 Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: LDIF.php 286718 2009-08-03 07:30:49Z beni $
|
* @version SVN: $Id: LDIF.php 324918 2012-04-06 12:31:04Z clockwerx $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -340,6 +340,7 @@ class Net_LDAP2_LDIF extends PEAR
|
||||||
+ count($entry_attrs_changes['replace'])
|
+ count($entry_attrs_changes['replace'])
|
||||||
+ count($entry_attrs_changes['delete']);
|
+ count($entry_attrs_changes['delete']);
|
||||||
|
|
||||||
|
|
||||||
$is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved());
|
$is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved());
|
||||||
|
|
||||||
// write version if not done yet
|
// write version if not done yet
|
||||||
|
@ -556,10 +557,10 @@ class Net_LDAP2_LDIF extends PEAR
|
||||||
$attributes = array();
|
$attributes = array();
|
||||||
$dn = false;
|
$dn = false;
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
if (preg_match('/^(\w+)(:|::|:<)\s(.+)$/', $line, $matches)) {
|
if (preg_match('/^(\w+(;binary)?)(:|::|:<)\s(.+)$/', $line, $matches)) {
|
||||||
$attr =& $matches[1];
|
$attr =& $matches[1] . $matches[2];
|
||||||
$delim =& $matches[2];
|
$delim =& $matches[3];
|
||||||
$data =& $matches[3];
|
$data =& $matches[4];
|
||||||
|
|
||||||
if ($delim == ':') {
|
if ($delim == ':') {
|
||||||
// normal data
|
// normal data
|
||||||
|
@ -682,20 +683,22 @@ class Net_LDAP2_LDIF extends PEAR
|
||||||
if (preg_match('/^version:\s(.+)$/', $data, $match)) {
|
if (preg_match('/^version:\s(.+)$/', $data, $match)) {
|
||||||
// version statement, set version
|
// version statement, set version
|
||||||
$this->version($match[1]);
|
$this->version($match[1]);
|
||||||
} elseif (preg_match('/^\w+::?\s.+$/', $data)) {
|
} elseif (preg_match('/^\w+(;binary)?::?\s.+$/', $data)) {
|
||||||
// normal attribute: add line
|
// normal attribute: add line
|
||||||
$commentmode = false;
|
$commentmode = false;
|
||||||
$this->_lines_next[] = trim($data);
|
$this->_lines_next[] = trim($data);
|
||||||
$datalines_read++;
|
$datalines_read++;
|
||||||
} elseif (preg_match('/^\s(.+)$/', $data, $matches)) {
|
} elseif (preg_match('/^\s(.+)$/', $data, $matches)) {
|
||||||
// wrapped data: unwrap if not in comment mode
|
// wrapped data: unwrap if not in comment mode
|
||||||
|
// note that the \s above is some more liberal than
|
||||||
|
// the RFC requests as it also matches tabs etc.
|
||||||
if (!$commentmode) {
|
if (!$commentmode) {
|
||||||
if ($datalines_read == 0) {
|
if ($datalines_read == 0) {
|
||||||
// first line of entry: wrapped data is illegal
|
// first line of entry: wrapped data is illegal
|
||||||
$this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line);
|
$this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line);
|
||||||
} else {
|
} else {
|
||||||
$last = array_pop($this->_lines_next);
|
$last = array_pop($this->_lines_next);
|
||||||
$last = $last.trim($matches[1]);
|
$last = $last.$matches[1];
|
||||||
$this->_lines_next[] = $last;
|
$this->_lines_next[] = $last;
|
||||||
$datalines_read++;
|
$datalines_read++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Jan Wagner, Benedikt Hallinger
|
* @copyright 2009 Jan Wagner, Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $
|
* @version SVN: $Id: Schema.php 296515 2010-03-22 14:46:41Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
* @todo see the comment at the end of the file
|
* @todo see the comment at the end of the file
|
||||||
*/
|
*/
|
||||||
|
@ -168,12 +168,16 @@ class Net_LDAP2_Schema extends PEAR
|
||||||
array('attributes' => array_values($schema_o->types),
|
array('attributes' => array_values($schema_o->types),
|
||||||
'scope' => 'base'));
|
'scope' => 'base'));
|
||||||
if (Net_LDAP2::isError($result)) {
|
if (Net_LDAP2::isError($result)) {
|
||||||
return $result;
|
return PEAR::raiseError('Could not fetch Subschema entry: '.$result->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$entry = $result->shiftEntry();
|
$entry = $result->shiftEntry();
|
||||||
if (!$entry instanceof Net_LDAP2_Entry) {
|
if (!$entry instanceof Net_LDAP2_Entry) {
|
||||||
return PEAR::raiseError('Could not fetch Subschema entry');
|
if ($entry instanceof Net_LDAP2_Error) {
|
||||||
|
return PEAR::raiseError('Could not fetch Subschema entry: '.$entry->getMessage());
|
||||||
|
} else {
|
||||||
|
return PEAR::raiseError('Could not fetch Subschema entry (search returned '.$result->count().' entries. Check parameter \'basedn\')');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$schema_o->parse($entry);
|
$schema_o->parse($entry);
|
||||||
|
@ -183,7 +187,7 @@ class Net_LDAP2_Schema extends PEAR
|
||||||
/**
|
/**
|
||||||
* Return a hash of entries for the given type
|
* Return a hash of entries for the given type
|
||||||
*
|
*
|
||||||
* Returns a hash of entry for th givene type. Types may be:
|
* Returns a hash of entry for the givene type. Types may be:
|
||||||
* objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
|
* objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
|
||||||
* matchingruleuses, nameforms, syntaxes
|
* matchingruleuses, nameforms, syntaxes
|
||||||
*
|
*
|
||||||
|
@ -508,9 +512,111 @@ class Net_LDAP2_Schema extends PEAR
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [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
|
* See if an schema element exists
|
||||||
// be able to return it just "flat", e.g. array_merge()d.
|
*
|
||||||
// We could use get_all() to achieve this easily, i think
|
* @param string $type Type of name, see get()
|
||||||
|
* @param string $name Name or OID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function exists($type, $name)
|
||||||
|
{
|
||||||
|
$entry = $this->get($type, $name);
|
||||||
|
if ($entry instanceof Net_LDAP2_ERROR) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if an attribute is defined in the schema
|
||||||
|
*
|
||||||
|
* @param string $attribute Name or OID of the attribute
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function attributeExists($attribute)
|
||||||
|
{
|
||||||
|
return $this->exists('attribute', $attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if an objectClass is defined in the schema
|
||||||
|
*
|
||||||
|
* @param string $ocl Name or OID of the objectClass
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function objectClassExists($ocl)
|
||||||
|
{
|
||||||
|
return $this->exists('objectclass', $ocl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See to which ObjectClasses an attribute is assigned
|
||||||
|
*
|
||||||
|
* The objectclasses are sorted into the keys 'may' and 'must'.
|
||||||
|
*
|
||||||
|
* @param string $attribute Name or OID of the attribute
|
||||||
|
*
|
||||||
|
* @return array|Net_LDAP2_Error Associative array with OCL names or Error
|
||||||
|
*/
|
||||||
|
public function getAssignedOCLs($attribute)
|
||||||
|
{
|
||||||
|
$may = array();
|
||||||
|
$must = array();
|
||||||
|
|
||||||
|
// Test if the attribute type is defined in the schema,
|
||||||
|
// if so, retrieve real name for lookups
|
||||||
|
$attr_entry = $this->get('attribute', $attribute);
|
||||||
|
if ($attr_entry instanceof Net_LDAP2_ERROR) {
|
||||||
|
return PEAR::raiseError("Attribute $attribute not defined in schema: ".$attr_entry->getMessage());
|
||||||
|
} else {
|
||||||
|
$attribute = $attr_entry['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// We need to get all defined OCLs for this.
|
||||||
|
$ocls = $this->getAll('objectclasses');
|
||||||
|
foreach ($ocls as $ocl => $ocl_data) {
|
||||||
|
// Fetch the may and must attrs and see if our searched attr is contained.
|
||||||
|
// If so, record it in the corresponding array.
|
||||||
|
$ocl_may_attrs = $this->may($ocl);
|
||||||
|
$ocl_must_attrs = $this->must($ocl);
|
||||||
|
if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) {
|
||||||
|
array_push($may, $ocl_data['name']);
|
||||||
|
}
|
||||||
|
if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) {
|
||||||
|
array_push($must, $ocl_data['name']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('may' => $may, 'must' => $must);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if an attribute is available in a set of objectClasses
|
||||||
|
*
|
||||||
|
* @param string $attribute Attribute name or OID
|
||||||
|
* @param array $ocls Names of OCLs to check for
|
||||||
|
*
|
||||||
|
* @return boolean TRUE, if the attribute is defined for at least one of the OCLs
|
||||||
|
*/
|
||||||
|
public function checkAttribute($attribute, $ocls)
|
||||||
|
{
|
||||||
|
foreach ($ocls as $ocl) {
|
||||||
|
$ocl_entry = $this->get('objectclass', $ocl);
|
||||||
|
$ocl_may_attrs = $this->may($ocl);
|
||||||
|
$ocl_must_attrs = $this->must($ocl);
|
||||||
|
if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // no ocl for the ocls found.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
|
@ -11,7 +11,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Tarjej Huse, Benedikt Hallinger
|
* @copyright 2009 Tarjej Huse, Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $
|
* @version SVN: $Id: Search.php 328961 2013-01-03 09:04:30Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -106,13 +106,22 @@ class Net_LDAP2_Search extends PEAR implements Iterator
|
||||||
/**
|
/**
|
||||||
* 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 not used by all functions and need consolidation.
|
||||||
*
|
*
|
||||||
* @access protected
|
* @access protected
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $_entry_cache = false;
|
protected $_entry_cache = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache variable for count()
|
||||||
|
*
|
||||||
|
* @see count()
|
||||||
|
* @access protected
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $_count_cache = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -143,7 +152,7 @@ class Net_LDAP2_Search extends PEAR implements Iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of entry objects
|
* Returns an array of entry objects.
|
||||||
*
|
*
|
||||||
* @return array Array of entry objects.
|
* @return array Array of entry objects.
|
||||||
*/
|
*/
|
||||||
|
@ -151,15 +160,19 @@ class Net_LDAP2_Search extends PEAR implements Iterator
|
||||||
{
|
{
|
||||||
$entries = array();
|
$entries = array();
|
||||||
|
|
||||||
while ($entry = $this->shiftEntry()) {
|
if (false === $this->_entry_cache) {
|
||||||
$entries[] = $entry;
|
// cache is empty: fetch from LDAP
|
||||||
|
while ($entry = $this->shiftEntry()) {
|
||||||
|
$entries[] = $entry;
|
||||||
|
}
|
||||||
|
$this->_entry_cache = $entries; // store result in cache
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entries;
|
return $this->_entry_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next entry in the searchresult.
|
* Get the next entry in the searchresult from LDAP server.
|
||||||
*
|
*
|
||||||
* This will return a valid Net_LDAP2_Entry object or false, so
|
* This will return a valid Net_LDAP2_Entry object or false, so
|
||||||
* you can use this method to easily iterate over the entries inside
|
* you can use this method to easily iterate over the entries inside
|
||||||
|
@ -169,22 +182,20 @@ class Net_LDAP2_Search extends PEAR implements Iterator
|
||||||
*/
|
*/
|
||||||
public function &shiftEntry()
|
public function &shiftEntry()
|
||||||
{
|
{
|
||||||
if ($this->count() == 0 ) {
|
|
||||||
$false = false;
|
|
||||||
return $false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($this->_entry)) {
|
if (is_null($this->_entry)) {
|
||||||
$this->_entry = @ldap_first_entry($this->_link, $this->_search);
|
if(!$this->_entry = @ldap_first_entry($this->_link, $this->_search)) {
|
||||||
|
$false = false;
|
||||||
|
return $false;
|
||||||
|
}
|
||||||
$entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
|
$entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
|
||||||
if ($entry instanceof Net_LDAP2_Error) $entry = false;
|
if ($entry instanceof PEAR_Error) $entry = false;
|
||||||
} else {
|
} else {
|
||||||
if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) {
|
if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) {
|
||||||
$false = false;
|
$false = false;
|
||||||
return $false;
|
return $false;
|
||||||
}
|
}
|
||||||
$entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
|
$entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
|
||||||
if ($entry instanceof Net_LDAP2_Error) $entry = false;
|
if ($entry instanceof PEAR_Error) $entry = false;
|
||||||
}
|
}
|
||||||
return $entry;
|
return $entry;
|
||||||
}
|
}
|
||||||
|
@ -461,7 +472,13 @@ class Net_LDAP2_Search extends PEAR implements Iterator
|
||||||
if (!$this->_search) {
|
if (!$this->_search) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return @ldap_count_entries($this->_link, $this->_search);
|
// ldap_count_entries is slow (see pear bug #18752) with large results,
|
||||||
|
// so we cache the result internally.
|
||||||
|
if ($this->_count_cache === null) {
|
||||||
|
$this->_count_cache = @ldap_count_entries($this->_link, $this->_search);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_count_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* @author Benedikt Hallinger <beni@php.net>
|
* @author Benedikt Hallinger <beni@php.net>
|
||||||
* @copyright 2009 Benedikt Hallinger
|
* @copyright 2009 Benedikt Hallinger
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
||||||
* @version SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $
|
* @version SVN: $Id: Util.php 332278 2013-12-05 11:01:15Z beni $
|
||||||
* @link http://pear.php.net/package/Net_LDAP2/
|
* @link http://pear.php.net/package/Net_LDAP2/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -525,17 +525,29 @@ class Net_LDAP2_Util extends PEAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits a attribute=value syntax into an array
|
* Splits an attribute=value syntax into an array
|
||||||
*
|
*
|
||||||
* The split will occur at the first unescaped '=' character.
|
* If escaped delimeters are used, they are returned escaped as well.
|
||||||
|
* The split will occur at the first unescaped delimeter character.
|
||||||
|
* In case an invalid delimeter is given, no split will be performed and an
|
||||||
|
* one element array gets returned.
|
||||||
|
* Optional also filter-assertion delimeters can be considered (>, <, >=, <=, ~=).
|
||||||
*
|
*
|
||||||
* @param string $attr Attribute and Value Syntax
|
* @param string $attr Attribute and Value Syntax ("foo=bar")
|
||||||
|
* @param boolean $extended If set to true, also filter-assertion delimeter will be matched
|
||||||
|
* @param boolean $withDelim If set to true, the return array contains the delimeter at index 1, putting the value to index 2
|
||||||
*
|
*
|
||||||
* @return array Indexed array: 0=attribute name, 1=attribute value
|
* @return array Indexed array: 0=attribute name, 1=attribute value OR ($withDelim=true): 0=attr, 1=delimeter, 2=value
|
||||||
*/
|
*/
|
||||||
public static function split_attribute_string($attr)
|
public static function split_attribute_string($attr, $extended=false, $withDelim=false)
|
||||||
{
|
{
|
||||||
return preg_split('/(?<!\\\\)=/', $attr, 2);
|
if ($withDelim) $withDelim = PREG_SPLIT_DELIM_CAPTURE;
|
||||||
|
|
||||||
|
if (!$extended) {
|
||||||
|
return preg_split('/(?<!\\\\)(=)/', $attr, 2, $withDelim);
|
||||||
|
} else {
|
||||||
|
return preg_split('/(?<!\\\\)(>=|<=|>|<|~=|=)/', $attr, 2, $withDelim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user