Source for file ldap.php
Documentation is available at ldap.php
// Pear DB LDAP - Database independent query interface definition
// for PHP's LDAP extension.
// Copyright (c) 2002-2003 Ludovico Magnocavallo <ludo@sumatrasolutions.com>
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// - Piotr Roszatycki <dexter@debian.org>
// DB_ldap::base() method, support for LDAP sequences, various fixes
// - Aaron Spencer Hawley <aaron dot hawley at uvm dot edu>
// fix to use port number if present in DB_ldap->connect()
require_once 'DB/common.php';
define("DB_ERROR_BIND_FAILED", -26 );
define("DB_ERROR_UNKNOWN_LDAP_ACTION", -27 );
* LDAP_result extends DB_result to provide specific LDAP
* @author Ludovico Magnocavallo <ludo@sumatrasolutions.com>
* data returned from ldap_entries()
* result rows as hash of records
* class constructor, calls DB_result constructor
* @param ref $dbh reference to the db instance
* @param resource $result ldap command result
$this->DB_result ($dbh, $result);
* fetch rows of data into $this->_recordset
* called once as soon as something needs to be returned
* @param resource $result ldap command result
if ($this->_recordset === null ) {
// begin processing result into recordset
$this->_entries = ldap_get_entries ($this->dbh->connection , $this->result);
$this->row_counter = $this->_entries['count'];
if (count($this->dbh->attributes ) > 0 ) {
reset($this->dbh->attributes );
while (list ($a_index, $a_name) = each($this->dbh->attributes )) $rs_template[$a_name] = '';
while (list ($entry_idx, $entry) = each($this->_entries)) {
// begin first loop, iterate through entries
if (!empty ($this->dbh->limit_from ) && ($i < $this->dbh->limit_from )) continue;
if (!empty ($this->dbh->limit_count ) && ($i > $this->dbh->limit_count )) break;
while (list ($attr, $attr_values) = each($entry)) {
// begin second loop, iterate through attributes
if (is_int($attr) || $attr == 'count') continue;
if (is_string($attr_values)) $rs[$attr] = $attr_values;
while (list ($value_idx, $attr_value) = each($attr_values)) {
// begin third loop, iterate through attribute values
if (!is_int($value_idx)) continue;
if (empty ($value)) $value = $attr_value;
if (is_array($value)) $value[] = $attr_value;
else $value = array ($value, $attr_value);
// else $value .= "\n$attr_value";
$this->_recordset[$entry_idx] = $rs;
$this->_recordset = array ();
if (!empty ($this->dbh->sorting )) {
$sorting_method = (!empty ($this->dbh->sorting_method ) ? $this->dbh->sorting_method : 'cmp');
uksort($this->_recordset, array (&$this, $sorting_method));
reset($this->_recordset);
// end processing result into recordset
* Fetch and return a row of data (it uses driver->fetchInto for that)
* @param int $fetchmode format of fetched row
* @param int $rownum the row number to fetch
* @return array a row of data, NULL on no more rows or PEAR_Error on error
function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT , $rownum = null )
if (count($this->_recordset) === 0 ) {
if ($this->_record !== null ) {
$this->_record = next($this->_recordset);
$this->_record = current($this->_recordset);
* Fetch a row of data into an existing variable.
* @param mixed $arr reference to data containing the row
* @param integer $fetchmode format of fetched row
* @param integer $rownum the row number to fetch
* @return mixed DB_OK on success, NULL on no more rows or
* a DB_Error object on error
function fetchInto(&$ar, $fetchmode = DB_FETCHMODE_DEFAULT , $rownum = null )
if ($this->_record !== null ) $this->_record = next($this->_recordset);
else $this->_record = current($this->_recordset);
* returns a hash of all records, basically returning
* a copy of $this->_recordset
* @param integer $fetchmode format of fetched row
* @param integer $rownum the row number to fetch (not used, here for interface compatibility)
* @return mixed DB_OK on success, NULL on no more rows or
* a DB_Error object on error
function fetchAll($fetchmode = DB_FETCHMODE_DEFAULT , $rownum = null )
return($this->_recordset);
* Get the the number of columns in a result set.
* @return int the number of columns, or a DB error
* Get the number of rows in a result set.
* @return int the number of rows, or a DB error
return $this->row_counter;
* Get the next result if a batch of queries was executed.
* @return bool true if a new result is available or false if not.
return $this->dbh->nextResult ($this->result);
* Frees the resources allocated for this result set.
$this->_recordset = null;
ldap_free_result ($this->result);
return $this->dbh->tableInfo ($this->result, $mode);
* returns the actual rows number
return $this->row_counter;
* LDAP DB interface class
* LDAP extends DB_common to provide DB compliant
* @author Ludovico Magnocavallo <ludo@sumatrasolutions.com>
* array of LDAP actions that only manipulate data
* returning a true/false value
var $manip = array ('add', 'compare', 'delete', 'modify', 'mod_add', 'mod_del', 'mod_replace', 'rename');
* store the default real LDAP action to perform
* store the real LDAP action to perform
* (ie PHP ldap function to call) for a query
* store optional parameters passed
* to the real LDAP action
* Constructor, calls DB_common constructor
* @see DB_common::DB_common()
$this->dbsyntax = 'ldap';
$this->errorcode_map = array (
0x10 => DB_ERROR_NOSUCHFIELD , // LDAP_NO_SUCH_ATTRIBUTE
0x11 => DB_ERROR_INVALID , // LDAP_UNDEFINED_TYPE
0x12 => DB_ERROR_INVALID , // LDAP_INAPPROPRIATE_MATCHING
0x13 => DB_ERROR_INVALID , // LDAP_CONSTRAINT_VIOLATION
0x14 => DB_ERROR_ALREADY_EXISTS , // LDAP_TYPE_OR_VALUE_EXISTS
0x15 => DB_ERROR_INVALID , // LDAP_INVALID_SYNTAX
0x20 => DB_ERROR_NOT_FOUND , // LDAP_NO_SUCH_OBJECT
0x21 => DB_ERROR_NOT_FOUND , // LDAP_ALIAS_PROBLEM
0x22 => DB_ERROR_INVALID , // LDAP_INVALID_DN_SYNTAX
0x23 => DB_ERROR_INVALID , // LDAP_IS_LEAF
0x24 => DB_ERROR_INVALID , // LDAP_ALIAS_DEREF_PROBLEM
0x30 => DB_ERROR_ACCESS_VIOLATION , // LDAP_INAPPROPRIATE_AUTH
0x31 => DB_ERROR_ACCESS_VIOLATION , // LDAP_INVALID_CREDENTIALS
0x32 => DB_ERROR_ACCESS_VIOLATION , // LDAP_INSUFFICIENT_ACCESS
0x40 => DB_ERROR_MISMATCH , // LDAP_NAMING_VIOLATION
0x41 => DB_ERROR_MISMATCH , // LDAP_OBJECT_CLASS_VIOLATION
0x44 => DB_ERROR_ALREADY_EXISTS , // LDAP_ALREADY_EXISTS
0x51 => DB_ERROR_CONNECT_FAILED , // LDAP_SERVER_DOWN
0x57 => DB_ERROR_SYNTAX // LDAP_FILTER_ERROR
* Connect and bind to LDAP server with either anonymous or authenticated bind depending on dsn info
* @param array $dsninfo dsn info as passed by DB::connect()
* @param boolean $persistent kept for interface compatibility
* @return DB_OK if successfully connected. A DB error code is returned on failure.
function connect($dsninfo, $persistent = false )
if (!PEAR ::loadExtension ('ldap'))
return $this->raiseError (DB_ERROR_EXTENSION_NOT_FOUND );
$user = $dsninfo['username'];
$pw = $dsninfo['password'];
$host = $dsninfo['hostspec'];
$port = $dsninfo['port'];
$this->base = $dsninfo['database'];
$this->d_base = $this->base;
$version = $dsninfo['protocol'];
return $this->raiseError (" no host specified $host" );
$conn = ldap_connect ($host, $port);
$conn = ldap_connect ($host);
return $this->raiseError (DB_ERROR_CONNECT_FAILED );
ldap_set_option ($conn, LDAP_OPT_PROTOCOL_VERSION , $version);
$res = ldap_set_option ($conn, LDAP_OPT_PROTOCOL_VERSION , 3 );
// If 3 fails then we can try 2
ldap_set_option ($conn, LDAP_OPT_PROTOCOL_VERSION , 2 );
$bind = @ldap_bind ($conn, $user, $pw);
$bind = @ldap_bind ($conn);
$this->connection = $conn;
* Unbinds from LDAP server
* @return int ldap_unbind() return value
$ret = @ldap_unbind ($this->connection);
$this->connection = null;
* Performs a request against the LDAP server
* The type of request (and the corresponding PHP ldap function called)
* depend on two additional parameters, added in respect to the
* @param string $filter text of the request to send to the LDAP server
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return result from ldap function or DB Error object if no result
function simpleQuery($filter, $action = null , $params = null )
$action = (!empty ($this->q_action) ? $this->q_action : $this->action);
$params = (count($this->q_params) > 0 ? $this->q_params : array ());
$base = $this->q_base ? $this->q_base : $this->base;
$deref = LDAP_DEREF_NEVER;
while (list ($k, $v) = each($params)) {
if (isset ($ {$k})) $ {$k} = $v;
$this->sorting = $sorting;
$this->sorting_method = $sorting_method;
$this->attributes = $attributes;
# double escape char for filter: '(o=Przedsi\C4\99biorstwo)' => '(o=Przedsi\\C4\\99biorstwo)'
$this->last_query = $filter;
$result = @ldap_search ($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
else if ($action == 'list')
$result = @ldap_list ($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
else if ($action == 'read')
$result = @ldap_read ($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
# If first argument is an array, it contains the entry with DN.
while (list ($k, $v) = each($params)) {
if (isset ($ {$k})) $ {$k} = $v;
$this->last_query = $filter;
$result = @ldap_add ($this->connection, $filter, $entry);
else if ($action == 'compare')
$result = @ldap_add ($this->connection, $filter, $attribute, $value);
else if ($action == 'delete')
$result = @ldap_delete ($this->connection, $filter);
else if ($action == 'modify')
$result = @ldap_modify ($this->connection, $filter, $entry);
else if ($action == 'mod_add')
$result = @ldap_mod_add ($this->connection, $filter, $entry);
else if ($action == 'mod_del')
$result = @ldap_mod_del ($this->connection, $filter, $entry);
else if ($action == 'mod_replace')
$result = @ldap_mod_replace ($this->connection, $filter, $entry);
else if ($action == 'rename')
$result = @ldap_rename ($this->connection, $filter, $newrdn, $newparent, $deleteoldrdn);
* Executes a query performing variables substitution in the query text
* @param string $stmt text of the request to send to the LDAP server
* @param array $data query variables values to substitute
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return LDAP_result object or DB Error object if no result
* @see DB_common::executeEmulateQuery $this->simpleQuery()
function execute($stmt, $data = false , $action = null , $params = array ())
$this->q_params = $params;
$realquery = $this->executeEmulateQuery ($stmt, $data);
if (DB ::isError ($realquery)) {
$result = $this->simpleQuery($realquery, $action, $params);
if (DB ::isError ($result) || $result === DB_OK ) {
* Executes multiple queries performing variables substitution for each query
* @param string $stmt text of the request to send to the LDAP server
* @param array $data query variables values to substitute
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return LDAP_result object or DB Error object if no result
* @see DB_common::executeMultiple
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
return(parent ::executeMultiple ($stmt, $data));
* Executes a query substituting variables if any are present
* @param string $query text of the request to send to the LDAP server
* @param array $data query variables values to substitute
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return LDAP_result object or DB Error object if no result
* @see DB_common::prepare() $this->execute()$this->simpleQuery()
function &query($query, $data = array (), $action = null , $params = array ())
// $this->q_action = $action ? $action : $this->action;
// $this->q_params = $params;
$sth = $this->prepare ($query);
return $this->execute($sth, $data);
$result = $this->simpleQuery($query, $action, $params);
if (DB ::isError ($result) || $result === DB_OK ) {
* Modifies a query to return only a set of rows, stores $from and $count for LDAP_result
* @param string $query text of the request to send to the LDAP server
* @param int $from record position from which to start returning data
* @param int $count number of records to return
* @return modified query text (no modifications are made, see above)
$this->limit_from = $from;
$this->limit_count = $count;
* Executes a query returning only a specified number of rows
* This method only saves the $from and $count parameters for LDAP_result
* where the actual records processing takes place
* @param string $query text of the request to send to the LDAP server
* @param int $from record position from which to start returning data
* @param int $count number of records to return
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return LDAP_result object or DB Error object if no result
function limitQuery($query, $from, $count, $action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
return $this->query($query, $action, $params);
* Fetch the first column of the first row of data returned from
* a query. Takes care of doing the query and freeing the results
* @param $query the SQL query
* @param $data if supplied, prepare/execute will be used
* with this array as execute parameters
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @see DB_common::getOne()
function &getOne($query, $data = array (), $action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
return(parent ::getOne ($query, $data));
* Fetch the first row of data returned from a query. Takes care
* of doing the query and freeing the results when finished.
* @param $query the SQL query
* @param $fetchmode the fetch mode to use
* @param $data array if supplied, prepare/execute will be used
* with this array as execute parameters
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return array the first row of results as an array indexed from
* @see DB_common::getRow()
$fetchmode = DB_FETCHMODE_DEFAULT ,
$action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
return(parent ::getRow ($query, $data, $fetchmode));
* Fetch the first column of data returned from a query. Takes care
* of doing the query and freeing the results when finished.
* @param $query the SQL query
* @param $col which column to return (integer [column number,
* starting at 0] or string [column name])
* @param $data array if supplied, prepare/execute will be used
* with this array as execute parameters
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return array an indexed array with the data from the first
* row at index 0, or a DB error code.
* @see DB_common::getCol()
function &getCol($query, $col = 0 , $data = array (), $action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
return(parent ::getCol ($query, $col, $data));
* Calls DB_common::getAssoc()
* @param $query the SQL query
* @param $force_array (optional) used only when the query returns
* exactly two columns. If true, the values of the returned array
* will be one-element arrays instead of scalars.
* starting at 0] or string [column name])
* @param array $data if supplied, prepare/execute will be used
* with this array as execute parameters
* @param $fetchmode the fetch mode to use
* @param boolean $group see DB_Common::getAssoc()
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return array an indexed array with the data from the first
* row at index 0, or a DB error code.
* @see DB_common::getAssoc()
function &getAssoc($query, $force_array = false , $data = array (),
$fetchmode = DB_FETCHMODE_ORDERED , $group = false ,
$action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
$result = parent ::getAssoc ($query, $force_array, $data, $fetchmode, $group);
* Fetch all the rows returned from a query.
* @param $query the SQL query
* @param array $data if supplied, prepare/execute will be used
* with this array as execute parameters
* @param $fetchmode the fetch mode to use
* @param string $action type of request to perform, defaults to search (ldap_search())
* @param array $params array of additional parameters to pass to the PHP ldap function requested
* @return array an nested array, or a DB error
* @see DB_common::getAll()
$fetchmode = DB_FETCHMODE_DEFAULT ,
$action = null , $params = array ())
$this->q_action = $action ? $action : $this->action;
$this->q_params = $params;
$result = parent ::getAll ($query, $data, $fetchmode);
return $result->numRows ();
return(in_array($action, $this->manip));
$this->q_params = array ();
$this->attributes = null;
// Deprecated, will be removed in future releases.
function base($base = null )
$this->q_base = ($base !== null ) ? $base : null;
$this->base = ($base !== null ) ? $base : $this->d_base;
if ($action != 'search' && $action != 'list' && $action != 'read') {
* Get the next value in a sequence.
* LDAP provides transactions for only one entry and we need to
* prevent race condition. If unique value before and after modify
* aren't equal then wait and try again.
* The name of sequence is LDAP DN of entry.
* @param string $seq_name the DN of the sequence
* @param bool $ondemand whether to create the sequence on demand
* @return a sequence integer, or a DB error
function nextId($seq_name, $ondemand = true )
// Get the sequence entry
$this->pushErrorHandling (PEAR_ERROR_RETURN );
$data = $this->getRow("objectClass=*");
$this->popErrorHandling ();
if (DB ::isError ($data)) {
// DB_ldap doesn't use DB_ERROR_NOT_FOUND
if ($ondemand && $repeat == 0
&& $data->getCode () == DB_ERROR ) {
// Try to create sequence and repeat
if (DB ::isError ($data)) {
// Increment sequence value
// Unique identificator of transaction
$data["uid"] = $seq_unique;
$this->pushErrorHandling (PEAR_ERROR_RETURN );
$this->popErrorHandling ();
if (DB ::isError ($data)) {
// Get the entry and check if it contains our unique value
$data = $this->getRow("objectClass=*");
if (DB ::isError ($data)) {
if ($data["uid"] != $seq_unique) {
// It is not our entry. Wait a little time and repeat
if (DB ::isError ($data)) {
* The sequence entry is based on core schema with extensibleObject,
* so it should work with any LDAP server which doesn't check schema
* or supports extensibleObject object class.
* Sequence name have to be DN started with "sn=$seq_id,", i.e.:
* $seq_name = "sn=uidNumber,ou=sequences,dc=php,dc=net";
* objectClass: extensibleObject
* @param string $seq_name the DN of the sequence
* @return mixed DB_OK on success or DB error on error
// Extract $seq_id from DN
list ($seq_id, $_) = explode(",", seq_name , 2 );
// Create the sequence entry
'objectclass' => array ("top", "extensibleObject"),
$this->pushErrorHandling (PEAR_ERROR_RETURN );
$this->popErrorHandling ();
* @param string $seq_name the DN of the sequence
* @return mixed DB_OK on success or DB error on error
// Delete the sequence entry
$this->pushErrorHandling (PEAR_ERROR_RETURN );
$this->popErrorHandling ();
$errno = $this->errorCode (ldap_errno ($this->connection));
if ($this->q_action !== null ) {
return $this->raiseError ($errno, null , null ,
sprintf('%s base="%s" filter="%s"',
$this->q_action, $this->q_base, $this->last_query
return $this->raiseError ($errno, null , null , "???",
@ldap_error ($this->connection));
Documentation generated on Mon, 11 Mar 2019 15:46:33 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|