| | |
| | | | program/include/rcube_ldap.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2006-2011, The Roundcube Dev Team | |
| | | | Copyright (C) 2006-2012, The Roundcube Dev Team | |
| | | | Copyright (C) 2011, Kolab Systems AG | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | | PURPOSE: | |
| | | | Interface to an LDAP address directory | |
| | |
| | | public $readonly = true; |
| | | public $ready = false; |
| | | public $group_id = 0; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $coltypes = array(); |
| | | |
| | | /** private properties */ |
| | | protected $conn; |
| | | protected $prop = array(); |
| | | protected $fieldmap = array(); |
| | | |
| | | protected $sub_filter; |
| | | protected $filter = ''; |
| | | protected $result = null; |
| | | protected $ldap_result = null; |
| | | protected $sort_col = ''; |
| | | protected $mail_domain = ''; |
| | | protected $debug = false; |
| | | |
| | |
| | | /** |
| | | * Object constructor |
| | | * |
| | | * @param array LDAP connection properties |
| | | * @param boolean Enables debug mode |
| | | * @param string Current user mail domain name |
| | | * @param integer User-ID |
| | | * @param array $p LDAP connection properties |
| | | * @param boolean $debug Enables debug mode |
| | | * @param string $mail_domain Current user mail domain name |
| | | */ |
| | | function __construct($p, $debug=false, $mail_domain=NULL) |
| | | function __construct($p, $debug = false, $mail_domain = null) |
| | | { |
| | | $this->prop = $p; |
| | | |
| | |
| | | foreach ($p['fieldmap'] as $rf => $lf) |
| | | $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf)); |
| | | } |
| | | else { |
| | | else if (!empty($p)) { |
| | | // read deprecated *_field properties to remain backwards compatible |
| | | foreach ($p as $prop => $value) |
| | | if (preg_match('/^(.+)_field$/', $prop, $matches)) |
| | |
| | | |
| | | // support for composite address |
| | | if ($this->fieldmap['street'] && $this->fieldmap['locality']) { |
| | | $this->coltypes['address'] = array('limit' => max(1, $this->coltypes['locality']['limit']), 'subtypes' => $this->coltypes['locality']['subtypes']); |
| | | foreach (array('street','locality','zipcode','region','country') as $childcol) |
| | | unset($this->coltypes[$childcol]); // remove address child col from global coltypes list |
| | | $this->coltypes['address'] = array('limit' => max(1, $this->coltypes['locality']['limit']), 'subtypes' => $this->coltypes['locality']['subtypes'], 'childs' => array()); |
| | | foreach (array('street','locality','zipcode','region','country') as $childcol) { |
| | | if ($this->fieldmap[$childcol]) { |
| | | $this->coltypes['address']['childs'][$childcol] = array('type' => 'text'); |
| | | unset($this->coltypes[$childcol]); // remove address child col from global coltypes list |
| | | } |
| | | } |
| | | } |
| | | else if ($this->coltypes['address']) |
| | | else if ($this->coltypes['address']) { |
| | | $this->coltypes['address'] = array('type' => 'textarea', 'childs' => null, 'limit' => 1, 'size' => 40); |
| | | } |
| | | |
| | | // make sure 'required_fields' is an array |
| | | if (!is_array($this->prop['required_fields'])) |
| | | if (!is_array($this->prop['required_fields'])) { |
| | | $this->prop['required_fields'] = (array) $this->prop['required_fields']; |
| | | } |
| | | |
| | | foreach ($this->prop['required_fields'] as $key => $val) |
| | | // make sure LDAP_rdn field is required |
| | | if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields'])) { |
| | | $this->prop['required_fields'][] = $this->prop['LDAP_rdn']; |
| | | } |
| | | |
| | | foreach ($this->prop['required_fields'] as $key => $val) { |
| | | $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val)); |
| | | } |
| | | |
| | | // Build sub_fields filter |
| | | if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { |
| | | $this->sub_filter = ''; |
| | | foreach ($this->prop['sub_fields'] as $attr => $class) { |
| | | if (!empty($class)) { |
| | | $class = is_array($class) ? array_pop($class) : $class; |
| | | $this->sub_filter .= '(objectClass=' . $class . ')'; |
| | | } |
| | | } |
| | | if (count($this->prop['sub_fields']) > 1) { |
| | | $this->sub_filter = '(|' . $this->sub_filter . ')'; |
| | | } |
| | | } |
| | | |
| | | $this->sort_col = is_array($p['sort']) ? $p['sort'][0] : $p['sort']; |
| | | $this->debug = $debug; |
| | |
| | | */ |
| | | private function _connect() |
| | | { |
| | | global $RCMAIL; |
| | | $RCMAIL = rcmail::get_instance(); |
| | | |
| | | if (!function_exists('ldap_connect')) |
| | | raise_error(array('code' => 100, 'type' => 'ldap', |
| | | rcube::raise_error(array('code' => 100, 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "No ldap support in this installation of PHP"), |
| | | true, true); |
| | |
| | | |
| | | foreach ($this->prop['hosts'] as $host) |
| | | { |
| | | $host = idn_to_ascii(rcube_parse_host($host)); |
| | | $host = idn_to_ascii(rcmail::parse_host($host)); |
| | | $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); |
| | | |
| | | $this->_debug("C: Connect [$hostname]"); |
| | | $this->_debug("C: Connect [$hostname] [{$this->prop['name']}]"); |
| | | |
| | | if ($lc = @ldap_connect($host, $this->prop['port'])) |
| | | { |
| | |
| | | ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']); |
| | | $this->prop['host'] = $host; |
| | | $this->conn = $lc; |
| | | |
| | | if (isset($this->prop['referrals'])) |
| | | ldap_set_option($lc, LDAP_OPT_REFERRALS, $this->prop['referrals']); |
| | | break; |
| | | } |
| | | $this->_debug("S: NOT OK"); |
| | |
| | | } |
| | | |
| | | if (!is_resource($this->conn)) { |
| | | raise_error(array('code' => 100, 'type' => 'ldap', |
| | | rcube::raise_error(array('code' => 100, 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); |
| | | |
| | |
| | | } |
| | | |
| | | // Get the pieces needed for variable replacement. |
| | | if ($fu = $RCMAIL->user->get_username()) |
| | | if ($fu = $RCMAIL->get_user_name()) |
| | | list($u, $d) = explode('@', $fu); |
| | | else |
| | | $d = $this->mail_domain; |
| | |
| | | $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); |
| | | |
| | | if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { |
| | | if (!empty($this->prop['search_bind_dn']) && !empty($this->prop['search_bind_pw'])) { |
| | | $this->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']); |
| | | } |
| | | |
| | | // Search for the dn to use to authenticate |
| | | $this->prop['search_base_dn'] = strtr($this->prop['search_base_dn'], $replaces); |
| | | $this->prop['search_filter'] = strtr($this->prop['search_filter'], $replaces); |
| | |
| | | if (!empty($this->prop['search_dn_default'])) |
| | | $replaces['%dn'] = $this->prop['search_dn_default']; |
| | | else { |
| | | raise_error(array( |
| | | rcube::raise_error(array( |
| | | 'code' => 100, 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "DN not found using LDAP search."), true); |
| | |
| | | } |
| | | |
| | | if (!function_exists('ldap_sasl_bind')) { |
| | | raise_error(array('code' => 100, 'type' => 'ldap', |
| | | rcube::raise_error(array('code' => 100, 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Unable to bind: ldap_sasl_bind() not exists"), |
| | | true, true); |
| | |
| | | |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | |
| | | raise_error(array( |
| | | rcube::raise_error(array( |
| | | 'code' => ldap_errno($this->conn), 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Bind failed for authcid=$authc ".ldap_error($this->conn)), |
| | |
| | | |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | |
| | | raise_error(array( |
| | | rcube::raise_error(array( |
| | | 'code' => ldap_errno($this->conn), 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)), |
| | |
| | | |
| | | |
| | | /** |
| | | * Set internal list page |
| | | * Set internal sort settings |
| | | * |
| | | * @param number $page Page number to list |
| | | * @param string $sort_col Sort column |
| | | * @param string $sort_order Sort order |
| | | */ |
| | | function set_page($page) |
| | | function set_sort_order($sort_col, $sort_order = null) |
| | | { |
| | | $this->list_page = (int)$page; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set internal page size |
| | | * |
| | | * @param number $size Number of messages to display on one page |
| | | */ |
| | | function set_pagesize($size) |
| | | { |
| | | $this->page_size = (int)$size; |
| | | if ($this->fieldmap[$sort_col]) |
| | | $this->sort_col = $this->fieldmap[$sort_col]; |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Get all members of the given group |
| | | * |
| | | * @param string Group DN |
| | | * @param array Group entries (if called recursively) |
| | | * @return array Accumulated group members |
| | | * Get all members of the given group |
| | | * |
| | | * @param string Group DN |
| | | * @param array Group entries (if called recursively) |
| | | * @return array Accumulated group members |
| | | */ |
| | | function list_group_members($dn, $count = false, $entries = null) |
| | | { |
| | |
| | | $entries = @ldap_get_entries($this->conn, $result); |
| | | } |
| | | |
| | | for ($i=0; $i < $entries["count"]; $i++) |
| | | for ($i=0; $i < $entries['count']; $i++) |
| | | { |
| | | $entry = $entries[$i]; |
| | | |
| | |
| | | foreach ((array)$entry['objectclass'] as $objectclass) |
| | | { |
| | | switch (strtolower($objectclass)) { |
| | | case "group": |
| | | case "groupofnames": |
| | | case "kolabgroupofnames": |
| | | $group_members = array_merge($group_members, $this->_list_group_members($dn, $entry, 'member', $count)); |
| | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) |
| | | break; |
| | | } |
| | |
| | | |
| | | for ($i=0; $i < $entry[$attr]['count']; $i++) |
| | | { |
| | | if (empty($entry[$attr][$i])) |
| | | continue; |
| | | |
| | | $result = @ldap_read($this->conn, $entry[$attr][$i], '(objectclass=*)', |
| | | $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']); |
| | | |
| | |
| | | |
| | | $attrib = $count ? array('dn') : array_values($this->fieldmap); |
| | | if ($result = @$func($this->conn, $m[1], $filter, |
| | | $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])) |
| | | { |
| | | $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) |
| | | ) { |
| | | $this->_debug("S: ".ldap_count_entries($this->conn, $result)." record(s) for ".$m[1]); |
| | | if ($err = ldap_errno($this->conn)) |
| | | $this->_debug("S: Error: " .ldap_err2str($err)); |
| | | } |
| | | else |
| | | { |
| | | else { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return $group_members; |
| | | } |
| | |
| | | * |
| | | * @param mixed $fields The field name of array of field names to search in |
| | | * @param mixed $value Search value (or array of values when $fields is array) |
| | | * @param boolean $strict True for strict, False for partial (fuzzy) matching |
| | | * @param int $mode Matching mode: |
| | | * 0 - partial (*abc*), |
| | | * 1 - strict (=), |
| | | * 2 - prefix (abc*) |
| | | * @param boolean $select True if results are requested, False if count only |
| | | * @param boolean $nocount (Not used) |
| | | * @param array $required List of fields that cannot be empty |
| | | * |
| | | * @return array Indexed list of contact records and 'count' value |
| | | */ |
| | | function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) |
| | | function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()) |
| | | { |
| | | $mode = intval($mode); |
| | | |
| | | // special treatment for ID-based search |
| | | if ($fields == 'ID' || $fields == $this->primary_key) |
| | | { |
| | |
| | | |
| | | $function = $this->_scope2func($this->prop['scope']); |
| | | $this->ldap_result = @$function($this->conn, $this->base_dn, $this->filter ? $this->filter : '(objectclass=*)', |
| | | array_values($this->fieldmap), 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']); |
| | | array_values($this->fieldmap), 0, $this->page_size, (int)$this->prop['timelimit']); |
| | | |
| | | $this->result = new rcube_result_set(0); |
| | | |
| | | if (!$this->ldap_result) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return $this->result; |
| | | } |
| | | |
| | | $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); |
| | | |
| | | // get all entries of this page and post-filter those that really match the query |
| | | $this->result = new rcube_result_set(0); |
| | | $search = mb_strtolower($value); |
| | | $entries = ldap_get_entries($this->conn, $this->ldap_result); |
| | | |
| | | for ($i = 0; $i < $entries['count']; $i++) { |
| | | $rec = $this->_ldap2result($entries[$i]); |
| | | if (stripos($rec['name'] . $rec['email'], $value) !== false) { |
| | | $this->result->add($rec); |
| | | $this->result->count++; |
| | | foreach (array('email', 'name') as $f) { |
| | | $val = mb_strtolower($rec[$f]); |
| | | switch ($mode) { |
| | | case 1: |
| | | $got = ($val == $search); |
| | | break; |
| | | case 2: |
| | | $got = ($search == substr($val, 0, strlen($search))); |
| | | break; |
| | | default: |
| | | $got = (strpos($val, $search) !== false); |
| | | break; |
| | | } |
| | | |
| | | if ($got) { |
| | | $this->result->add($rec); |
| | | $this->result->count++; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | // use AND operator for advanced searches |
| | | $filter = is_array($value) ? '(&' : '(|'; |
| | | $wc = !$strict && $this->prop['fuzzy_search'] ? '*' : ''; |
| | | // set wildcards |
| | | $wp = $ws = ''; |
| | | if (!empty($this->prop['fuzzy_search']) && $mode != 1) { |
| | | $ws = '*'; |
| | | if (!$mode) { |
| | | $wp = '*'; |
| | | } |
| | | } |
| | | |
| | | if ($fields == '*') |
| | | { |
| | |
| | | if (is_array($this->prop['search_fields'])) |
| | | { |
| | | foreach ($this->prop['search_fields'] as $field) { |
| | | $filter .= "($field=$wc" . $this->_quote_string($value) . "$wc)"; |
| | | $filter .= "($field=$wp" . $this->_quote_string($value) . "$ws)"; |
| | | } |
| | | } |
| | | } |
| | |
| | | foreach ((array)$fields as $idx => $field) { |
| | | $val = is_array($value) ? $value[$idx] : $value; |
| | | if ($f = $this->_map_field($field)) { |
| | | $filter .= "($f=$wc" . $this->_quote_string($val) . "$wc)"; |
| | | $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; |
| | | } |
| | | } |
| | | } |
| | |
| | | // The filter is not set, set it. |
| | | $this->filter = $this->prop['filter']; |
| | | } |
| | | $this->_exec_search(true); |
| | | if ($this->ldap_result) { |
| | | $count = ldap_count_entries($this->conn, $this->ldap_result); |
| | | } |
| | | |
| | | $count = (int) $this->_exec_search(true); |
| | | } |
| | | |
| | | return new rcube_result_set($count, ($this->list_page-1) * $this->page_size); |
| | |
| | | */ |
| | | function get_record($dn, $assoc=false) |
| | | { |
| | | $res = null; |
| | | $res = $this->result = null; |
| | | |
| | | if ($this->conn && $dn) |
| | | { |
| | | $dn = self::dn_decode($dn); |
| | | |
| | | $this->_debug("C: Read [dn: $dn] [(objectclass=*)]"); |
| | | |
| | | if ($this->ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', array_values($this->fieldmap))) |
| | | $entry = ldap_first_entry($this->conn, $this->ldap_result); |
| | | else |
| | | if ($ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', array_values($this->fieldmap))) { |
| | | $this->_debug("S: OK"); |
| | | |
| | | $entry = ldap_first_entry($this->conn, $ldap_result); |
| | | |
| | | if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) { |
| | | $rec = array_change_key_case($rec, CASE_LOWER); |
| | | } |
| | | } |
| | | else { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | } |
| | | |
| | | if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) |
| | | { |
| | | $this->_debug("S: OK"/* . print_r($rec, true)*/); |
| | | // Use ldap_list to get subentries like country (c) attribute (#1488123) |
| | | if (!empty($rec) && $this->sub_filter) { |
| | | if ($entries = $this->ldap_list($dn, $this->sub_filter, array_keys($this->prop['sub_fields']))) { |
| | | foreach ($entries as $entry) { |
| | | $lrec = array_change_key_case($entry, CASE_LOWER); |
| | | $rec = array_merge($lrec, $rec); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $rec = array_change_key_case($rec, CASE_LOWER); |
| | | |
| | | if (!empty($rec)) { |
| | | // Add in the dn for the entry. |
| | | $rec['dn'] = $dn; |
| | | $res = $this->_ldap2result($rec); |
| | | $this->result = new rcube_result_set(1); |
| | | $this->result = new rcube_result_set(); |
| | | $this->result->add($res); |
| | | } |
| | | } |
| | |
| | | */ |
| | | public function validate(&$save_data, $autofix = false) |
| | | { |
| | | // validate e-mail addresses |
| | | if (!parent::validate($save_data, $autofix)) { |
| | | return false; |
| | | } |
| | | |
| | | // check for name input |
| | | if (empty($save_data['name'])) { |
| | | $this->set_error(self::ERROR_VALIDATE, 'nonamewarning'); |
| | |
| | | $missing = null; |
| | | $ldap_data = $this->_map_data($save_data); |
| | | foreach ($this->prop['required_fields'] as $fld) { |
| | | if (!isset($ldap_data[$fld])) { |
| | | if (!isset($ldap_data[$fld]) || $ldap_data[$fld] === '') { |
| | | $missing[$fld] = 1; |
| | | } |
| | | } |
| | |
| | | if ($missing) { |
| | | // try to complete record automatically |
| | | if ($autofix) { |
| | | $sn_field = $this->fieldmap['surname']; |
| | | $fn_field = $this->fieldmap['firstname']; |
| | | $mail_field = $this->fieldmap['email']; |
| | | |
| | | // try to extract surname and firstname from displayname |
| | | $reverse_map = array_flip($this->fieldmap); |
| | | $name_parts = preg_split('/[\s,.]+/', $save_data['name']); |
| | | if ($missing['sn']) { |
| | | $sn_field = $reverse_map['sn']; |
| | | $save_data[$sn_field] = array_pop ($name_parts); |
| | | } |
| | | if ($missing[($fn_field = $this->fieldmap['firstname'])]) { |
| | | $save_data['firstname'] = array_shift($name_parts); |
| | | $name_parts = preg_split('/[\s,.]+/', $save_data['name']); |
| | | |
| | | if ($sn_field && $missing[$sn_field]) { |
| | | $save_data['surname'] = array_pop($name_parts); |
| | | unset($missing[$sn_field]); |
| | | } |
| | | |
| | | return $this->validate($save_data, false); |
| | | if ($fn_field && $missing[$fn_field]) { |
| | | $save_data['firstname'] = array_shift($name_parts); |
| | | unset($missing[$fn_field]); |
| | | } |
| | | |
| | | // try to fix missing e-mail, very often on import |
| | | // from vCard we have email:other only defined |
| | | if ($mail_field && $missing[$mail_field]) { |
| | | $emails = $this->get_col_values('email', $save_data, true); |
| | | if (!empty($emails) && ($email = array_shift($emails))) { |
| | | $save_data['email'] = $email; |
| | | unset($missing[$mail_field]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // TODO: generate message saying which fields are missing |
| | | $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); |
| | | return false; |
| | | if (!empty($missing)) { |
| | | $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // validate e-mail addresses |
| | | return parent::validate($save_data, $autofix); |
| | | return true; |
| | | } |
| | | |
| | | |
| | |
| | | // Build the new entries DN. |
| | | $dn = $this->prop['LDAP_rdn'].'='.$this->_quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->base_dn; |
| | | |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($newentry, true)); |
| | | // Remove attributes that need to be added separately (child objects) |
| | | $xfields = array(); |
| | | if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { |
| | | foreach ($this->prop['sub_fields'] as $xf => $xclass) { |
| | | if (!empty($newentry[$xf])) { |
| | | $xfields[$xf] = $newentry[$xf]; |
| | | unset($newentry[$xf]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $res = ldap_add($this->conn, $dn, $newentry); |
| | | if ($res === FALSE) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_add($dn, $newentry)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } // end if |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | foreach ($xfields as $xidx => $xf) { |
| | | $xdn = $xidx.'='.$this->_quote_string($xf).','.$dn; |
| | | $xf = array( |
| | | $xidx => $xf, |
| | | 'objectClass' => (array) $this->prop['sub_fields'][$xidx], |
| | | ); |
| | | |
| | | $this->ldap_add($xdn, $xf); |
| | | } |
| | | |
| | | $dn = self::dn_encode($dn); |
| | | |
| | | // add new contact to the selected group |
| | | if ($this->groups) |
| | | if ($this->group_id) |
| | | $this->add_to_group($this->group_id, $dn); |
| | | |
| | | return $dn; |
| | |
| | | function update($id, $save_cols) |
| | | { |
| | | $record = $this->get_record($id, true); |
| | | $result = $this->get_result(); |
| | | $record = $result->first(); |
| | | |
| | | $newdata = array(); |
| | | $newdata = array(); |
| | | $replacedata = array(); |
| | | $deletedata = array(); |
| | | $deletedata = array(); |
| | | $subdata = array(); |
| | | $subdeldata = array(); |
| | | $subnewdata = array(); |
| | | |
| | | // flatten composite fields in $record |
| | | if (is_array($record['address'])) { |
| | | foreach ($record['address'] as $i => $struct) { |
| | | foreach ($struct as $col => $val) { |
| | | $record[$col][$i] = $val; |
| | | $ldap_data = $this->_map_data($save_cols); |
| | | $old_data = $record['_raw_attrib']; |
| | | |
| | | // special handling of photo col |
| | | if ($photo_fld = $this->fieldmap['photo']) { |
| | | // undefined means keep old photo |
| | | if (!array_key_exists('photo', $save_cols)) { |
| | | $ldap_data[$photo_fld] = $record['photo']; |
| | | } |
| | | } |
| | | } |
| | | |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | | if ($fld) { |
| | | $val = $ldap_data[$fld]; |
| | | $old = $old_data[$fld]; |
| | | // remove empty array values |
| | | if (is_array($val)) |
| | | $val = array_filter($val); |
| | | // $this->_map_data() result and _raw_attrib use different format |
| | | // make sure comparing array with one element with a string works as expected |
| | | if (is_array($old) && count($old) == 1 && !is_array($val)) { |
| | | $old = array_pop($old); |
| | | } |
| | | if (is_array($val) && count($val) == 1 && !is_array($old)) { |
| | | $val = array_pop($val); |
| | | } |
| | | // Subentries must be handled separately |
| | | if (!empty($this->prop['sub_fields']) && isset($this->prop['sub_fields'][$fld])) { |
| | | if ($old != $val) { |
| | | if ($old !== null) { |
| | | $subdeldata[$fld] = $old; |
| | | } |
| | | if ($val) { |
| | | $subnewdata[$fld] = $val; |
| | | } |
| | | } |
| | | else if ($old !== null) { |
| | | $subdata[$fld] = $old; |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | // The field does exist compare it to the ldap record. |
| | | if ($record[$col] != $val) { |
| | | if ($old != $val) { |
| | | // Changed, but find out how. |
| | | if (!isset($record[$col])) { |
| | | if ($old === null) { |
| | | // Field was not set prior, need to add it. |
| | | $newdata[$fld] = $val; |
| | | } // end if |
| | | elseif ($val == '') { |
| | | } |
| | | else if ($val == '') { |
| | | // Field supplied is empty, verify that it is not required. |
| | | if (!in_array($fld, $this->prop['required_fields'])) { |
| | | // It is not, safe to clear. |
| | | $deletedata[$fld] = $record[$col]; |
| | | } // end if |
| | | } // end elseif |
| | | $deletedata[$fld] = $old_data[$fld]; |
| | | } |
| | | } |
| | | else { |
| | | // The data was modified, save it out. |
| | | $replacedata[$fld] = $val; |
| | | } // end else |
| | | } |
| | | } // end if |
| | | } // end if |
| | | } // end foreach |
| | | |
| | | /* |
| | | console($old_data); |
| | | console($ldap_data); |
| | | console('----'); |
| | | console($newdata); |
| | | console($replacedata); |
| | | console($deletedata); |
| | | console('----'); |
| | | console($subdata); |
| | | console($subnewdata); |
| | | console($subdeldata); |
| | | */ |
| | | $dn = self::dn_decode($id); |
| | | |
| | | // Update the entry as required. |
| | | if (!empty($deletedata)) { |
| | | // Delete the fields. |
| | | $this->_debug("C: Delete [dn: $dn]: ".print_r($deletedata, true)); |
| | | if (!ldap_mod_del($this->conn, $dn, $deletedata)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_mod_del($dn, $deletedata)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | | } // end if |
| | | |
| | | if (!empty($replacedata)) { |
| | |
| | | } |
| | | // Replace the fields. |
| | | if (!empty($replacedata)) { |
| | | $this->_debug("C: Replace [dn: $dn]: ".print_r($replacedata, true)); |
| | | if (!ldap_mod_replace($this->conn, $dn, $replacedata)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_mod_replace($dn, $replacedata)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | | } // end if |
| | | } |
| | | } // end if |
| | | |
| | | // RDN change, we need to remove all sub-entries |
| | | if (!empty($newrdn)) { |
| | | $subdeldata = array_merge($subdeldata, $subdata); |
| | | $subnewdata = array_merge($subnewdata, $subdata); |
| | | } |
| | | |
| | | // remove sub-entries |
| | | if (!empty($subdeldata)) { |
| | | foreach ($subdeldata as $fld => $val) { |
| | | $subdn = $fld.'='.$this->_quote_string($val).','.$dn; |
| | | if (!$this->ldap_delete($subdn)) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!empty($newdata)) { |
| | | // Add the fields. |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($newdata, true)); |
| | | if (!ldap_mod_add($this->conn, $dn, $newdata)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_mod_add($dn, $newdata)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | | } // end if |
| | | |
| | | // Handle RDN change |
| | | if (!empty($newrdn)) { |
| | | $this->_debug("C: Rename [dn: $dn] [dn: $newrdn]"); |
| | | if (!ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_rename($dn, $newrdn, null, true)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | | |
| | | $dn = self::dn_encode($dn); |
| | | $newdn = self::dn_encode($newdn); |
| | | |
| | | // change the group membership of the contact |
| | | if ($this->groups) |
| | | { |
| | | if ($this->groups) { |
| | | $group_ids = $this->get_record_groups($dn); |
| | | foreach ($group_ids as $group_id) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | return $newdn; |
| | | $dn = self::dn_decode($newdn); |
| | | } |
| | | |
| | | return true; |
| | | // add sub-entries |
| | | if (!empty($subnewdata)) { |
| | | foreach ($subnewdata as $fld => $val) { |
| | | $subdn = $fld.'='.$this->_quote_string($val).','.$dn; |
| | | $xf = array( |
| | | $fld => $val, |
| | | 'objectClass' => (array) $this->prop['sub_fields'][$fld], |
| | | ); |
| | | $this->ldap_add($subdn, $xf); |
| | | } |
| | | } |
| | | |
| | | return $newdn ? $newdn : true; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | foreach ($ids as $id) { |
| | | $dn = self::dn_decode($id); |
| | | $this->_debug("C: Delete [dn: $dn]"); |
| | | |
| | | // Need to delete all sub-entries first |
| | | if ($this->sub_filter) { |
| | | if ($entries = $this->ldap_list($dn, $this->sub_filter)) { |
| | | foreach ($entries as $entry) { |
| | | if (!$this->ldap_delete($entry['dn'])) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Delete the record. |
| | | $res = ldap_delete($this->conn, $dn); |
| | | if ($res === FALSE) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_delete($dn)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } // end if |
| | | $this->_debug("S: OK"); |
| | | } |
| | | |
| | | // remove contact from all groups where he was member |
| | | if ($this->groups) { |
| | |
| | | } // end foreach |
| | | |
| | | return count($ids); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Remove all contact records |
| | | */ |
| | | function delete_all() |
| | | { |
| | | //searching for contact entries |
| | | $dn_list = $this->ldap_list($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)'); |
| | | |
| | | if (!empty($dn_list)) { |
| | | foreach ($dn_list as $idx => $entry) { |
| | | $dn_list[$idx] = self::dn_encode($entry['dn']); |
| | | } |
| | | $this->delete($dn_list); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | // only fetch dn for count (should keep the payload low) |
| | | $attrs = $count ? array('dn') : array_values($this->fieldmap); |
| | | if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter, |
| | | $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])) |
| | | { |
| | | $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) |
| | | ) { |
| | | // when running on a patched PHP we can use the extended functions to retrieve the total count from the LDAP search result |
| | | if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control') && |
| | | ldap_parse_result($this->conn, $this->ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) { |
| | | ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $this->vlv_count, $vresult); |
| | | $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$this->vlv_count"); |
| | | if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) { |
| | | if (ldap_parse_result($this->conn, $this->ldap_result, |
| | | $errcode, $matcheddn, $errmsg, $referrals, $serverctrls) |
| | | ) { |
| | | ldap_parse_virtuallist_control($this->conn, $serverctrls, |
| | | $last_offset, $this->vlv_count, $vresult); |
| | | $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$this->vlv_count"); |
| | | } |
| | | else { |
| | | $this->_debug("S: ".($errmsg ? $errmsg : ldap_error($this->conn))); |
| | | } |
| | | } |
| | | |
| | | $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); |
| | | if ($err = ldap_errno($this->conn)) |
| | | $this->_debug("S: Error: " .ldap_err2str($err)); |
| | | $entries_count = ldap_count_entries($this->conn, $this->ldap_result); |
| | | $this->_debug("S: $entries_count record(s)"); |
| | | |
| | | return $count ? ldap_count_entries($this->conn, $this->ldap_result) : true; |
| | | return $count ? $entries_count : true; |
| | | } |
| | | else |
| | | { |
| | | else { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | } |
| | | } |
| | |
| | | $ns_function = 'ldap_read'; |
| | | break; |
| | | } |
| | | |
| | | |
| | | return $function; |
| | | } |
| | | |
| | |
| | | for ($i=0; $i < $rec[$lf]['count']; $i++) { |
| | | if (!($value = $rec[$lf][$i])) |
| | | continue; |
| | | |
| | | list($col, $subtype) = explode(':', $rf); |
| | | $out['_raw_attrib'][$lf][$i] = $value; |
| | | |
| | | if ($rf == 'email' && $this->mail_domain && !strpos($value, '@')) |
| | | $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); |
| | | else if (in_array($rf, array('street','zipcode','locality','country','region'))) |
| | | $out['address'][$i][$rf] = $value; |
| | | else if (in_array($col, array('street','zipcode','locality','country','region'))) |
| | | $out['address'.($subtype?':':'').$subtype][$i][$col] = $value; |
| | | else if ($rec[$lf]['count'] > 1) |
| | | $out[$rf][] = $value; |
| | | else |
| | |
| | | |
| | | // Make sure name fields aren't arrays (#1488108) |
| | | if (is_array($out[$rf]) && in_array($rf, array('name', 'surname', 'firstname', 'middlename', 'nickname'))) { |
| | | $out[$rf] = $out[$rf][0]; |
| | | $out[$rf] = $out['_raw_attrib'][$lf] = $out[$rf][0]; |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private function _map_data($save_cols) |
| | | { |
| | | // flatten composite fields first |
| | | foreach ($this->coltypes as $col => $colprop) { |
| | | if (is_array($colprop['childs']) && ($values = $this->get_col_values($col, $save_cols, false))) { |
| | | foreach ($values as $subtype => $childs) { |
| | | $subtype = $subtype ? ':'.$subtype : ''; |
| | | foreach ($childs as $i => $child_values) { |
| | | foreach ((array)$child_values as $childcol => $value) { |
| | | $save_cols[$childcol.$subtype][$i] = $value; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | $ldap_data = array(); |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | |
| | | $ldap_data[$fld] = $val; |
| | | } |
| | | } |
| | | |
| | | |
| | | return $ldap_data; |
| | | } |
| | | |
| | |
| | | */ |
| | | private function _debug($str) |
| | | { |
| | | if ($this->debug) |
| | | write_log('ldap', $str); |
| | | if ($this->debug) { |
| | | rcmail::write_log('ldap', $str); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Activate/deactivate debug mode |
| | | * |
| | | * @param boolean $dbg True if LDAP commands should be logged |
| | | * @access public |
| | | */ |
| | | function set_debug($dbg = true) |
| | | { |
| | | $this->debug = $dbg; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | $groups = array(); |
| | | if ($search) { |
| | | $search = strtolower($search); |
| | | $search = mb_strtolower($search); |
| | | foreach ($group_cache as $group) { |
| | | if (strstr(strtolower($group['name']), $search)) |
| | | if (strpos(mb_strtolower($group['name']), $search) !== false) |
| | | $groups[] = $group; |
| | | } |
| | | } |
| | |
| | | $groups[$group_id]['ID'] = $group_id; |
| | | $groups[$group_id]['dn'] = $ldap_data[$i]['dn']; |
| | | $groups[$group_id]['name'] = $group_name; |
| | | $groups[$group_id]['member_attr'] = $this->prop['member_attr']; |
| | | |
| | | // check objectClass attributes of group and act accordingly |
| | | for ($j=0; $j < $ldap_data[$i]['objectclass']['count']; $j++) { |
| | | switch (strtolower($ldap_data[$i]['objectclass'][$j])) { |
| | | case 'groupofnames': |
| | | case 'kolabgroupofnames': |
| | | $groups[$group_id]['member_attr'] = 'member'; |
| | | break; |
| | | |
| | | case 'groupofuniquenames': |
| | | case 'kolabgroupofuniquenames': |
| | | $groups[$group_id]['member_attr'] = 'uniqueMember'; |
| | | break; |
| | | } |
| | | } |
| | | $groups[$group_id]['member_attr'] = $this->get_group_member_attr($ldap_data[$i]['objectclass']); |
| | | |
| | | // list email attributes of a group |
| | | for ($j=0; $ldap_data[$i][$email_attr] && $j < $ldap_data[$i][$email_attr]['count']; $j++) { |
| | |
| | | $groups[$group_id]['email'][] = $ldap_data[$i][$email_attr][$j]; |
| | | } |
| | | |
| | | $group_sortnames[] = strtolower($ldap_data[$i][$sort_attr][0]); |
| | | $group_sortnames[] = mb_strtolower($ldap_data[$i][$sort_attr][0]); |
| | | } |
| | | |
| | | // recursive call can exit here |
| | |
| | | $base_dn = $this->groups_base_dn; |
| | | $new_dn = "cn=$group_name,$base_dn"; |
| | | $new_gid = self::dn_encode($group_name); |
| | | $name_attr = $this->prop['groups']['name_attr']; |
| | | $member_attr = $this->get_group_member_attr(); |
| | | $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; |
| | | |
| | | $new_entry = array( |
| | | 'objectClass' => $this->prop['groups']['object_classes'], |
| | | $name_attr => $group_name, |
| | | $member_attr => '', |
| | | ); |
| | | |
| | | $this->_debug("C: Add [dn: $new_dn]: ".print_r($new_entry, true)); |
| | | |
| | | $res = ldap_add($this->conn, $new_dn, $new_entry); |
| | | if ($res === false) |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_add($new_dn, $new_entry)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | $this->cache->remove('groups'); |
| | | |
| | | return array('id' => $new_gid, 'name' => $group_name); |
| | |
| | | $group_name = $group_cache[$group_id]['name']; |
| | | $del_dn = "cn=$group_name,$base_dn"; |
| | | |
| | | $this->_debug("C: Delete [dn: $del_dn]"); |
| | | |
| | | $res = ldap_delete($this->conn, $del_dn); |
| | | if ($res === false) |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_delete($del_dn)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | $this->cache->remove('groups'); |
| | | |
| | | return true; |
| | |
| | | $new_rdn = "cn=$new_name"; |
| | | $new_gid = self::dn_encode($new_name); |
| | | |
| | | $this->_debug("C: Rename [dn: $old_dn] [dn: $new_rdn]"); |
| | | |
| | | $res = ldap_rename($this->conn, $old_dn, $new_rdn, NULL, TRUE); |
| | | if ($res === false) |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_rename($old_dn, $new_rdn, null, true)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | $this->cache->remove('groups'); |
| | | |
| | | return $new_name; |
| | |
| | | if (($group_cache = $this->cache->get('groups')) === null) |
| | | $group_cache = $this->_fetch_groups(); |
| | | |
| | | if (!is_array($contact_ids)) |
| | | $contact_ids = explode(',', $contact_ids); |
| | | |
| | | $base_dn = $this->groups_base_dn; |
| | | $group_name = $group_cache[$group_id]['name']; |
| | | $member_attr = $group_cache[$group_id]['member_attr']; |
| | | $group_dn = "cn=$group_name,$base_dn"; |
| | | |
| | | $new_attrs = array(); |
| | | foreach (explode(",", $contact_ids) as $id) |
| | | foreach ($contact_ids as $id) |
| | | $new_attrs[$member_attr][] = self::dn_decode($id); |
| | | |
| | | $this->_debug("C: Add [dn: $group_dn]: ".print_r($new_attrs, true)); |
| | | |
| | | $res = ldap_mod_add($this->conn, $group_dn, $new_attrs); |
| | | if ($res === false) |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_mod_add($group_dn, $new_attrs)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return 0; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | $this->cache->remove('groups'); |
| | | |
| | | return count($new_attrs['member']); |
| | |
| | | foreach (explode(",", $contact_ids) as $id) |
| | | $del_attrs[$member_attr][] = self::dn_decode($id); |
| | | |
| | | $this->_debug("C: Delete [dn: $group_dn]: ".print_r($del_attrs, true)); |
| | | |
| | | $res = ldap_mod_del($this->conn, $group_dn, $del_attrs); |
| | | if ($res === false) |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | if (!$this->ldap_mod_del($group_dn, $del_attrs)) { |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return 0; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | $this->cache->remove('groups'); |
| | | |
| | | return count($del_attrs['member']); |
| | |
| | | |
| | | $base_dn = $this->groups_base_dn; |
| | | $contact_dn = self::dn_decode($contact_id); |
| | | $name_attr = $this->prop['groups']['name_attr']; |
| | | $member_attr = $this->prop['member_attr']; |
| | | $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; |
| | | $member_attr = $this->get_group_member_attr(); |
| | | $add_filter = ''; |
| | | if ($member_attr != 'member' && $member_attr != 'uniqueMember') |
| | | $add_filter = "($member_attr=$contact_dn)"; |
| | |
| | | $groups[$group_id] = $group_id; |
| | | } |
| | | return $groups; |
| | | } |
| | | |
| | | /** |
| | | * Detects group member attribute name |
| | | */ |
| | | private function get_group_member_attr($object_classes = array()) |
| | | { |
| | | if (empty($object_classes)) { |
| | | $object_classes = $this->prop['groups']['object_classes']; |
| | | } |
| | | if (!empty($object_classes)) { |
| | | foreach ((array)$object_classes as $oc) { |
| | | switch (strtolower($oc)) { |
| | | case 'group': |
| | | case 'groupofnames': |
| | | case 'kolabgroupofnames': |
| | | $member_attr = 'member'; |
| | | break; |
| | | |
| | | case 'groupofuniquenames': |
| | | case 'kolabgroupofuniquenames': |
| | | $member_attr = 'uniqueMember'; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!empty($member_attr)) { |
| | | return $member_attr; |
| | | } |
| | | |
| | | if (!empty($this->prop['groups']['member_attr'])) { |
| | | return $this->prop['groups']['member_attr']; |
| | | } |
| | | |
| | | return 'member'; |
| | | } |
| | | |
| | | |
| | |
| | | $str = str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=', STR_PAD_RIGHT); |
| | | return base64_decode($str); |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_add() |
| | | */ |
| | | protected function ldap_add($dn, $entry) |
| | | { |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($entry, true)); |
| | | |
| | | $res = ldap_add($this->conn, $dn, $entry); |
| | | if ($res === false) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_delete() |
| | | */ |
| | | protected function ldap_delete($dn) |
| | | { |
| | | $this->_debug("C: Delete [dn: $dn]"); |
| | | |
| | | $res = ldap_delete($this->conn, $dn); |
| | | if ($res === false) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_mod_replace() |
| | | */ |
| | | protected function ldap_mod_replace($dn, $entry) |
| | | { |
| | | $this->_debug("C: Replace [dn: $dn]: ".print_r($entry, true)); |
| | | |
| | | if (!ldap_mod_replace($this->conn, $dn, $entry)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_mod_add() |
| | | */ |
| | | protected function ldap_mod_add($dn, $entry) |
| | | { |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($entry, true)); |
| | | |
| | | if (!ldap_mod_add($this->conn, $dn, $entry)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_mod_del() |
| | | */ |
| | | protected function ldap_mod_del($dn, $entry) |
| | | { |
| | | $this->_debug("C: Delete [dn: $dn]: ".print_r($entry, true)); |
| | | |
| | | if (!ldap_mod_del($this->conn, $dn, $entry)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_rename() |
| | | */ |
| | | protected function ldap_rename($dn, $newrdn, $newparent = null, $deleteoldrdn = true) |
| | | { |
| | | $this->_debug("C: Rename [dn: $dn] [dn: $newrdn]"); |
| | | |
| | | if (!ldap_rename($this->conn, $dn, $newrdn, $newparent, $deleteoldrdn)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return false; |
| | | } |
| | | |
| | | $this->_debug("S: OK"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Wrapper for ldap_list() |
| | | */ |
| | | protected function ldap_list($dn, $filter, $attrs = array('')) |
| | | { |
| | | $list = array(); |
| | | $this->_debug("C: List [dn: $dn] [{$filter}]"); |
| | | |
| | | if ($result = ldap_list($this->conn, $dn, $filter, $attrs)) { |
| | | $list = ldap_get_entries($this->conn, $result); |
| | | |
| | | if ($list === false) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return array(); |
| | | } |
| | | |
| | | $count = $list['count']; |
| | | unset($list['count']); |
| | | |
| | | $this->_debug("S: $count record(s)"); |
| | | } |
| | | else { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | } |
| | | |
| | | return $list; |
| | | } |
| | | |
| | | } |