View Source

<ac:macro ac:name="note"><ac:parameter ac:name="title">Under Construction</ac:parameter><ac:rich-text-body>
<p>This proposal is under construction and is not ready for review.</p></ac:rich-text-body></ac:macro>

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
Zend_Ldap
{zone-data}

{zone-data:proposer-list}
[Shawn Coomey|mailto:shawn.coomey@cubist.com]
[Andrew Yager|mailto:andrew@rwts.com.au]
[Michelangelo van Dam|mailto:vandammike@yahoo.com]
{zone-data}

{zone-data:revision}
1.2 - 29 March 2007: Updated from community comments and fleshing it out.
{zone-data}

{zone-data:overview}
Zend_Ldap is a component that used to communicate with directory servers that use the LDAP protocol. Provides basic abstraction from built-in PHP ldap functions in a manner similar to Zend_Db.
{zone-data}

{zone-data:references}
* [Zend fw-general discussion on LDAP support|http://www.nabble.com/LDAP-support-tf3029876s16154.html]
* [SimpleXML Reference for PHP|http://www.php.net/simplexml]
* [Python LDAP Interface|http://python-ldap.sourceforge.net/doc/python-ldap/module-ldap.html]
{zone-data}

{zone-data:requirements}
* Provide communications API for use with any directory server that supports LDAPv3
{zone-data}

{zone-data:dependencies}
* Zend_Exception
{zone-data}

{zone-data:operation}
TBA
{zone-data}

{zone-data:milestones}
{zone-data}

{zone-data:class-list}
* Zend_Ldap
* Zend_Ldap_Exception
{zone-data}

{zone-data:use-cases}
||UC-01||
Bind to LDAP server
{code}
$config=array('hostname' => 'localhost',
'base' => 'dc=sample,dc=org',
'port' => 4000,
'autobind' => false);
$conn = new Zend_Ldap($config);
$conn->bind('cn=user,dc=sample,dc=org', 'password');
{code}

||UC-02||
Bind to LDAP server using autobind
{code}
$config=array('hostname' => 'localhost',
'base' => 'dc=sample,dc=org',
'port' => 4000,
'binddn' => 'cn=user,dc=sample,dc=org',
'bindpassword' => 'password');
$conn = new Zend_Ldap($config);
{code}

||UC-03||
Search for objects
{code}
$conn = new Zend_Ldap($config);
$objects = $conn->searchEntries('(|(sn=$person*)(givenname=$person*))');
{code}

{zone-data}

{zone-data:skeletons}
{code}
class Zend_Ldap_Exception extends Zend_Exception {}

class Zend_Ldap {

/**
* Connection link resource
*
* @var string
*/
protected $_connection;

/**
* Hostname for bind
*
* @var string
*/
protected $_hostname;

/**
* Port number for bind
*
* @var integer
*/
protected $_port = 389;

/**
* Distinguised Name for bind
*
* @var string
*/
protected $_binddn;

/**
* Password for bind
*
* @var string
*/
protected $_bindpassword;

/**
* Base Distinguished Name
*
* @var string
*/
protected $_base;

/**
* LDAP Protocol version
*
* @var integer
*/
protected $_protocol = 3;

/**
* LDAP error code
*
* @var integer
*/
protected $_errno;

/**
* LDAP error message
*
* @var string
*/
protected $_error;


/**
* Automatically bind on connect
*
* @var string
**/
protected $_autobind = true;

/**
* Construct a new LDAP instance
*
* @param array $config
* @return Zend_Ldap
**/
public function __construct($config) {
if (isset($config['hostname'])) {
$this->_hostname = $config['hostname'];
}
if (isset($config['port'])) {
$this->_port = $config['port'];
}
if (isset($config['base'])) {
$this->_base = $config['base'];
}
if (isset($config['protocol'])) {
$this->_protocol = $config['protocol'];
}
if (isset($config['binddn'])) {
$this->_binddn = $config['binddn'];
}
if (isset($config['bindpassword'])) {
$this->_bindpw = $config['bindpassword'];
}
if (isset($config['autobind'])) {
$this->_autobind = $config['autobind']
}
$this->connect();
}

public function __destruct() {
$this->disconnect();
}

/**
* Connect with the LDAP server
*
* @param string $hostname
* @param integer $port
*
* @return void
* @throws Zend_Ldap_Exception
*/
public function connect() {
$this->_connection = ldap_connect($this->_hostname, $this->_port);
$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if(!$this->_connection) {
throw new Zend_Ldap_Exception(
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
$this->setVersion();
if ($this->_autobind) $this->bind();
}

/**
* Set the LDAP connection protocol to the correct version
*
* @param integer $version
*/
public function setVersion() {
if($this->_protocol === 3) {
ldap_set_option($this->_connection, LDAP_OPT_PROTOCOL_VERSION, $version);
}
}

/**
* Bind a distinguised name
*
* @param string $dn
* @return void
*/
public function bind($dn = null, $password = null) {
if ($dn!==null) {
$this->_binddn = $dn;
}
if ($password!==null) {
$this->_bindpassword = $password;
}
if(isset($this->_binddn) && isset($this->_bindpassword)) {
$bind = ldap_bind($this->_connection, $this->_binddn, $this->_bindpassword);
} else {
$bind = ldap_bind($this->_connection);
}
$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if($bind === false) {
throw new Zend_Ldap_Exception(
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
}


/**
* A global LDAP search routine for finding information
*
* @param mixed $filter
* @param string $base_dn
* @param mixed $attributes
* @return resource $result_identifier
* @throws Zend_Ldap_Exception
*/
public function search($filter, $basedn = null, $attributes=null) {
if ($basedn === null) {
$basedn = $this->_base;
}

if (isset($attributes)) {
$search = ldap_search($this->_connection, $basedn, $filter, $attributes);
} else {
$search = ldap_search($this->_connection, $basedn, $filter);
}

$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if($search === false) {
throw new Zend_Ldap_Exception(
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
return $search;
}

/**
* Search LDAP registry for entries matching filter and optional attributes
*
* @param string $base_dn
* @param mixed $filter
* @param mixed $attributes
* @return array $searchresults
*/
public function searchEntries($filter, $basedn=null, $attributes = null) {
$search = $this->search($filter, $basedn, $attributes);
return ldap_get_entries($this->_connection, $search);
}

/**
* Search LDAP for specific values
*
* @param string $attibute
* @return array $searchresults
*/
public function findValues($attibute) {
$search = $this->search($filter, $this->_base, $attibutes);
return ldap_get_values($this->_connection, $search, $attibute);
}

/**
* Add new information to the LDAP repository
*
* @param string $base_dn
* @param array $blockInfo
* @return boolean
* @throws Zend_Ldap_Exception
*/
public function add($base_dn, $blockInfo) {
// bool ldap_add ( resource $link_identifier, string $dn, array $entry )
$isAdded = @ldap_add($this->_connection, $base_dn, $blockInfo);
$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if($isAdded === false) {
throw new Zend_Ldap_Exception (
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
return $isAdded;
}

/**
* Update LDAP registry
*
* @param string $base_dn
* @param mixed $blockinfo
* @return boolean
* @throws Zend_Ldap_Exception
*/
public function update($base_dn, $blockInfo) {
$isModified = @ldap_modify($this->_connection, $base_dn, $blockInfo);
$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if($isModified === false) {
throw new Zend_Ldap_Exception(
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
return $isModified;
}

/**
* Delete an LDAP entry
*
* @param string $dn
* @return boolean
* @throws Zend_Ldap_Exception
*/
public function delete($dn) {
$isDeleted = ldap_delete($this->_connection, $dn);
$this->_errno = ldap_errno($this->_connection);
$this->_error = ldap_error($this->_connection);
if($isDeleted === false) {
throw new Zend_Ldap_Exception(
sprintf("LDAP error %d: %s", $this->_errno, $this->_error)
);
}
return $isDeleted;
}

/**
* Get the status code for a LDAP action
*
* @return int
*/
public function getStatusCode() {
return $this->_errno;
}

/**
* Get the status message for a LDAP action
*
* @return string
*/
public function getStatusMessage() {
return $this->_error;
}

/**
* Retrieve an error message from a LDAP error code
*
* @param int $errorCode
* @return string
*/
public function getStatus($errorCode) {
return ldap_err2str($errorCode);
}

/**
* Disconnect the LDAP connection
*
* @return void
*/
public function disconnect() {
if(isset($this->_connection)) {
$conn = ldap_unbind($this->_connection);
}
}
}
{code}
{code}
class Zend_Ldap_ObjectSet_Exception extends Zend_Exception {}


/**
* @category Zend
* @package Zend_Ldap
*/
class Zend_Ldap_ObjectSet implements Iterator, Countable
{
/**
* The original LDAP data for each object
*
* @var array
**/
protected $_data = array();

/**
* The original LDAP connection
*
* @var Zend_Ldap
**/
protected $_connection;

/**
* Zend_Ldap_Object class name
*
* @var string
**/
protected $_objectClass = "Zend_Ldap_Object";

/**
* Iterator pointer
*
* @var integer
**/
protected $_pointer = 0;

/**
* How man data rows there are
*
* @var integer
**/
protected $_count;

/**
* Collection of instantiated Zend_Ldap_Object objects
*
* @var string
**/
protected $_rows = array();

/**
* @var boolean
**/
protected $_stored = false;

/**
* undocumented function
*
* @return void
* @author Andrew Yager
**/
public function __construct(array $config)
{
f (isset($config['connection'])) {
$this->_connection = $config['table'];
}
if (isset($config['objectClass'])) {
$this->_objectClass = $config['objectClass'];
}
if (isset($config['data'])) {
$this->_data = $config['data'];
}
if (isset($config['stored'])) {
$this->_stored = $config['stored'];
}

// set the count of rows
$this->_count = count($this->_data);
}

/**
* Store data, class names, and state in serialized object
*
* @return array
*/
public function __sleep()
{
return array('_data', '_objectClass', '_pointer', '_count', '_rows', '_stored');
}

/**
* Setup to do on wakeup.
* A de-serialized ObjectSet should not be assumed to have access to a live
* LDAP connection, so set _connected = false.
*
* @return void
*/
public function __wakeup()
{
$this->_connected = false;
}


/**
* Returns the connection object, or null if this is disconnected objectset
*
* @return Zend_Ldap|null
*/
public function getConnection()
{
return $this->_connection;
}

/**
* Set the connection object, to re-establish a live connection
* to the LDAP server for a ObjectSet that has been de-serialized.
*
* @param Zend_Ldap $connection
* @return boolean
* @throws Zend_Ldap_ObjectSet_Exception
*/
public function setConnection(Zend_Ldap $connection)
{
$this->_connection = $connection;
$this->_connected = false;
// @todo This works only if we have iterated through
// the result set once to instantiate the rows.
foreach ($this->_rows as $row) {
$connected = $row->setConnection($connection);
if ($connected == true) {
$this->_connected = true;
}
}
return $this->_connected;
}

/**
* Rewind the Iterator to the first element.
* Similar to the reset() function for arrays in PHP.
* Required by interface Iterator.
*
* @return void
*/
public function rewind()
{
$this->_pointer = 0;
}

/**
* Return the current element.
* Similar to the current() function for arrays in PHP
* Required by interface Iterator.
*
* @return Zend_Ldap_Object_Abstract current element from the collection
*/
public function current()
{
if ($this->valid() === false) {
return null;
}

// do we already have a row object for this position?
if (empty($this->_rows[$this->_pointer])) {
$this->_rows[$this->_pointer] = new $this->_objectClass(
array(
'connection' => $this->_connection,
'data' => $this->_data[$this->_pointer],
'stored' => $this->_stored
)
);
}

// return the row object
return $this->_rows[$this->_pointer];
}

/**
* Return the identifying key of the current element.
* Similar to the key() function for arrays in PHP.
* Required by interface Iterator.
*
* @return int
*/
public function key()
{
return $this->_pointer;
}

/**
* Move forward to next element.
* Similar to the next() function for arrays in PHP.
* Required by interface Iterator.
*
* @return void
*/
public function next()
{
++$this->_pointer;
}

/**
* Check if there is a current element after calls to rewind() or next().
* Used to check if we've iterated to the end of the collection.
* Required by interface Iterator.
*
* @return bool False if there's nothing more to iterate over
*/
public function valid()
{
return $this->_pointer < $this->_count;
}

/**
* Returns the number of elements in the collection.
*
* Implements Countable::count()
*
* @return int
*/
public function count()
{
return $this->_count;
}

/**
* Returns true if and only if count($this) > 0.
*
* @return bool
* @deprecated since 0.9.3; use count() instead
*/
public function exists()
{
return $this->_count > 0;
}

/**
* Returns all data as an array.
*
* Updates the $_data property with current row object values.
*
* @return array
*/
public function toArray()
{
// @todo This works only if we have iterated through
// the result set once to instantiate the rows.
foreach ($this->_rows as $i => $row) {
$this->_data[$i] = $row->toArray();
}
return $this->_data;
}

}


/**
* @category Zend
* @package Zend_Ldap
* @todo Write this class
*/
abstract class Zend_Ldap_Object_Abstract
{
//todo
}

/**
* @category Zend
* @package Zend_Ldap
*/
class Zend_Ldap_Object extends Zend_Ldap_Object_Abstract
{
}
{code}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>