1 | <?php |
||||
2 | /** |
||||
3 | * API - accounts SQL backend |
||||
4 | * |
||||
5 | * The SQL backend stores the group memberships via the ACL class (location 'phpgw_group') |
||||
6 | * |
||||
7 | * The (positive) account_id's of groups are mapped in this class to negative numeric |
||||
8 | * account_id's, to conform with the way we handle groups in LDAP! |
||||
9 | * |
||||
10 | * @link http://www.egroupware.org |
||||
11 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> complete rewrite in 6/2006 and |
||||
12 | * earlier to use the new DB functions |
||||
13 | * |
||||
14 | * This class replaces the former accounts_sql class written by |
||||
15 | * Joseph Engo <[email protected]>, Dan Kuykendall <[email protected]> |
||||
16 | * and Bettina Gille <[email protected]>. |
||||
17 | * Copyright (C) 2000 - 2002 Joseph Engo |
||||
18 | * Copyright (C) 2003 Lars Kneschke, Bettina Gille |
||||
19 | * |
||||
20 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||
21 | * @package api |
||||
22 | * @subpackage accounts |
||||
23 | * @version $Id$ |
||||
24 | */ |
||||
25 | |||||
26 | namespace EGroupware\Api\Accounts; |
||||
27 | |||||
28 | use EGroupware\Api; |
||||
29 | |||||
30 | /** |
||||
31 | * SQL Backend for accounts |
||||
32 | * |
||||
33 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||
34 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||
35 | * @access internal only use the interface provided by the accounts class |
||||
36 | */ |
||||
37 | class Sql |
||||
38 | { |
||||
39 | /** |
||||
40 | * instance of the db class |
||||
41 | * |
||||
42 | * @var Api\Db |
||||
43 | */ |
||||
44 | var $db; |
||||
45 | /** |
||||
46 | * table name for the accounts |
||||
47 | * |
||||
48 | * @var string |
||||
49 | */ |
||||
50 | const TABLE = 'egw_accounts'; |
||||
51 | var $table = self::TABLE; |
||||
52 | /** |
||||
53 | * table name for the contacts |
||||
54 | * |
||||
55 | * @var string |
||||
56 | */ |
||||
57 | var $contacts_table = 'egw_addressbook'; |
||||
58 | /** |
||||
59 | * Join with the accounts-table used in contacts::search |
||||
60 | * |
||||
61 | * @var string |
||||
62 | */ |
||||
63 | var $contacts_join = ' RIGHT JOIN egw_accounts ON egw_accounts.account_id=egw_addressbook.account_id'; |
||||
64 | /** |
||||
65 | * total number of found entries from get_list method |
||||
66 | * |
||||
67 | * @var int |
||||
68 | */ |
||||
69 | var $total; |
||||
70 | |||||
71 | /** |
||||
72 | * Reference to our frontend |
||||
73 | * |
||||
74 | * @var accounts |
||||
0 ignored issues
–
show
|
|||||
75 | */ |
||||
76 | private $frontend; |
||||
77 | |||||
78 | /** |
||||
79 | * Instance of contacts object, NOT automatic instanciated! |
||||
80 | * |
||||
81 | * @var Api\Contacts |
||||
82 | */ |
||||
83 | private $contacts; |
||||
84 | |||||
85 | /** |
||||
86 | * does backend allow to change account_lid |
||||
87 | */ |
||||
88 | const CHANGE_ACCOUNT_LID = true; |
||||
89 | |||||
90 | /** |
||||
91 | * does backend requires password to be set, before allowing to enable an account |
||||
92 | */ |
||||
93 | const REQUIRE_PASSWORD_FOR_ENABLE = false; |
||||
94 | |||||
95 | /** |
||||
96 | * Constructor |
||||
97 | * |
||||
98 | * @param Api\Accounts $frontend reference to the frontend class, to be able to call it's methods if needed |
||||
99 | */ |
||||
100 | function __construct(Api\Accounts $frontend) |
||||
101 | { |
||||
102 | $this->frontend = $frontend; |
||||
0 ignored issues
–
show
It seems like
$frontend of type EGroupware\Api\Accounts is incompatible with the declared type EGroupware\Api\Accounts\accounts of property $frontend .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||
103 | |||||
104 | if (is_object($GLOBALS['egw_setup']->db)) |
||||
105 | { |
||||
106 | $this->db = $GLOBALS['egw_setup']->db; |
||||
107 | } |
||||
108 | else |
||||
109 | { |
||||
110 | $this->db = $GLOBALS['egw']->db; |
||||
111 | } |
||||
112 | } |
||||
113 | |||||
114 | /** |
||||
115 | * Reads the data of one account |
||||
116 | * |
||||
117 | * For performance reasons and because the contacts-object itself depends on the accounts-object, |
||||
118 | * we directly join with the contacts table for reading! |
||||
119 | * |
||||
120 | * @param int $account_id numeric account-id |
||||
121 | * @return array/boolean array with account data (keys: account_id, account_lid, ...) or false if account not found |
||||
0 ignored issues
–
show
|
|||||
122 | */ |
||||
123 | function read($account_id) |
||||
124 | { |
||||
125 | if (!(int)$account_id) return false; |
||||
126 | |||||
127 | if ($account_id > 0) |
||||
128 | { |
||||
129 | $extra_cols = $this->contacts_table.'.n_given AS account_firstname,'. |
||||
130 | $this->contacts_table.'.n_family AS account_lastname,'. |
||||
131 | $this->contacts_table.'.contact_email AS account_email,'. |
||||
132 | $this->contacts_table.'.n_fn AS account_fullname,'. |
||||
133 | $this->contacts_table.'.contact_id AS person_id,'. |
||||
134 | $this->contacts_table.'.contact_created AS account_created,'. |
||||
135 | $this->contacts_table.'.contact_modified AS account_modified,'. |
||||
136 | $this->contacts_table.'.tel_work AS account_phone,'; |
||||
137 | $join = 'LEFT JOIN '.$this->contacts_table.' ON '.$this->table.'.account_id='.$this->contacts_table.'.account_id'; |
||||
138 | } |
||||
139 | // during setup emailadmin might not yet be installed and running below query |
||||
140 | // will abort transaction in PostgreSQL |
||||
141 | elseif (!isset($GLOBALS['egw_setup']) || in_array(Api\Mail\Smtp\Sql::TABLE, $this->db->table_names(true))) |
||||
142 | { |
||||
143 | $extra_cols = Api\Mail\Smtp\Sql::TABLE.'.mail_value AS account_email,'; |
||||
144 | $join = 'LEFT JOIN '.Api\Mail\Smtp\Sql::TABLE.' ON '.$this->table.'.account_id=-'.Api\Mail\Smtp\Sql::TABLE.'.account_id AND mail_type='.Api\Mail\Smtp\Sql::TYPE_ALIAS; |
||||
145 | } |
||||
146 | try { |
||||
147 | $rs = $this->db->select($this->table, $extra_cols.$this->table.'.*', |
||||
148 | $this->table.'.account_id='.abs($account_id), |
||||
149 | __LINE__, __FILE__, false, '', false, 0, $join); |
||||
150 | } |
||||
151 | catch (Api\Db\Exception $e) { |
||||
152 | unset($e); |
||||
153 | } |
||||
154 | |||||
155 | if (!$rs) // handle not (yet) existing mailaccounts table |
||||
0 ignored issues
–
show
|
|||||
156 | { |
||||
157 | $rs = $this->db->select($this->table, $this->table.'.*', |
||||
158 | $this->table.'.account_id='.abs($account_id), __LINE__, __FILE__); |
||||
159 | } |
||||
160 | if (!$rs || !($data = $rs->fetch())) |
||||
0 ignored issues
–
show
|
|||||
161 | { |
||||
162 | return false; |
||||
163 | } |
||||
164 | if ($data['account_type'] == 'g') |
||||
165 | { |
||||
166 | $data['account_id'] = -$data['account_id']; |
||||
167 | $data['mailAllowed'] = true; |
||||
168 | } |
||||
169 | if (!$data['account_firstname']) $data['account_firstname'] = $data['account_lid']; |
||||
170 | if (!$data['account_lastname']) |
||||
171 | { |
||||
172 | $data['account_lastname'] = $data['account_type'] == 'g' ? 'Group' : 'User'; |
||||
173 | // if we call lang() before the translation-class is correctly setup, |
||||
174 | // we can't switch away from english language anymore! |
||||
175 | if (Api\Translation::$lang_arr) |
||||
0 ignored issues
–
show
The expression
EGroupware\Api\Translation::lang_arr of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
176 | { |
||||
177 | $data['account_lastname'] = lang($data['account_lastname']); |
||||
178 | } |
||||
179 | } |
||||
180 | if (!$data['account_fullname']) $data['account_fullname'] = $data['account_firstname'].' '.$data['account_lastname']; |
||||
181 | |||||
182 | return $data; |
||||
183 | } |
||||
184 | |||||
185 | /** |
||||
186 | * Saves / adds the data of one account |
||||
187 | * |
||||
188 | * If no account_id is set in data the account is added and the new id is set in $data. |
||||
189 | * |
||||
190 | * @param array $data array with account-data |
||||
191 | * @return int/boolean the account_id or false on error |
||||
0 ignored issues
–
show
|
|||||
192 | */ |
||||
193 | function save(&$data) |
||||
194 | { |
||||
195 | $to_write = $data; |
||||
196 | unset($to_write['account_passwd']); |
||||
197 | // encrypt password if given or unset it if not |
||||
198 | if ($data['account_passwd']) |
||||
199 | { |
||||
200 | // if password it's not already entcrypted, do so now |
||||
201 | if (!preg_match('/^\\{[a-z5]{3,5}\\}.+/i',$data['account_passwd']) && |
||||
202 | !preg_match('/^[0-9a-f]{32}$/',$data['account_passwd'])) // md5 hash |
||||
203 | { |
||||
204 | $data['account_passwd'] = Api\Auth::encrypt_sql($data['account_passwd']); |
||||
205 | } |
||||
206 | $to_write['account_pwd'] = $data['account_passwd']; |
||||
207 | $to_write['account_lastpwd_change'] = time(); |
||||
208 | } |
||||
209 | if ($data['mustchangepassword'] == 1) $to_write['account_lastpwd_change']=0; |
||||
210 | if (!(int)$data['account_id'] || !$this->id2name($data['account_id'])) |
||||
211 | { |
||||
212 | if ($to_write['account_id'] < 0) $to_write['account_id'] *= -1; |
||||
213 | |||||
214 | if (!isset($to_write['account_pwd'])) $to_write['account_pwd'] = ''; // is NOT NULL! |
||||
215 | if (!isset($to_write['account_status'])) $to_write['account_status'] = ''; // is NOT NULL! |
||||
216 | |||||
217 | // postgres requires the auto-id field to be unset! |
||||
218 | if (isset($to_write['account_id']) && !$to_write['account_id']) unset($to_write['account_id']); |
||||
219 | |||||
220 | if (!in_array($to_write['account_type'],array('u','g')) || |
||||
221 | !$this->db->insert($this->table,$to_write,false,__LINE__,__FILE__)) return false; |
||||
222 | |||||
223 | if (!(int)$data['account_id']) |
||||
224 | { |
||||
225 | $data['account_id'] = $this->db->get_last_insert_id($this->table,'account_id'); |
||||
226 | if ($data['account_type'] == 'g') $data['account_id'] *= -1; |
||||
227 | } |
||||
228 | } |
||||
229 | else // update of existing account |
||||
230 | { |
||||
231 | unset($to_write['account_id']); |
||||
232 | if (!$this->db->update($this->table,$to_write,array('account_id' => abs($data['account_id'])),__LINE__,__FILE__)) |
||||
233 | { |
||||
234 | return false; |
||||
235 | } |
||||
236 | } |
||||
237 | // store group-email in mailaccounts table |
||||
238 | if ($data['account_id'] < 0 && class_exists('EGroupware\\Api\\Mail\\Smtp\\Sql', isset($data['account_email']))) |
||||
239 | { |
||||
240 | try { |
||||
241 | if (isset($GLOBALS['egw_setup']) && !in_array(Api\Mail\Smtp\Sql::TABLE, $this->db->table_names(true))) |
||||
242 | { |
||||
243 | // cant store email, if table not yet exists |
||||
244 | } |
||||
245 | elseif (empty($data['account_email'])) |
||||
246 | { |
||||
247 | $this->db->delete(Api\Mail\Smtp\Sql::TABLE, array( |
||||
248 | 'account_id' => $data['account_id'], |
||||
249 | 'mail_type' => Api\Mail\Smtp\Sql::TYPE_ALIAS, |
||||
250 | ), __LINE__, __FILE__, Api\Mail\Smtp\Sql::APP); |
||||
251 | } |
||||
252 | else |
||||
253 | { |
||||
254 | $this->db->insert(Api\Mail\Smtp\Sql::TABLE, array( |
||||
255 | 'mail_value' => $data['account_email'], |
||||
256 | ), array( |
||||
257 | 'account_id' => $data['account_id'], |
||||
258 | 'mail_type' => Api\Mail\Smtp\Sql::TYPE_ALIAS, |
||||
259 | ), __LINE__, __FILE__, Api\Mail\Smtp\Sql::APP); |
||||
260 | } |
||||
261 | } |
||||
262 | // ignore not (yet) existing mailaccounts table (does NOT work in PostgreSQL, because of transaction!) |
||||
263 | catch (Api\Db\Exception $e) { |
||||
264 | unset($e); |
||||
265 | } |
||||
266 | } |
||||
267 | return $data['account_id']; |
||||
268 | } |
||||
269 | |||||
270 | /** |
||||
271 | * Delete one account, deletes also all acl-entries for that account |
||||
272 | * |
||||
273 | * @param int $account_id numeric account_id |
||||
274 | * @return boolean true on success, false otherwise |
||||
275 | */ |
||||
276 | function delete($account_id) |
||||
277 | { |
||||
278 | if (!(int)$account_id) return false; |
||||
279 | |||||
280 | $contact_id = $this->id2name($account_id,'person_id'); |
||||
281 | |||||
282 | if (!$this->db->delete($this->table,array('account_id' => abs($account_id)),__LINE__,__FILE__)) |
||||
283 | { |
||||
284 | return false; |
||||
285 | } |
||||
286 | if ($contact_id) |
||||
287 | { |
||||
288 | if (!isset($this->contacts)) $this->contacts = new Api\Contacts(); |
||||
289 | $this->contacts->delete($contact_id,false); // false = allow to delete accounts (!) |
||||
290 | } |
||||
291 | return true; |
||||
292 | } |
||||
293 | |||||
294 | /** |
||||
295 | * Get all memberships of an account $accountid / groups the account is a member off |
||||
296 | * |
||||
297 | * @param int $account_id numeric account-id |
||||
298 | * @return array/boolean array with account_id => account_lid pairs or false if account not found |
||||
0 ignored issues
–
show
|
|||||
299 | */ |
||||
300 | function memberships($account_id) |
||||
301 | { |
||||
302 | if (!(int)$account_id) return false; |
||||
303 | |||||
304 | $memberships = array(); |
||||
305 | if(($gids = $GLOBALS['egw']->acl->get_location_list_for_id('phpgw_group', 1, $account_id))) |
||||
306 | { |
||||
307 | foreach($gids as $gid) |
||||
308 | { |
||||
309 | $memberships[(string) $gid] = $this->id2name($gid); |
||||
310 | } |
||||
311 | } |
||||
312 | return $memberships; |
||||
313 | } |
||||
314 | |||||
315 | /** |
||||
316 | * Sets the memberships of the account this class is instanciated for |
||||
317 | * |
||||
318 | * @param array $groups array with gidnumbers |
||||
319 | * @param int $account_id numerical account-id |
||||
320 | */ |
||||
321 | function set_memberships($groups,$account_id) |
||||
322 | { |
||||
323 | if (!(int)$account_id) return; |
||||
324 | |||||
325 | $acl = new Api\Acl($account_id); |
||||
326 | $acl->read_repository(); |
||||
327 | $acl->delete('phpgw_group',false); |
||||
328 | |||||
329 | foreach($groups as $group) |
||||
330 | { |
||||
331 | $acl->add('phpgw_group',$group,1); |
||||
332 | } |
||||
333 | $acl->save_repository(); |
||||
334 | } |
||||
335 | |||||
336 | /** |
||||
337 | * Get all members of the group $accountid |
||||
338 | * |
||||
339 | * @param int/string $account_id numeric account-id |
||||
0 ignored issues
–
show
|
|||||
340 | * @return array with account_id => account_lid pairs |
||||
341 | */ |
||||
342 | function members($account_id) |
||||
343 | { |
||||
344 | if (!is_numeric($account_id)) $account_id = $this->name2id($account_id); |
||||
345 | |||||
346 | $members = array(); |
||||
347 | foreach($this->db->select($this->table, 'account_id,account_lid', |
||||
348 | $this->db->expression(Api\Acl::TABLE, array( |
||||
349 | 'acl_appname' => 'phpgw_group', |
||||
350 | 'acl_location' => $account_id, |
||||
351 | )), __LINE__, __FILE__, false, '', false, 0, |
||||
352 | 'JOIN '.Api\Acl::TABLE.' ON account_id=acl_account' |
||||
353 | ) as $row) |
||||
354 | { |
||||
355 | $members[$row['account_id']] = $row['account_lid']; |
||||
356 | } |
||||
357 | return $members; |
||||
358 | } |
||||
359 | |||||
360 | /** |
||||
361 | * Set the members of a group |
||||
362 | * |
||||
363 | * @param array $members array with uidnumber or uid's |
||||
364 | * @param int $gid gidnumber of group to set |
||||
365 | */ |
||||
366 | function set_members($members,$gid) |
||||
367 | { |
||||
368 | $GLOBALS['egw']->acl->delete_repository('phpgw_group',$gid,false); |
||||
369 | |||||
370 | if (is_array($members)) |
||||
0 ignored issues
–
show
|
|||||
371 | { |
||||
372 | foreach($members as $id) |
||||
373 | { |
||||
374 | $GLOBALS['egw']->acl->add_repository('phpgw_group',$gid,$id,1); |
||||
375 | } |
||||
376 | } |
||||
377 | } |
||||
378 | |||||
379 | /** |
||||
380 | * Searches / lists accounts: users and/or groups |
||||
381 | * |
||||
382 | * @param array with the following keys: |
||||
383 | * @param $param['type'] string/int 'accounts', 'groups', 'owngroups' (groups the user is a member of), 'both', |
||||
0 ignored issues
–
show
|
|||||
384 | * 'groupmember' or 'groupmembers+memberships' |
||||
385 | * or integer group-id for a list of members of that group |
||||
386 | * @param $param['start'] int first account to return (returns offset or max_matches entries) or all if not set |
||||
387 | * @param $param['order'] string column to sort after, default account_lid if unset |
||||
388 | * @param $param['sort'] string 'ASC' or 'DESC', default 'ASC' if not set |
||||
389 | * @param $param['query'] string to search for, no search if unset or empty |
||||
390 | * @param $param['query_type'] string: |
||||
391 | * 'all' - query all fields for containing $param[query] |
||||
392 | * 'start' - query all fields starting with $param[query] |
||||
393 | * 'exact' - query all fields for exact $param[query] |
||||
394 | * 'lid','firstname','lastname','email' - query only the given field for containing $param[query] |
||||
395 | * @param $param['offset'] int - number of matches to return if start given, default use the value in the prefs |
||||
396 | * @param $param['objectclass'] boolean return objectclass(es) under key 'objectclass' in each account |
||||
397 | * @return array with account_id => data pairs, data is an array with account_id, account_lid, account_firstname, |
||||
398 | * account_lastname, person_id (id of the linked addressbook entry), account_status, account_expires, account_primary_group |
||||
399 | */ |
||||
400 | function search($param) |
||||
401 | { |
||||
402 | static $order2contact = array( |
||||
403 | 'account_firstname' => 'n_given', |
||||
404 | 'account_lastname' => 'n_family', |
||||
405 | 'account_email' => 'contact_email', |
||||
406 | ); |
||||
407 | |||||
408 | // fetch order of account_fullname from Api\Accounts::format_username |
||||
409 | if (strpos($param['order'],'account_fullname') !== false) |
||||
410 | { |
||||
411 | $param['order'] = str_replace('account_fullname', preg_replace('/[ ,]+/',',',str_replace(array('[',']'),'', |
||||
412 | Api\Accounts::format_username('account_lid','account_firstname','account_lastname'))), $param['order']); |
||||
413 | } |
||||
414 | $order = str_replace(array_keys($order2contact),array_values($order2contact),$param['order']); |
||||
415 | |||||
416 | // allways add 'account_lid' |
||||
417 | if (strpos($order, 'account_lid') === false) |
||||
418 | { |
||||
419 | $order .= ($order?',':'').'account_lid'; |
||||
420 | } |
||||
421 | if ($param['sort']) $order = implode(' '.$param['sort'].',', explode(',', $order)).' '.$param['sort']; |
||||
422 | |||||
423 | $search_cols = array('account_lid','n_family','n_given','email'); |
||||
424 | $join = $this->contacts_join; |
||||
425 | $email_cols = array('email'); |
||||
426 | |||||
427 | // Add in group email searching |
||||
428 | if (!isset($GLOBALS['egw_setup']) || in_array(Api\Mail\Smtp\Sql::TABLE, $this->db->table_names(true))) |
||||
429 | { |
||||
430 | $email_cols = array('coalesce('.$this->contacts_table.'.contact_email,'.Api\Mail\Smtp\Sql::TABLE.'.mail_value) as email'); |
||||
431 | if ($this->db->Type == 'mysql' && !preg_match('/[\x80-\xFF]/', $param['query'])) |
||||
432 | { |
||||
433 | $search_cols[] = Api\Mail\Smtp\Sql::TABLE.'.mail_value'; |
||||
434 | } |
||||
435 | $join .= ' LEFT JOIN '.Api\Mail\Smtp\Sql::TABLE.' ON '.$this->table.'.account_id=-'.Api\Mail\Smtp\Sql::TABLE.'.account_id AND mail_type='.Api\Mail\Smtp\Sql::TYPE_ALIAS; |
||||
436 | } |
||||
437 | |||||
438 | $filter = array(); |
||||
439 | switch($param['type']) |
||||
440 | { |
||||
441 | case 'accounts': |
||||
442 | $filter['owner'] = 0; |
||||
443 | break; |
||||
444 | case 'groups': |
||||
445 | $filter[] = "account_type='g'"; |
||||
446 | break; |
||||
447 | case 'owngroups': |
||||
448 | $filter['account_id'] = array_map('abs', $this->frontend->memberships($GLOBALS['egw_info']['user']['account_id'], true)); |
||||
449 | $filter[] = "account_type='g'"; |
||||
450 | break; |
||||
451 | case 'groupmembers': |
||||
452 | case 'groupmembers+memberships': |
||||
453 | $members = array(); |
||||
454 | foreach((array)$this->memberships($GLOBALS['egw_info']['user']['account_id'], true) as $grp => $name) |
||||
0 ignored issues
–
show
The call to
EGroupware\Api\Accounts\Sql::memberships() has too many arguments starting with true .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
455 | { |
||||
456 | unset($name); |
||||
457 | $members = array_unique(array_merge($members, array_keys((array)$this->members($grp)))); |
||||
458 | if ($param['type'] == 'groupmembers+memberships') $members[] = abs($grp); |
||||
459 | } |
||||
460 | $filter['account_id'] = $members; |
||||
461 | break; |
||||
462 | default: |
||||
463 | if (is_numeric($param['type'])) |
||||
464 | { |
||||
465 | $filter['account_id'] = $this->frontend->members($param['type'], true, $param['active']); |
||||
466 | $filter['owner'] = 0; |
||||
467 | break; |
||||
468 | } |
||||
469 | // fall-through |
||||
470 | case 'both': |
||||
471 | $filter[] = "(egw_addressbook.contact_owner=0 OR egw_addressbook.contact_owner IS NULL)"; |
||||
472 | break; |
||||
473 | } |
||||
474 | // fix ambigous account_id (used in accounts and contacts table) |
||||
475 | if (array_key_exists('account_id', $filter)) |
||||
476 | { |
||||
477 | if (!$filter['account_id']) // eg. group without members (would give SQL error) |
||||
478 | { |
||||
479 | $this->total = 0; |
||||
480 | return array(); |
||||
481 | } |
||||
482 | $filter[] = $this->db->expression($this->table, $this->table.'.', array( |
||||
483 | 'account_id' => $filter['account_id'], |
||||
484 | )); |
||||
485 | unset($filter['account_id']); |
||||
486 | } |
||||
487 | if ($param['active']) |
||||
488 | { |
||||
489 | $filter[] = str_replace('UNIX_TIMESTAMP(NOW())',time(),Api\Contacts\Sql::ACOUNT_ACTIVE_FILTER); |
||||
490 | } |
||||
491 | $criteria = array(); |
||||
492 | $wildcard = $param['query_type'] == 'start' || $param['query_type'] == 'exact' ? '' : '%'; |
||||
493 | if (($query = $param['query'])) |
||||
494 | { |
||||
495 | switch($param['query_type']) |
||||
496 | { |
||||
497 | case 'start': |
||||
498 | $query .= '*'; |
||||
499 | // fall-through |
||||
500 | case 'all': |
||||
501 | default: |
||||
502 | case 'exact': |
||||
503 | foreach($search_cols as $col) |
||||
504 | { |
||||
505 | $criteria[$col] = $query; |
||||
506 | } |
||||
507 | break; |
||||
508 | case 'account_firstname': |
||||
509 | case 'firstname': |
||||
510 | $criteria['n_given'] = $query; |
||||
511 | break; |
||||
512 | case 'account_lastname': |
||||
513 | case 'lastname': |
||||
514 | $criteria['n_family'] = $query; |
||||
515 | break; |
||||
516 | case 'account_lid': |
||||
517 | case 'lid': |
||||
518 | $criteria['account_lid'] = $query; |
||||
519 | break; |
||||
520 | case 'account_email': |
||||
521 | case 'email': |
||||
522 | $criteria['email'] = $query; |
||||
523 | // Group email |
||||
524 | if(in_array(Api\Mail\Smtp\Sql::TABLE, $this->db->table_names(true))) |
||||
525 | { |
||||
526 | $criteria[Api\Mail\Smtp\Sql::TABLE.'.mail_value'] = $query; |
||||
527 | } |
||||
528 | break; |
||||
529 | } |
||||
530 | } |
||||
531 | if (!isset($this->contacts)) $this->contacts = new Api\Contacts(); |
||||
532 | |||||
533 | $accounts = array(); |
||||
534 | foreach((array) $this->contacts->search($criteria, |
||||
535 | array_merge(array(1,'n_given','n_family','id','created','modified',$this->table.'.account_id AS account_id'),$email_cols), |
||||
536 | $order, "account_lid,account_type,account_status,account_expires,account_primary_group,account_description". |
||||
537 | ",account_lastlogin,account_lastloginfrom,account_lastpwd_change", |
||||
538 | $wildcard,false,$query[0] == '!' ? 'AND' : 'OR', |
||||
539 | $param['offset'] ? array($param['start'], $param['offset']) : (is_null($param['start']) ? false : $param['start']), |
||||
540 | $filter,$join) as $contact) |
||||
541 | { |
||||
542 | if ($contact) |
||||
543 | { |
||||
544 | $account_id = ($contact['account_type'] == 'g' ? -1 : 1) * $contact['account_id']; |
||||
545 | $accounts[$account_id] = array( |
||||
546 | 'account_id' => $account_id, |
||||
547 | 'account_lid' => $contact['account_lid'], |
||||
548 | 'account_type' => $contact['account_type'], |
||||
549 | 'account_firstname' => $contact['n_given'], |
||||
550 | 'account_lastname' => $contact['n_family'], |
||||
551 | 'account_email' => $contact['email'], |
||||
552 | 'person_id' => $contact['id'], |
||||
553 | 'account_status' => $contact['account_status'], |
||||
554 | 'account_expires' => $contact['account_expires'], |
||||
555 | 'account_primary_group' => $contact['account_primary_group'], |
||||
556 | // Api\Contacts::search() returns everything in user-time, need to convert to server-time |
||||
557 | 'account_created' => Api\DateTime::user2server($contact['created']), |
||||
558 | 'account_modified' => Api\DateTime::user2server($contact['modified']), |
||||
559 | 'account_lastlogin' => $contact['account_lastlogin'] ? |
||||
560 | Api\DateTime::user2server($contact['account_lastlogin']) : null, |
||||
561 | 'account_lastloginfrom' => $contact['account_lastloginfrom'], |
||||
562 | 'account_lastpwd_change' => $contact['account_lastpwd_change'] ? |
||||
563 | Api\DateTime::user2server($contact['account_lastpwd_change']) : null, |
||||
564 | 'account_description' => $contact['account_description'], |
||||
565 | ); |
||||
566 | } |
||||
567 | } |
||||
568 | $this->total = $this->contacts->total; |
||||
0 ignored issues
–
show
It seems like
$this->contacts->total can also be of type boolean . However, the property $total is declared as type integer . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||||
569 | //error_log(__METHOD__."(".array2string($param).") returning ".count($accounts).'/'.$this->total); |
||||
570 | return $accounts; |
||||
571 | } |
||||
572 | |||||
573 | /** |
||||
574 | * convert an alphanumeric account-value (account_lid, account_email, account_fullname) to the account_id |
||||
575 | * |
||||
576 | * Please note: |
||||
577 | * - if a group and an user have the same account_lid the group will be returned (LDAP only) |
||||
578 | * - if multiple user have the same email address, the returned user is undefined |
||||
579 | * |
||||
580 | * @param string $name value to convert |
||||
581 | * @param string $which ='account_lid' type of $name: account_lid (default), account_email, person_id, account_fullname |
||||
582 | * @param string $account_type u = user, g = group, default null = try both |
||||
583 | * @return int/false numeric account_id or false on error ($name not found) |
||||
0 ignored issues
–
show
|
|||||
584 | */ |
||||
585 | function name2id($name,$which='account_lid',$account_type=null) |
||||
586 | { |
||||
587 | if ($account_type === 'g' && $which != 'account_lid') return false; |
||||
588 | |||||
589 | $where = array(); |
||||
590 | $cols = 'account_id'; |
||||
591 | switch($which) |
||||
592 | { |
||||
593 | case 'account_fullname': |
||||
594 | $table = $this->contacts_table; |
||||
595 | $where['n_fn'] = $name; |
||||
596 | break; |
||||
597 | case 'account_email': |
||||
598 | $table = $this->contacts_table; |
||||
599 | $where['contact_email'] = $name; |
||||
600 | break; |
||||
601 | case 'person_id': |
||||
602 | $table = $this->contacts_table; |
||||
603 | $where['contact_id'] = $name; |
||||
604 | break; |
||||
605 | default: |
||||
606 | $table = $this->table; |
||||
607 | $cols .= ',account_type'; |
||||
608 | $where[$which] = $name; |
||||
609 | // check if we need to treat username case-insensitive |
||||
610 | if ($which == 'account_lid' && !$GLOBALS['egw_info']['server']['case_sensitive_username']) // = is case sensitiv eg. on postgres, but not on mysql! |
||||
611 | { |
||||
612 | $where[] = 'account_lid '.$this->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($where['account_lid']); |
||||
613 | unset($where['account_lid']); |
||||
614 | } |
||||
615 | } |
||||
616 | if ($account_type) |
||||
617 | { |
||||
618 | $where['account_type'] = $account_type; |
||||
619 | } |
||||
620 | else |
||||
621 | { |
||||
622 | $where[] = 'account_id IS NOT NULL'. // otherwise contacts with eg. the same email hide the accounts! |
||||
623 | ($table == $this->contacts_table ? " AND contact_tid != 'D'" : ''); // ignore deleted accounts contact-data |
||||
624 | |||||
625 | } |
||||
626 | if (!($rs = $this->db->select($table,$cols,$where,__LINE__,__FILE__)) || !($row = $rs->fetch())) |
||||
627 | { |
||||
628 | //error_log(__METHOD__."('$name', '$which', ".array2string($account_type).") db->select('$table', '$cols', ".array2string($where).") returned ".array2string($rs).' '.function_backtrace()); |
||||
629 | return false; |
||||
630 | } |
||||
631 | return ($row['account_type'] == 'g' ? -1 : 1) * $row['account_id']; |
||||
632 | } |
||||
633 | |||||
634 | /** |
||||
635 | * Convert an numeric account_id to any other value of that account (account_lid, account_email, ...) |
||||
636 | * |
||||
637 | * Uses the read method to fetch all data. |
||||
638 | * |
||||
639 | * @param int $account_id numerica account_id |
||||
640 | * @param string $which ='account_lid' type to convert to: account_lid (default), account_email, ... |
||||
641 | * @return string/false converted value or false on error ($account_id not found) |
||||
0 ignored issues
–
show
|
|||||
642 | */ |
||||
643 | function id2name($account_id,$which='account_lid') |
||||
644 | { |
||||
645 | return $this->frontend->id2name($account_id,$which); |
||||
646 | } |
||||
647 | |||||
648 | /** |
||||
649 | * Update the last login timestamps and the IP |
||||
650 | * |
||||
651 | * @param int $account_id |
||||
652 | * @param string $ip |
||||
653 | * @return int lastlogin time |
||||
654 | */ |
||||
655 | function update_lastlogin($account_id, $ip) |
||||
656 | { |
||||
657 | $previous_login = $this->db->select($this->table,'account_lastlogin',array('account_id'=>abs($account_id)),__LINE__,__FILE__)->fetchColumn(); |
||||
658 | |||||
659 | $this->db->update($this->table,array( |
||||
660 | 'account_lastloginfrom' => $ip, |
||||
661 | 'account_lastlogin' => time(), |
||||
662 | ),array( |
||||
663 | 'account_id' => abs($account_id), |
||||
664 | ),__LINE__,__FILE__); |
||||
665 | |||||
666 | return $previous_login; |
||||
667 | } |
||||
668 | } |
||||
669 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths