| | |
| | | <?php |
| | | |
| | | /* |
| | | +-----------------------------------------------------------------------+ |
| | | | program/include/rcube_ldap.inc | |
| | |
| | | |
| | | */ |
| | | |
| | | |
| | | /** |
| | | * Model class to access an LDAP address directory |
| | | * |
| | | * @package Addressbook |
| | | */ |
| | | class rcube_ldap |
| | | { |
| | | var $conn; |
| | |
| | | if (preg_match('/^(.+)_field$/', $prop, $matches)) |
| | | $this->fieldmap[$matches[1]] = $value; |
| | | |
| | | // $this->filter = "(dn=*)"; |
| | | $this->connect(); |
| | | } |
| | | |
| | | /** |
| | | * PHP 4 object constructor |
| | | * |
| | | * @see rcube_ldap::__construct |
| | | * @see rcube_ldap::__construct() |
| | | */ |
| | | function rcube_ldap($p) |
| | | { |
| | |
| | | if (!is_array($this->prop['hosts'])) |
| | | $this->prop['hosts'] = array($this->prop['hosts']); |
| | | |
| | | if (empty($this->prop['ldap_version'])) |
| | | $this->prop['ldap_version'] = 3; |
| | | |
| | | foreach ($this->prop['hosts'] as $host) |
| | | { |
| | | if ($lc = @ldap_connect($host, $this->prop['port'])) |
| | | { |
| | | ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['port']); |
| | | ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']); |
| | | $this->prop['host'] = $host; |
| | | $this->conn = $lc; |
| | | break; |
| | |
| | | } |
| | | |
| | | if (is_resource($this->conn)) |
| | | { |
| | | $this->ready = true; |
| | | if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass'])) |
| | | $this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']); |
| | | } |
| | | else |
| | | raise_error(array('type' => 'ldap', 'message' => "Could not connect to any LDAP server, tried $host:{$this->prop[port]} last"), true); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Merge with connect()? |
| | | * Bind connection with DN and password |
| | | * |
| | | * @param string Bind DN |
| | | * @param string Bind password |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | function bind($dn=null, $pass=null) |
| | | function bind($dn, $pass) |
| | | { |
| | | if ($this->conn) |
| | | { |
| | | if ($dn) |
| | | { |
| | | if (@ldap_bind($this->conn, $dn, $pass)) |
| | | return true; |
| | | else |
| | | raise_error(array('code' => ldap_errno($this->conn), |
| | | 'type' => 'ldap', |
| | | 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)), |
| | | true); |
| | | } |
| | | else |
| | | { |
| | | if (@ldap_bind($this->conn)) |
| | | return true; |
| | | else |
| | | raise_error(array('code' => ldap_errno($this->conn), |
| | | 'type' => 'ldap', |
| | | 'message' => "Anonymous bind failed: ".ldap_error($this->conn)), |
| | | true); |
| | | } |
| | | if (!$this->conn) { |
| | | return false; |
| | | } |
| | | else |
| | | raise_error(array('type' => 'ldap', 'message' => "Attempted bind on nonexistent connection"), true); |
| | | |
| | | |
| | | if (ldap_bind($this->conn, $dn, $pass)) { |
| | | return true; |
| | | } |
| | | |
| | | raise_error(array( |
| | | 'code' => ldap_errno($this->conn), |
| | | 'type' => 'ldap', |
| | | 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)), |
| | | true); |
| | | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | function close() |
| | | { |
| | | if ($this->conn) |
| | | { |
| | | @ldap_unbind($this->conn); |
| | | $this->conn = null; |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | /** |
| | | * Save a search string for future listings |
| | | * |
| | | * @param string ?? |
| | | * @param string Filter string |
| | | */ |
| | | function set_search_set($filter) |
| | | { |
| | |
| | | * List the current set of contact records |
| | | * |
| | | * @param array List of cols to show |
| | | * @param int Only return this number of records (not implemented) |
| | | * @return array Indexed list of contact records, each a hash array |
| | | */ |
| | | function list_records($cols=null, $subset=0) |
| | | { |
| | | // add general filter to query |
| | | if (!empty($this->prop['filter'])) |
| | | { |
| | | $filter = $this->prop['filter']; |
| | | $this->set_search_set($filter); |
| | | } |
| | | |
| | | // exec LDAP search if no result resource is stored |
| | | if ($this->conn && !$this->ldap_result) |
| | | $this->_exec_search(); |
| | |
| | | * @param array List of fields to search in |
| | | * @param string Search value |
| | | * @param boolean True if results are requested, False if count only |
| | | * @return Indexed list of contact records and 'count' value |
| | | * @return array Indexed list of contact records and 'count' value |
| | | */ |
| | | function search($fields, $value, $select=true) |
| | | function search($fields, $value, $strict=false, $select=true) |
| | | { |
| | | // special treatment for ID-based search |
| | | if ($fields == 'ID' || $fields == $this->primary_key) |
| | |
| | | } |
| | | |
| | | $filter = '(|'; |
| | | $wc = $this->prop['fuzzy_search'] ? '*' : ''; |
| | | $wc = !$strict && $this->prop['fuzzy_search'] ? '*' : ''; |
| | | if (is_array($this->prop['search_fields'])) |
| | | { |
| | | foreach ($this->prop['search_fields'] as $k => $field) |
| | |
| | | $filter .= "($f=$wc" . rcube_ldap::quote_string($value) . "$wc)"; |
| | | } |
| | | $filter .= ')'; |
| | | |
| | | // avoid double-wildcard if $value is empty |
| | | $filter = preg_replace('/\*+/', '*', $filter); |
| | | |
| | | // add general filter to query |
| | | if (!empty($this->prop['filter'])) |
| | | $filter = '(&(' . preg_replace('/^\(|\)$/', '', $this->prop['filter']) . ')' . $filter . ')'; |
| | | |
| | | // set filter string and execute search |
| | | $this->set_search_set($filter); |
| | |
| | | /** |
| | | * Count number of available contacts in database |
| | | * |
| | | * @return Result array with values for 'count' and 'first' |
| | | * @return object rcube_result_set Resultset with values for 'count' and 'first' |
| | | */ |
| | | function count() |
| | | { |
| | |
| | | /** |
| | | * Return the last result set |
| | | * |
| | | * @return Result array or NULL if nothing selected yet |
| | | * @return object rcube_result_set Current resultset or NULL if nothing selected yet |
| | | */ |
| | | function get_result() |
| | | { |
| | |
| | | /** |
| | | * Get a specific contact record |
| | | * |
| | | * @param mixed record identifier |
| | | * @return Hash array with all record fields or False if not found |
| | | * @param mixed Record identifier |
| | | * @param boolean Return as associative array |
| | | * @return mixed Hash array or rcube_result_set with all record fields |
| | | */ |
| | | function get_record($dn, $assoc=false) |
| | | { |
| | |
| | | /** |
| | | * Create a new contact record |
| | | * |
| | | * @param array Assoziative array with save data |
| | | * @return The create record ID on success, False on error |
| | | * @param array Hash array with save data |
| | | * @return boolean The create record ID on success, False on error |
| | | */ |
| | | function insert($save_cols) |
| | | { |
| | |
| | | * Update a specific contact record |
| | | * |
| | | * @param mixed Record identifier |
| | | * @param array Assoziative array with save data |
| | | * @return True on success, False on error |
| | | * @param array Hash array with save data |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | function update($id, $save_cols) |
| | | { |
| | |
| | | * Mark one or more contact records as deleted |
| | | * |
| | | * @param array Record identifiers |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | function delete($ids) |
| | | { |
| | |
| | | /** |
| | | * Execute the LDAP search based on the stored credentials |
| | | * |
| | | * @private |
| | | * @access private |
| | | */ |
| | | function _exec_search() |
| | | { |
| | | if ($this->conn && $this->filter) |
| | | { |
| | | $function = $this->prop['scope'] == 'sub' ? 'ldap_search' : ($this->prop['scope'] == 'base' ? 'ldap_read' : 'ldap_list'); |
| | | $this->ldap_result = @$function($this->conn, $this->prop['base_dn'], $this->filter, array_values($this->fieldmap), 0, 0); |
| | | $this->ldap_result = $function($this->conn, $this->prop['base_dn'], $this->filter, array_values($this->fieldmap), 0, 0); |
| | | return true; |
| | | } |
| | | else |
| | |
| | | |
| | | |
| | | /** |
| | | * @private |
| | | * @access private |
| | | */ |
| | | function _ldap2result($rec) |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * @private |
| | | * @access private |
| | | */ |
| | | function _map_field($field) |
| | | { |
| | |
| | | |
| | | } |
| | | |
| | | ?> |
| | | ?> |