1: <?php
2: /**
3: * XOOPS Kernel Class
4: *
5: * You may not change or alter any portion of this comment or credits
6: * of supporting developers from this source code or any supporting source code
7: * which is considered copyrighted (c) material of the original comment or credit authors.
8: * This program is distributed in the hope that it will be useful,
9: * but WITHOUT ANY WARRANTY; without even the implied warranty of
10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11: *
12: * @copyright XOOPS Project (http://xoops.org)
13: * @license GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
14: * @package kernel
15: * @since 2.0.0
16: * @author Kazumi Ono (AKA onokazu) http://www.myweb.ne.jp/, http://jp.xoops.org/
17: * @version $Id$
18: */
19:
20: namespace Xoops\Core\Kernel\Handlers;
21:
22: use Xoops\Core\Database\Connection;
23: use Xoops\Core\Kernel\Criteria;
24: use Xoops\Core\Kernel\CriteriaCompo;
25: use Xoops\Core\Kernel\CriteriaElement;
26:
27: /**
28: * XOOPS member handler class.
29: * This class provides simple interface (a facade class) for handling groups/users/
30: * membership data.
31: *
32: * @category Xoops\Core\Kernel\Handlers\XoopsMemberHandler
33: * @package Xoops\Core\Kernel
34: * @author Kazumi Ono <onokazu@xoops.org>
35: * @copyright 2000-2015 XOOPS Project (http://xoops.org)
36: * @license GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
37: * @link http://xoops.org
38: */
39: class XoopsMemberHandler
40: {
41:
42: /**
43: * @var XoopsGroupPermHandler group handler(DAO) class
44: */
45: private $groupHandler;
46:
47: /**
48: * @var XoopsUserHandler user handler(DAO) class
49: */
50: private $userHandler;
51:
52: /**
53: * @var XoopsMembershipHandler membership handler(DAO) class
54: */
55: private $membershipHandler;
56:
57: /**
58: * holds temporary user objects
59: */
60: private $membersWorkingList = array();
61:
62: /**
63: * Constructor
64: *
65: * @param Connection|null $db database connection
66: */
67: public function __construct(Connection $db = null)
68: {
69: $this->groupHandler = \Xoops::getInstance()->getHandlerGroup();
70: $this->userHandler = \Xoops::getInstance()->getHandlerUser();
71: $this->membershipHandler = \Xoops::getInstance()->getHandlerMembership();
72: }
73:
74: /**
75: * create a new group
76: *
77: * @return XoopsGroup reference to the new group
78: */
79: public function createGroup()
80: {
81: $inst = $this->groupHandler->create();
82: return $inst;
83: }
84:
85: /**
86: * create a new user
87: *
88: * @return XoopsUser reference to the new user
89: */
90: public function createUser()
91: {
92: $inst = $this->userHandler->create();
93: return $inst;
94: }
95:
96: /**
97: * retrieve a group
98: *
99: * @param int $id ID for the group
100: *
101: * @return XoopsGroup reference to the group
102: */
103: public function getGroup($id)
104: {
105: return $this->groupHandler->get($id);
106: }
107:
108: /**
109: * retrieve a user
110: *
111: * @param int $id ID for the user
112: *
113: * @return XoopsUser
114: */
115: public function getUser($id)
116: {
117: if (!isset($this->membersWorkingList[$id])) {
118: $this->membersWorkingList[$id] = $this->userHandler->get($id);
119: }
120: return $this->membersWorkingList[$id];
121: }
122:
123: /**
124: * delete a group
125: *
126: * @param XoopsGroup $group the group to delete
127: *
128: * @return bool FALSE if failed
129: */
130: public function deleteGroup(XoopsGroup $group)
131: {
132: $this->groupHandler->delete($group);
133: $this->membershipHandler->deleteAll(new Criteria('groupid', $group->getVar('groupid')));
134: return true;
135: }
136:
137: /**
138: * delete a user
139: *
140: * @param XoopsUser $user reference to the user to delete
141: *
142: * @return bool FALSE if failed
143: */
144: public function deleteUser(XoopsUser $user)
145: {
146: $this->userHandler->delete($user);
147: $this->membershipHandler->deleteAll(new Criteria('uid', $user->getVar('uid')));
148: return true;
149: }
150:
151: /**
152: * insert a group into the database
153: *
154: * @param XoopsGroup $group the group to insert
155: *
156: * @return bool TRUE if already in database and unchanged, FALSE on failure
157: */
158: public function insertGroup(XoopsGroup $group)
159: {
160: return $this->groupHandler->insert($group);
161: }
162:
163: /**
164: * insert a user into the database
165: *
166: * @param XoopsUser $user the user to insert
167: * @param bool $force force insert
168: *
169: * @return bool TRUE if already in database and unchanged, FALSE on failure
170: */
171: public function insertUser(XoopsUser $user, $force = false)
172: {
173: return $this->userHandler->insert($user, $force);
174: }
175:
176: /**
177: * retrieve groups from the database
178: *
179: * @param CriteriaElement|null $criteria criteria to match
180: * @param bool $id_as_key use the group's ID as key for the array?
181: *
182: * @return XoopsGroup[]
183: */
184: public function getGroups(CriteriaElement $criteria = null, $id_as_key = false)
185: {
186: return $this->groupHandler->getObjects($criteria, $id_as_key);
187: }
188:
189: /**
190: * retrieve users from the database
191: *
192: * @param CriteriaElement|null $criteria criteria to match
193: * @param bool $id_as_key use the group's ID as key for the array?
194: *
195: * @return XoopsUser[]
196: */
197: public function getUsers(CriteriaElement $criteria = null, $id_as_key = false)
198: {
199: return $this->userHandler->getObjects($criteria, $id_as_key);
200: }
201:
202: /**
203: * get a list of groupnames and their IDs
204: *
205: * @param CriteriaElement|null $criteria criteria to match
206: *
207: * @return array associative array of group-IDs and names
208: */
209: public function getGroupList(CriteriaElement $criteria = null)
210: {
211: $groups = $this->groupHandler->getObjects($criteria, true);
212: $ret = array();
213: foreach (array_keys($groups) as $i) {
214: $ret[$i] = $groups[$i]->getVar('name');
215: }
216: return $ret;
217: }
218:
219: /**
220: * get a list of usernames and their IDs
221: *
222: * @param CriteriaElement|null $criteria criteria to match
223: *
224: * @return array associative array of user-IDs and names
225: */
226: public function getUserList(CriteriaElement $criteria = null)
227: {
228: $users = $this->userHandler->getObjects($criteria, true);
229: $ret = array();
230: foreach (array_keys($users) as $i) {
231: $ret[$i] = $users[$i]->getVar('uname');
232: }
233: return $ret;
234: }
235:
236: /**
237: * add a user to a group
238: *
239: * @param int $group_id ID of the group
240: * @param int $user_id ID of the user
241: *
242: * @return XoopsMembership
243: */
244: public function addUserToGroup($group_id, $user_id)
245: {
246: $mship = $this->membershipHandler->create();
247: $mship->setVar('groupid', $group_id);
248: $mship->setVar('uid', $user_id);
249: return $this->membershipHandler->insert($mship);
250: }
251:
252: /**
253: * remove a list of users from a group
254: *
255: * @param int $group_id ID of the group
256: * @param array $user_ids array of user-IDs
257: *
258: * @return bool success?
259: */
260: public function removeUsersFromGroup($group_id, $user_ids = array())
261: {
262: $criteria = new CriteriaCompo();
263: $criteria->add(new Criteria('groupid', $group_id));
264: $criteria2 = new CriteriaCompo();
265: foreach ($user_ids as $uid) {
266: $criteria2->add(new Criteria('uid', $uid), 'OR');
267: }
268: $criteria->add($criteria2);
269: return $this->membershipHandler->deleteAll($criteria);
270: }
271:
272: /**
273: * get a list of users belonging to a group
274: *
275: * @param int $group_id ID of the group
276: * @param bool $asobject return the users as objects?
277: * @param int $limit number of users to return
278: * @param int $start index of the first user to return
279: *
280: * @return array Array of XoopsUser objects (if $asobject is TRUE)
281: * or of associative arrays matching the record structure
282: */
283: public function getUsersByGroup($group_id, $asobject = false, $limit = 0, $start = 0)
284: {
285: $user_ids = $this->membershipHandler->getUsersByGroup($group_id, $limit, $start);
286: if (!$asobject) {
287: return $user_ids;
288: } else {
289: $ret = array();
290: foreach ($user_ids as $u_id) {
291: $user = $this->getUser($u_id);
292: if (is_object($user)) {
293: $ret[] = $user;
294: }
295: unset($user);
296: }
297: return $ret;
298: }
299: }
300:
301: /**
302: * get a list of groups that a user is member of
303: *
304: * @param int $user_id ID of the user
305: * @param bool $asobject return groups as XoopsGroup objects or arrays?
306: *
307: * @return array array of objects or arrays
308: */
309: public function getGroupsByUser($user_id, $asobject = false)
310: {
311: $ret = array();
312: $group_ids = $this->membershipHandler->getGroupsByUser($user_id);
313: if (!$asobject) {
314: return $group_ids;
315: } else {
316: foreach ($group_ids as $g_id) {
317: $ret[] = $this->getGroup($g_id);
318: }
319: return $ret;
320: }
321: }
322:
323: /**
324: * log in a user
325: *
326: * @param string $uname username as entered in the login form
327: * @param string $pwd password entered in the login form
328: *
329: * @return mixed object XoopsUser reference to the logged in user
330: * boolean FALSE if failed to log in
331: *
332: * @todo - md5 support should be completely removed eventually
333: */
334: public function loginUser($uname, $pwd)
335: {
336: $criteria = new Criteria('uname', $uname);
337: //$criteria->add(new Criteria('pass', md5($pwd)));
338: $user = $this->userHandler->getObjects($criteria, false);
339: if (!$user || count($user) != 1) {
340: return false;
341: }
342:
343: $hash = $user[0]->pass();
344: $type = substr($user[0]->pass(), 0, 1);
345: // see if we have a crypt like signature, old md5 hash is just hex digits
346: if ($type==='$') {
347: if (!password_verify($pwd, $hash)) {
348: return false;
349: }
350: // check if hash uses the best algorithm (i.e. after a PHP upgrade)
351: $rehash = password_needs_rehash($hash, PASSWORD_DEFAULT);
352: } else {
353: if ($hash!=md5($pwd)) {
354: return false;
355: }
356: $rehash = true; // automatically update old style
357: }
358: // hash used an old algorithm, so make it stronger
359: if ($rehash) {
360: $user[0]->setVar('pass', password_hash($pwd, PASSWORD_DEFAULT));
361: $this->userHandler->insert($user[0]);
362: }
363: return $user[0];
364: }
365:
366: /**
367: * count users matching certain conditions
368: *
369: * @param CriteriaElement|null $criteria criteria to match
370: *
371: * @return int
372: */
373: public function getUserCount(CriteriaElement $criteria = null)
374: {
375: return $this->userHandler->getCount($criteria);
376: }
377:
378: /**
379: * count users belonging to a group
380: *
381: * @param int $group_id ID of the group
382: *
383: * @return int
384: */
385: public function getUserCountByGroup($group_id)
386: {
387: return $this->membershipHandler->getCount(new Criteria('groupid', $group_id));
388: }
389:
390: /**
391: * updates a single field in a users record
392: *
393: * @param XoopsUser $user user object to update
394: * @param string $fieldName name of the field to update
395: * @param string $fieldValue updated value for the field
396: *
397: * @return bool TRUE if success or unchanged, FALSE on failure
398: */
399: public function updateUserByField(XoopsUser $user, $fieldName, $fieldValue)
400: {
401: $user->setVar($fieldName, $fieldValue);
402: return $this->insertUser($user);
403: }
404:
405: /**
406: * updates a single field in a users record
407: *
408: * @param string $fieldName name of the field to update
409: * @param string $fieldValue updated value for the field
410: * @param CriteriaElement $criteria criteria to match
411: *
412: * @return bool TRUE if success or unchanged, FALSE on failure
413: */
414: public function updateUsersByField($fieldName, $fieldValue, CriteriaElement $criteria = null)
415: {
416: if (is_null($criteria)) {
417: $criteria = new Criteria(''); // empty criteria resolves to 'WHERE (1)'
418: }
419: return $this->userHandler->updateAll($fieldName, $fieldValue, $criteria);
420: }
421:
422: /**
423: * activate a user
424: *
425: * @param XoopsUser $user the user object
426: *
427: * @return bool successful?
428: */
429: public function activateUser(XoopsUser $user)
430: {
431: if ($user->getVar('level') != 0) {
432: return true;
433: }
434: $user->setVar('level', 1);
435: return $this->userHandler->insert($user, true);
436: }
437:
438: /**
439: * Get a list of users belonging to certain groups and matching criteria
440: * Temporary solution
441: *
442: * @param array $groups IDs of groups
443: * @param CriteriaElement $criteria criteria to match
444: * @param bool $asobject return the users as objects?
445: * @param bool $id_as_key use the UID as key for the array if $asobject is TRUE
446: *
447: * @return array Array of XoopsUser objects (if $asobject is TRUE)
448: * or of associative arrays matching the record structure in the database.
449: */
450: public function getUsersByGroupLink(
451: $groups,
452: CriteriaElement $criteria = null,
453: $asobject = false,
454: $id_as_key = false
455: ) {
456:
457: $qb = $this->userHandler->db2->createXoopsQueryBuilder();
458: $eb = $qb->expr();
459:
460: $qb ->select('DISTINCT ' . ($asobject ? 'u.*' : 'u.uid'))
461: ->fromPrefix('system_user', 'u')
462: ->leftJoinPrefix('u', 'system_usergroup', 'm', 'm.uid = u.uid');
463:
464: $where = false;
465: if (!empty($groups)) {
466: $qb->where($eb->in('m.groupid', $groups));
467: $where = true;
468: }
469: if (isset($criteria) && ($criteria instanceof CriteriaElement)) {
470: $whereMode = $where ? 'AND' : '';
471: $sql[] = $criteria->renderQb($qb, $whereMode);
472: }
473:
474: $ret = array();
475:
476: if (!$result = $qb->execute()) {
477: return $ret;
478: }
479:
480: while ($myrow = $result->fetch(\PDO::FETCH_ASSOC)) {
481: if ($asobject) {
482: $user = new XoopsUser();
483: $user->assignVars($myrow);
484: if (!$id_as_key) {
485: $ret[] = $user;
486: } else {
487: $ret[$myrow['uid']] = $user;
488: }
489: unset($user);
490: } else {
491: $ret[] = $myrow['uid'];
492: }
493: }
494: return $ret;
495: }
496:
497: /**
498: * Get count of users belonging to certain groups and matching criteria
499: * Temporary solution
500: *
501: * @param array $groups IDs of groups
502: * @param CriteriaElement|null $criteria criteria to match
503: *
504: * @return int count of users
505: */
506: public function getUserCountByGroupLink($groups, $criteria = null)
507: {
508: $qb = $this->userHandler->db2->createXoopsQueryBuilder();
509: $eb = $qb->expr();
510:
511: $qb ->select('COUNT(DISTINCT u.uid)')
512: ->fromPrefix('system_user', 'u')
513: ->leftJoinPrefix('u', 'system_usergroup', 'm', 'm.uid = u.uid');
514:
515: $where = false;
516: if (!empty($groups)) {
517: $qb->where($eb->in('m.groupid', $groups));
518: $where = true;
519: }
520: if (isset($criteria) && ($criteria instanceof CriteriaElement)) {
521: $whereMode = $where ? 'AND' : '';
522: $criteria->renderQb($qb, $whereMode);
523: }
524:
525: $result = $qb->execute();
526: $ret = $result->fetchColumn(0);
527:
528: return $ret;
529: }
530: }
531: