<?php


/**
 * LDAP client.
 * 
  ldap_connect()    // establish connection to server
     |
  ldap_bind()       // anonymous or authenticated "login"
     |
  do something like search or update the directory
  and display the results
     |
  ldap_close()      // "logout"
*/
class Core_Client_Ldap {

	private $_conn;
	private $_protocol_version;
	private $_base_dn;
	private $_user;
	private $_pass;
	private $_LDAP_OPT_DIAGNOSTIC_MESSAGE = 0x0032;

	public function __construct($host, $user, $pass, $base_dn, $version = 3) {
		$this->_base_dn = $base_dn;
		$this->_user = $user;
		$this->_pass = $pass;

		if (0) {// TODO: if base_dn not set - set from $host name
			if (empty($this->_base_dn)) {
				$serverName = $host;
				if (false !== ($pos = strrpos($serverName, ':'))) {
					$serverName = substr($serverName, 0, $pos);
				}
				if (false !== ($pos = strrpos($serverName, '/'))) {
					$serverName = substr($serverName, $pos + 1);
				}

				$ldapDcArr = array();
				$dc_arr = explode('.', $serverName);
				foreach ($dc_arr as $vDc) {
					$ldapDcArr[] = "dc={$vDc}";
				}
				$this->_base_dn = implode(',', $ldapDcArr);
			}
		}

		$this->_conn = ldap_connect($host);
		if (!is_resource($this->_conn)) {
			trigger_error("Error connecting to LDAP", E_USER_WARNING);
		}
		else {
			// use ldap 3 version
			$this->_protocol_version = 2;
			if ($version == 3) {
				if (ldap_set_option($this->_conn, LDAP_OPT_PROTOCOL_VERSION, 3)) {
					$this->_protocol_version = 3;// Using LDAP v3
				} else {
					// Failed to set version to protocol 3
				}
			}

			// ldap_set_option($ldap->conn, LDAP_OPT_REFERRALS, 0);

			// TODO:?: bind to the LDAP server if user and pass is set
			//if ($user && $pass) {
			//	$this->bind($user, $pass);
			//}
		}
	}

	public function __destruct() {
		if (is_resource($this->_conn)) {
			@ ldap_close($this->_conn);
		}
	}

	public function isConnected() {
		return is_resource($this->_conn);
	}

	public function getBaseDN() {
		return $this->_base_dn;
	}

	public function bind($user_rdn, $pass, &$errorMsg) {
		$bind = ldap_bind($this->_conn, $user_rdn, $pass);
		if ($bind) {
			return true;
		}

		if (ldap_get_option($this->_conn, $this->_LDAP_OPT_DIAGNOSTIC_MESSAGE, $extended_error)) {
			$errorMsg = 'Error Binding to LDAP: '.$extended_error;
		} else {
			$errorMsg = 'Error Binding to LDAP: No additional information is available.';
		}
		return false;
	}

	public function bindDiradmin(&$errorMsg = '') {
		$bind = ldap_bind($this->_conn, "uid={$this->_user},cn=users,{$this->_base_dn}", $this->_pass);
		if ($bind) {
			return true;
		}
		if (ldap_get_option($this->_conn, $this->_LDAP_OPT_DIAGNOSTIC_MESSAGE, $extended_error)) {
			$errorMsg = 'Error Binding to LDAP: '.$extended_error;
		} else {
			$errorMsg = 'Error Binding to LDAP: No additional information is available.';
		}
		return false;
	}

	public function search($query, $domain = '', $attributes = array()) {
		$domain = ($domain)? "{$domain},{$this->_base_dn}" : $this->_base_dn;
		$res = ldap_search($this->_conn, $domain, $query, $attributes);
		if (!is_resource($res)) {
			trigger_error("Error LDAP search '{$query}', '{$domain}'", E_USER_WARNING);
		}
		return $res;
	}

	public function count_entries($res) {
		return ldap_count_entries($this->_conn, $res);
	}

	public function first_entry($res) {
		$entry = ldap_first_entry($this->_conn, $res);
		return $entry;
	}

	public function get_dn($entry) {
		return ldap_get_dn($this->_conn, $entry);
	}

	public function get_values($entry, $attr) {
		return ldap_get_values($this->_conn, $entry, $attr);
	}

	public function get_attributes($entry) {
		$attrs = ldap_get_attributes($this->_conn, $entry);
		return $attrs;
	}

	public function next_entry($entry) {
		$entry = ldap_next_entry($this->_conn, $entry);
		return $entry;
	}

	public function free_result($res) {
		ldap_free_result($res);
	}

	public function error() {
		return ldap_error($this->_conn);
	}

	public function get_entries($res) {
		return ldap_get_entries($this->_conn, $res);
	}

	/**
	 * example: $attr['email'] = 'foo@bar.com';
	 */
	public function mod_replace($userUid, $attr) {
		$result = ldap_mod_replace($this->_conn, "uid={$userUid},cn=users,{$this->_base_dn}", $attr);
		if (true === $result) {
			return true;
		}
		return false;
	}

	public function groupAttrUpdate($groupUid, $attr) {
		$result = ldap_mod_replace($this->_conn, "cn={$groupUid},cn=groups,{$this->_base_dn}", $attr);
//echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">ldap_mod_replace('."cn={$groupUid},cn=groups,{$this->_base_dn}".') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($result);echo'</pre>';
		if (true === $result) {
			return true;
		}
		return false;
	}

	public function mod_del($userUid, $attr) {
		$result = ldap_mod_del($this->_conn, "uid={$userUid},cn=users,{$this->_base_dn}", $attr);
		if (true === $result) {
			return true;
		}
		return false;
	}

}
