1: <?php
2:
3: /**
4: * This file contains the system property collection and item class.
5: *
6: * @package Core
7: * @subpackage GenericDB_Model
8: * @author Bjoern Behrens
9: * @author Holger Librenz
10: * @copyright four for business AG <www.4fb.de>
11: * @license http://www.contenido.org/license/LIZENZ.txt
12: * @link http://www.4fb.de
13: * @link http://www.contenido.org
14: */
15:
16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
17:
18: /**
19: * User collection
20: *
21: * @package Core
22: * @subpackage GenericDB_Model
23: */
24: class cApiUserCollection extends ItemCollection {
25: /**
26: * Constructor to create an instance of this class.
27: *
28: * @param string|bool $where [optional]
29: * The where clause in the select, usable to run select by creating
30: * the instance
31: *
32: * @throws cDbException
33: * @throws cInvalidArgumentException
34: * @global array $cfg
35: */
36: public function __construct($where = false) {
37: global $cfg;
38: parent::__construct($cfg['tab']['user'], 'user_id');
39: $this->_setItemClass('cApiUser');
40: if ($where !== false) {
41: $this->select($where);
42: }
43: }
44:
45: /**
46: * Createa a user by user name.
47: *
48: * @param string $username
49: *
50: * @return cApiUser|bool
51: * @throws cDbException
52: * @throws cException
53: * @throws cInvalidArgumentException
54: */
55: public function create($username) {
56: $primaryKeyValue = md5($username);
57:
58: $item = $this->createNewItem($primaryKeyValue);
59: if ($item->usernameExists($username)) {
60: return false;
61: }
62:
63: $item->set('username', $username);
64: $item->set('salt', md5($username . rand(1000, 9999) . rand(1000, 9999) . rand(1000, 9999)));
65: $item->store();
66:
67: return $item;
68: }
69:
70: /**
71: * Removes the specified user from the database by users name.
72: *
73: * @param string $username
74: * Specifies the username
75: *
76: * @return bool
77: * True if the delete was successful
78: *
79: * @throws cDbException
80: * @throws cInvalidArgumentException
81: */
82: public function deleteUserByUsername($username) {
83: $result = $this->deleteBy('username', $username);
84: return ($result > 0) ? true : false;
85: }
86:
87: /**
88: * Returns all users which are accessible by the current user.
89: *
90: * @param array $perms
91: * Permissions array
92: * @param bool $includeAdmins [optional]
93: * Flag to get admins (admin and sysadmin) too
94: * @param string $orderBy [optional]
95: * Order by rule, uses 'realname, username' by default
96: * @return array
97: * Array of user objects
98: * @throws cDbException
99: * @throws cException
100: */
101: public function fetchAccessibleUsers($perms, $includeAdmins = false, $orderBy = '') {
102: $users = array();
103: $limit = array();
104: $where = '';
105:
106: if (!in_array('sysadmin', $perms)) {
107: // not sysadmin, compose where rules
108: $clientColl = new cApiClientCollection();
109: $allClients = $clientColl->getAvailableClients();
110:
111: foreach ($allClients as $key => $value) {
112: if (in_array('client[' . $key . ']', $perms) || in_array('admin[' . $key . ']', $perms)) {
113: $limit[] = 'perms LIKE "%client[' . $this->escape($key) . ']%"';
114: if ($includeAdmins) {
115: $limit[] = 'perms LIKE "%admin[' . $this->escape($key) . ']%"';
116: }
117: }
118: if (in_array('admin[' . $key . ']', $perms)) {
119: $limit[] = 'perms LIKE "%admin[' . $key . ']%"';
120: }
121: }
122:
123: if ($includeAdmins) {
124: $limit[] = 'perms LIKE "%sysadmin%"';
125: }
126:
127: if (count($limit) > 0) {
128: $where = '1 AND ' . implode(' OR ', $limit);
129: }
130: }
131:
132: if (empty($orderBy)) {
133: $orderBy = 'realname, username';
134: }
135:
136: $this->select($where, '', $this->escape($orderBy));
137: while (($oItem = $this->next()) !== false) {
138: $users[] = clone $oItem;
139: }
140:
141: return $users;
142: }
143:
144: /**
145: * Returns all users which are accessible by the current user.
146: * Is a wrapper of fetchAccessibleUsers() and returns contrary to that
147: * function
148: * a multidimensional array instead of a list of objects.
149: *
150: * @param array $perms
151: * Permissions array
152: * @param bool $includeAdmins [optional]
153: * Flag to get admins (admin and sysadmin) too
154: * @param string $orderBy [optional]
155: * Order by rule, uses 'realname, username' by default
156: *
157: * @return array
158: * Array of user like $arr[user_id][username], $arr[user_id][realname]
159: * @throws cDbException
160: * @throws cException
161: */
162: public function getAccessibleUsers($perms, $includeAdmins = false, $orderBy = '') {
163: $users = array();
164: $oUsers = $this->fetchAccessibleUsers($perms, $includeAdmins, $orderBy);
165: foreach ($oUsers as $oItem) {
166: $users[$oItem->get('user_id')] = array(
167: 'username' => $oItem->get('username'),
168: 'realname' => $oItem->get('realname')
169: );
170: }
171: return $users;
172: }
173:
174: /**
175: * Returns all users available in the system
176: *
177: * @param string $orderBy [optional]
178: * SQL order by part
179: * @return array
180: * @throws cDbException
181: * @throws cException
182: */
183: public function fetchAvailableUsers($orderBy = 'realname ASC') {
184: $users = array();
185:
186: $this->select('', '', $this->escape($orderBy));
187: while (($oItem = $this->next()) !== false) {
188: $users[] = clone $oItem;
189: }
190:
191: return $users;
192: }
193:
194: /**
195: * Returns all system admins available in the system
196: *
197: * @param bool $forceActive [optional]
198: * flag if only active sysadmins should be returned
199: * @return array
200: * Array of user objects
201: * @throws cDbException
202: * @throws cException
203: */
204: public function fetchSystemAdmins($forceActive = false) {
205: $users = array();
206:
207: $where = 'perms LIKE "%sysadmin%"';
208: if ($forceActive === true) {
209: $where .= " AND (valid_from <= NOW() OR valid_from = '0000-00-00 00:00:00')" . " AND (valid_to >= NOW() OR valid_to = '0000-00-00 00:00:00')";
210: }
211:
212: $this->select($where);
213: while (($item = $this->next()) !== false) {
214: $users[] = clone $item;
215: }
216:
217: return $users;
218: }
219:
220: /**
221: * Returns all system admins available in the system
222: *
223: * @param int $client
224: * @return array
225: * Array of user objects
226: * @throws cDbException
227: * @throws cException
228: */
229: public function fetchClientAdmins($client) {
230: $client = (int) $client;
231: $users = array();
232:
233: $where = 'perms LIKE "%admin[' . $client . ']%"';
234:
235: $this->select($where);
236: while (($item = $this->next()) !== false) {
237: $users[] = clone $item;
238: }
239:
240: return $users;
241: }
242: }
243:
244: /**
245: * User item
246: *
247: * In current version you can administer optional password checks
248: * via following configuration values:
249: *
250: * - En- or disabling checks:
251: * $cfg['password']['check_password_mask'] = [true|false]
252: * Use this flag to enable (true) or disable (false) the mask checks.
253: *
254: * $cfg['password']['use_cracklib'] = [true|false]
255: * Use this to enable (true) or disable (false) the strength check, currently
256: * done with cracklib.
257: *
258: * - Mask checks:
259: * Password mask checks are checks belonging to the "format" of the needed
260: * password string.
261: *
262: * $cfg['password']['min_length'], int
263: * Minimum length a password has to have. If not set, 8 chars are set as default
264: * $cfg['password']['numbers_mandatory'], int
265: * If set to a value greater than 0, at least
266: * $cfg['password']['numbers_mandatory'] numbers
267: * must be in password
268: * $cfg['password']['symbols_mandatory'], int &&
269: * $cfg['password']['symbols_regex'], String
270: * If 'symbols_mandatory' set to a value greater than 0, at least so many
271: * symbols has to appear in
272: * given password. What symbols are regcognized can be administrated via
273: * 'symbols_regex'. This has
274: * to be a regular expression which is used to "find" the symbols in $password.
275: * If not set, following
276: * RegEx is used: "/[|!@#$%&*\/=?,;.:\-_+~^ยจ\\\]/"
277: * $cfg['password']['mixed_case_mandatory'], int
278: * If set to a value greater than 0 so many lower and upper case character must
279: * appear in the password.
280: * (e.g.: if set to 2, 2 upper and 2 lower case characters must appear)
281: *
282: * - Strength check
283: * Passwords should have some special characteristics to be a strong, i.e. not
284: * easy to guess, password. Currently
285: * cracklib is supported. These are the configuration possibilities:
286: *
287: * $cfg['password']['cracklib_dict'], string
288: * Path and file name (without file extension!) to dictionary you want to use.
289: * This setting is
290: * mandatory!
291: *
292: * Keep in mind that these type of check only works if crack module is
293: * available.
294: *
295: * @package Core
296: * @subpackage GenericDB_Model
297: */
298: class cApiUser extends Item {
299:
300: /**
301: * Password is ok and stored.
302: *
303: * @var int
304: *
305: */
306: const PASS_OK = 0;
307:
308: /**
309: * Given password is to short
310: *
311: * @var int
312: *
313: */
314: const PASS_TO_SHORT = 1;
315:
316: /**
317: * Given password is not strong enough
318: *
319: * @var int
320: *
321: */
322: const PASS_NOT_STRONG = 2;
323:
324: /**
325: * Given password is not complex enough
326: *
327: * @var int
328: *
329: */
330: const PASS_NOT_COMPLEX = 3;
331:
332: /**
333: * Password does not contain enough numbers.
334: *
335: * @var int
336: *
337: */
338: const PASS_NOT_ENOUGH_NUMBERS = 4;
339:
340: /**
341: * Password does not contain enough symbols.
342: *
343: * @var int
344: */
345: const PASS_NOT_ENOUGH_SYMBOLS = 5;
346:
347: /**
348: * Password does not contain enough mixed characters.
349: *
350: * @var int
351: *
352: */
353: const PASS_NOT_ENOUGH_MIXED_CHARS = 6;
354:
355: /**
356: * Password does not contain enough different characters.
357: *
358: * @var int
359: *
360: */
361: const PASS_NOT_ENOUGH_DIFFERENT_CHARS = 7;
362:
363: /**
364: * Exception code, which is used if you try to add an user
365: * that already exists.
366: *
367: * @var int
368: *
369: */
370: const EXCEPTION_USERNAME_EXISTS = 8;
371:
372: /**
373: * Exception code, which is used if an password is set to save
374: * that is not valid.
375: *
376: * @var int
377: *
378: */
379: const EXCEPTION_PASSWORD_INVALID = 9;
380:
381: /**
382: * This value will be used if no minimum length
383: * for passwords are set via $cfg['password']['min_length']
384: *
385: * @var int
386: *
387: */
388: const MIN_PASS_LENGTH_DEFAULT = 8;
389:
390: /**
391: * Constructor to create an instance of this class.
392: *
393: * @param mixed $mId [optional]
394: * Specifies the ID of item to load
395: *
396: * @throws cDbException
397: * @throws cException
398: */
399: public function __construct($mId = false) {
400: global $cfg;
401: parent::__construct($cfg['tab']['user'], 'user_id');
402: $this->setFilters(array(), array());
403: if ($mId !== false) {
404: $this->loadByPrimaryKey($mId);
405: }
406: }
407:
408: /**
409: * Loads a user from the database by its userID.
410: *
411: * @param string $userId
412: * Specifies the userID
413: * @return bool
414: * True if the load was successful
415: *
416: * @throws cDbException
417: * @throws cException
418: */
419: public function loadUserByUserID($userId) {
420: return $this->loadByPrimaryKey($userId);
421: }
422:
423: /**
424: * Loads a user entry by username.
425: *
426: * @param string $userName
427: * Specifies the username
428: * @return bool
429: * True if the load was successful
430: *
431: * @throws cDbException
432: * @throws cException
433: */
434: public function loadUserByUsername($userName) {
435: return $this->loadBy('username', $userName);
436: }
437:
438: /**
439: * Checks if a user with the id $userId exists
440: *
441: * @param string $userId
442: *
443: * @return bool
444: * user exists or not
445: *
446: * @throws cDbException
447: * @throws cException
448: */
449: public static function userExists($userId) {
450: $test = new cApiUser();
451:
452: return $test->loadByPrimaryKey($userId);
453: }
454:
455: /**
456: * Checks if a username exists
457: *
458: * @param string $username
459: * the name
460: * @return bool
461: * username exists or not
462: *
463: * @throws cDbException
464: * @throws cException
465: */
466: public static function usernameExists($username) {
467: $user = new cApiUser();
468: return $user->loadBy('username', $username);
469: }
470:
471: /**
472: * Checks a given password against some predefined rules like minimum
473: * character
474: * length, required special character, etc...
475: * This behaviour is configurable in global configuration $cfg['password'].
476: *
477: * @param string $password
478: * The password check
479: * @return int
480: * One of defined PASS_* constants (PASS_OK if everything was ok)
481: */
482: public static function checkPasswordMask($password) {
483: global $cfg;
484:
485: $iResult = self::PASS_OK;
486:
487: $cfgPw = $cfg['password'];
488:
489: if (!isset($cfgPw['check_password_mask']) || $cfgPw['check_password_mask'] == false) {
490: // no or disabled password check configuration
491: return $iResult;
492: }
493:
494: // any min length in config set?
495: $iMinLength = self::MIN_PASS_LENGTH_DEFAULT;
496: if (isset($cfgPw['min_length'])) {
497: $iMinLength = (int) $cfgPw['min_length'];
498: }
499:
500: // check length...
501: if (cString::getStringLength($password) < $iMinLength) {
502: $iResult = self::PASS_TO_SHORT;
503: }
504:
505: // check password elements
506: // numbers.....
507: if ($iResult == self::PASS_OK && isset($cfgPw['numbers_mandatory']) && (int) $cfgPw['numbers_mandatory'] > 0) {
508:
509: $aNumbersInPassword = array();
510: preg_match_all('/[0-9]/', $password, $aNumbersInPassword);
511:
512: if (count($aNumbersInPassword[0]) < (int) $cfgPw['numbers_mandatory']) {
513: $iResult = self::PASS_NOT_ENOUGH_NUMBERS;
514: }
515: }
516:
517: // symbols....
518: if ($iResult == self::PASS_OK && isset($cfgPw['symbols_mandatory']) && (int) $cfgPw['symbols_mandatory'] > 0) {
519:
520: $aSymbols = array();
521: $sSymbolsDefault = "/[|!@#$%&*\/=?,;.:\-_+~^ยจ\\\]/";
522: if (isset($cfgPw['symbols_regex']) && !empty($cfgPw['symbols_regex'])) {
523: $sSymbolsDefault = $cfgPw['symbols_regex'];
524: }
525:
526: preg_match_all($sSymbolsDefault, $password, $aSymbols);
527:
528: if (count($aSymbols[0]) < (int) $cfgPw['symbols_mandatory']) {
529: $iResult = self::PASS_NOT_ENOUGH_SYMBOLS;
530: }
531: }
532:
533: // mixed case??
534: if ($iResult == self::PASS_OK && isset($cfgPw['mixed_case_mandatory']) && (int) $cfgPw['mixed_case_mandatory'] > 0) {
535:
536: $aLowerCaseChars = array();
537: $aUpperCaseChars = array();
538:
539: preg_match_all('/[a-z]/', $password, $aLowerCaseChars);
540: preg_match_all('/[A-Z]/', $password, $aUpperCaseChars);
541:
542: if ((count($aLowerCaseChars[0]) < (int) $cfgPw['mixed_case_mandatory']) || (count($aUpperCaseChars[0]) < (int) $cfgPw['mixed_case_mandatory'])) {
543: $iResult = self::PASS_NOT_ENOUGH_MIXED_CHARS;
544: }
545: }
546:
547: return $iResult;
548: }
549:
550: /**
551: * Encodes a passed password (uses md5 to generate a hash of it).
552: *
553: * @param string $password
554: * The password to encode
555: * @return string
556: * Encoded password
557: */
558: public function encodePassword($password) {
559: return hash("sha256", md5($password) . $this->get("salt"));
560: }
561:
562: /**
563: * User defined field value setter.
564: *
565: * @see Item::setField()
566: * @param string $sField
567: * Field name
568: * @param string $mValue
569: * Value to set
570: * @param bool $bSafe [optional]
571: * Flag to run defined inFilter on passed value
572: * @return bool
573: */
574: public function setField($sField, $mValue, $bSafe = true) {
575: if ('perms' === $sField) {
576: if (is_array($mValue)) {
577: $mValue = implode(',', $mValue);
578: }
579: }
580:
581: return parent::setField($sField, $mValue, $bSafe);
582: }
583:
584: /**
585: * Returns user id, currently set.
586: *
587: * @return string
588: */
589: public function getUserId() {
590: return $this->get('user_id');
591: }
592:
593: /**
594: * User id settter.
595: * NOTE: Setting the user id by this method will load the user model.
596: *
597: * @param string $uid
598: *
599: * @throws cDbException
600: * @throws cException
601: */
602: public function setUserId($uid) {
603: $this->loadByPrimaryKey($uid);
604: }
605:
606: /**
607: * Checks password which has to be set and return PASS_* values (i.e.
608: * on success PASS_OK).
609: *
610: * @param string $password
611: * @return int
612: */
613: public function setPassword($password) {
614: $result = self::checkPasswordMask($password);
615: if ($result != self::PASS_OK) {
616: return $result;
617: }
618:
619: $encPass = $this->encodePassword($password);
620:
621: if ($this->get('password') != $encPass) {
622: $this->set('password', $encPass);
623: $this->set('using_pw_request', '0');
624: }
625:
626: return $result;
627: }
628:
629: /**
630: * This method saves the given password $password.
631: *
632: * The password has to be checked, before it is set to the database.
633: *
634: * The resulting integer value represents the result code.
635: *
636: * Use the PASS_* constants to check what happens.
637: *
638: * @param string $password
639: * @return int|bool
640: * PASS_* or false if saving fails
641: * @throws cDbException
642: * @throws cInvalidArgumentException
643: */
644: public function savePassword($password) {
645: if ($this->get('password') == $this->encodePassword($password)) {
646: return self::PASS_OK;
647: }
648:
649: $result = $this->setPassword($password);
650:
651: if ($this->store() === false) {
652: return false;
653: } else {
654: return $result;
655: }
656: }
657:
658: /**
659: * Returns user name, currently set
660: *
661: * @return string
662: */
663: public function getUserName() {
664: return $this->get('username');
665: }
666:
667: /**
668: * Sets up new user name.
669: *
670: * @param string $sUserName
671: */
672: public function setUserName($sUserName) {
673: if ($this->get('username') != $sUserName) {
674: $this->set('username', $sUserName);
675: }
676: }
677:
678: /**
679: * Getter method to get user realname
680: *
681: * @return string
682: * Realname of user
683: */
684: public function getRealName() {
685: return $this->get('realname');
686: }
687:
688: /**
689: * Returns effective user name (if exists realname , otherwise username)
690: *
691: * @return string
692: * Realname or username of user
693: */
694: public function getEffectiveName() {
695: $name = trim($this->get('realname'));
696: if (cString::getStringLength($name) == 0) {
697: $name = trim($this->get('username'));
698: }
699: return $name;
700: }
701:
702: /**
703: * Getter method to get user mail
704: *
705: * @return string
706: */
707: public function getMail() {
708: return $this->get('email');
709: }
710:
711: /**
712: * Getter method to get user tel number
713: *
714: * @return string
715: */
716: public function getTelNumber() {
717: return $this->get('telephone');
718: }
719:
720: /**
721: * Getter method to get user adress data
722: *
723: * @return array
724: * Address data array like:
725: * <pre>
726: * $aAddress['street'], $aAddress['city'], $aAddress['country'],
727: * $aAddress['zip']
728: * </pre>
729: */
730: public function getAddressData() {
731: $aret = array(
732: 'street' => $this->get('address_street'),
733: 'city' => $this->get('address_city'),
734: 'country' => $this->get('address_country'),
735: 'zip' => $this->get('address_zip')
736: );
737:
738: return $aret;
739: }
740:
741: /**
742: * Getter method to get user wysi
743: *
744: * @return int
745: */
746: public function getUseWysi() {
747: return $this->get('wysi');
748: }
749:
750: /**
751: * Getter method to get user valid date from-to
752: *
753: * @return string
754: */
755: public function getValidDateTo() {
756: return $this->get('valid_to');
757: }
758:
759: /**
760: * Getter method to get user valid date from-to
761: *
762: * @return string
763: */
764: public function getValidDateFrom() {
765: return $this->get('valid_from');
766: }
767:
768: /**
769: * Getter method to get user perm name
770: *
771: * @return string
772: */
773: public function getPerms() {
774: return $this->get('perms');
775: }
776:
777: /**
778: * Returns list of user permissions.
779: *
780: * @return array
781: */
782: public function getPermsArray() {
783: return explode(',', $this->get('perms'));
784: }
785:
786: /**
787: * Setter method to set user real name
788: *
789: * @param string $sRealName
790: */
791: public function setRealName($sRealName) {
792: if ($this->get('realname') != $sRealName) {
793: $this->set('realname', $sRealName);
794: }
795: }
796:
797: /**
798: * Setter method to set user mail address
799: *
800: * @param string $sMail
801: */
802: public function setMail($sMail) {
803: if ($this->get('email') != $sMail) {
804: $this->set('email', $sMail);
805: }
806: }
807:
808: /**
809: * Setter method to set user tel number
810: *
811: * @param string $sTelNumber
812: */
813: public function setTelNumber($sTelNumber) {
814: if ($this->get('telephone') != $sTelNumber) {
815: $this->set('telephone', $sTelNumber);
816: }
817: }
818:
819: /**
820: * Setter method to set address data
821: *
822: * @param string $sStreet
823: * @param string $sCity
824: * @param string $sZip
825: * @param string $sCountry
826: */
827: public function setAddressData($sStreet, $sCity, $sZip, $sCountry) {
828: if ($this->get('address_street') != $sStreet) {
829: $this->set('address_street', $sStreet);
830: }
831: if ($this->get('address_city') != $sCity) {
832: $this->set('address_city', $sCity);
833: }
834: if ($this->get('address_zip') != $sZip) {
835: $this->set('address_zip', $sZip);
836: }
837: if ($this->get('address_country') != $sCountry) {
838: $this->set('address_country', $sCountry);
839: }
840: }
841:
842: /**
843: * Sets value for street.
844: *
845: * @param string $sStreet
846: */
847: public function setStreet($sStreet) {
848: if ($this->get('address_street') != $sStreet) {
849: $this->set('address_street', $sStreet);
850: }
851: }
852:
853: /**
854: * Sets value for city.
855: *
856: * @param string $sCity
857: */
858: public function setCity($sCity) {
859: if ($this->get('address_city') != $sCity) {
860: $this->set('address_city', $sCity);
861: }
862: }
863:
864: /**
865: * Sets value for ZIP.
866: *
867: * @param string $sZip
868: */
869: public function setZip($sZip) {
870: if ($this->get('address_zip') != $sZip) {
871: $this->set('address_zip', $sZip);
872: }
873: }
874:
875: /**
876: * Sets value for country.
877: *
878: * @param string $sCountry
879: */
880: public function setCountry($sCountry) {
881: if ($this->get('address_country') != $sCountry) {
882: $this->set('address_country', $sCountry);
883: }
884: }
885:
886: /**
887: * Setter method to set wysi
888: *
889: * @param int $iUseWysi
890: */
891: public function setUseWysi($iUseWysi) {
892: if ($this->get('wysi') != $iUseWysi) {
893: $this->set('wysi', $iUseWysi);
894: }
895: }
896:
897: /**
898: * Setter method to set valid_to
899: *
900: * @todo add type check
901: * @param string $sValidateTo
902: */
903: public function setValidDateTo($sValidateTo) {
904: if ('0000-00-00' == $this->get('valid_to') && 0 == cString::getStringLength(trim($sValidateTo))) {
905: return;
906: }
907: if ($this->get('valid_to') != $sValidateTo) {
908: $this->set('valid_to', $sValidateTo);
909: }
910: }
911:
912: /**
913: * Setter method to set valid_from
914: *
915: * @todo add type checks
916: * @param string $sValidateFrom
917: */
918: public function setValidDateFrom($sValidateFrom) {
919: if ('0000-00-00' == $this->get('valid_from') && 0 == cString::getStringLength(trim($sValidateFrom))) {
920: return;
921: }
922: if ($this->get('valid_from') != $sValidateFrom) {
923: $this->set('valid_from', $sValidateFrom);
924: }
925: }
926:
927: /**
928: * Setter method to set perms
929: *
930: * @param array|string $perms
931: */
932: public function setPerms($perms) {
933: if ($this->get('perms') != $perms) {
934: $this->set('perms', $perms);
935: }
936: }
937:
938: /**
939: * Function returns effective perms for user including group rights as perm
940: * string.
941: *
942: * @author Timo Trautmann
943: * @return string
944: * Current users permissions
945: */
946: public function getEffectiveUserPerms() {
947: global $perm;
948:
949: // first get users own permissions and filter them into result array
950: // $aUserPerms
951: $aUserPerms = array();
952: $aUserPermsSelf = explode(',', $this->values['perms']);
953: foreach ($aUserPermsSelf as $sPerm) {
954: if (trim($sPerm) != '') {
955: $aUserPerms[] = $sPerm;
956: }
957: }
958:
959: // get all corresponding groups for this user
960: $groups = $perm->getGroupsForUser($this->values['user_id']);
961:
962: foreach ($groups as $value) {
963: // get global group permissions
964: $oGroup = new cApiGroup($value);
965: $aGroupPerms = $oGroup->getPermsArray();
966:
967: // add group permissions to $aUserPerms if they were not alredy
968: // defined before
969: foreach ($aGroupPerms as $sPerm) {
970: if (trim($sPerm) != '' && !in_array($sPerm, $aUserPerms)) {
971: $aUserPerms[] = $sPerm;
972: }
973: }
974: }
975: return implode(',', $aUserPerms);
976: }
977:
978: /**
979: * Returns group names where the user is in.
980: *
981: * @param string $userid [optional]
982: * user id, uses id of loaded user by default.
983: * @param bool $bAddDescription [optional]
984: * Flag to add description like "groupname (description)"
985: * @return array
986: * @throws cDbException
987: * @throws cException
988: */
989: public function getGroupNamesByUserID($userid = NULL, $bAddDescription = true) {
990: $userid = (NULL === $userid) ? $this->get('user_id') : $userid;
991:
992: $aGroups = array();
993:
994: $oGroupColl = new cApiGroupCollection();
995: $groups = $oGroupColl->fetchByUserID($userid);
996:
997: foreach ($groups as $group) {
998: $sTemp = $group->get('groupname');
999: $sTemp = cString::getPartOfString($sTemp, 4, cString::getStringLength($sTemp) - 4);
1000:
1001: if (true === $bAddDescription) {
1002: $sDescription = trim($group->get('description'));
1003: if ($sDescription != '') {
1004: $sTemp .= ' (' . $sDescription . ')';
1005: }
1006: }
1007:
1008: $aGroups[] = $sTemp;
1009: }
1010:
1011: return $aGroups;
1012: }
1013:
1014: /**
1015: * Returns group ids where the user is in.
1016: *
1017: * @param string $userid [optional]
1018: * user id, uses id of loaded user by default.
1019: * @return array
1020: * @throws cDbException
1021: * @throws cException
1022: */
1023: public function getGroupIDsByUserID($userid) {
1024: $userid = (NULL === $userid) ? $this->get('user_id') : $userid;
1025:
1026: $aGroups = array();
1027:
1028: $oGroupColl = new cApiGroupCollection();
1029: $groups = $oGroupColl->fetchByUserID($userid);
1030:
1031: foreach ($groups as $group) {
1032: $aGroups[] = $group->get('group_id');
1033: }
1034:
1035: return $aGroups;
1036: }
1037:
1038: /**
1039: * Retrieves the effective user property.
1040: *
1041: * @param string $type
1042: * Type (class, category etc) for the property to retrieve
1043: * @param string $name
1044: * Name of the property to retrieve
1045: * @param bool $group [optional]
1046: * Flag to search in groups
1047: * @return string|bool
1048: * value of the retrieved property or false
1049: *
1050: * @throws cDbException
1051: * @throws cException
1052: */
1053: public function getUserProperty($type, $name, $group = false) {
1054: global $perm;
1055:
1056: if (!is_object($perm)) {
1057: $perm = new cPermission();
1058: }
1059:
1060: $result = false;
1061:
1062: if ($group == true) {
1063: // first get property by existing groups, if desired
1064: $groups = $perm->getGroupsForUser($this->values['user_id']);
1065:
1066: foreach ($groups as $groupid) {
1067: $groupPropColl = new cApiGroupPropertyCollection($groupid);
1068: $groupProp = $groupPropColl->fetchByGroupIdTypeName($type, $name);
1069: if ($groupProp) {
1070: $result = $groupProp->get('value');
1071: }
1072: }
1073: }
1074:
1075: // get property of user
1076: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1077: $userProp = $userPropColl->fetchByUserIdTypeName($type, $name);
1078: if ($userProp) {
1079: $result = $userProp->get('value');
1080: }
1081:
1082: return ($result !== false) ? $result : false;
1083: }
1084:
1085: /**
1086: * Returns all user properties by type.
1087: *
1088: * @todo return value should be similar to getUserProperties()
1089: *
1090: * @param string $type
1091: * Type (class, category etc) of the properties to retrieve
1092: * @param bool $group [optional]
1093: * Flag to retrieve in group properties. If enabled, group
1094: * properties will be merged with user properties where the user
1095: * poperties will overwrite group properties
1096: * @return array
1097: * Assoziative properties array as follows:
1098: * - $arr[name] = value
1099: * @throws cDbException
1100: * @throws cException
1101: */
1102: public function getUserPropertiesByType($type, $group = false) {
1103: global $perm;
1104:
1105: if (!is_object($perm)) {
1106: $perm = new cPermission();
1107: }
1108:
1109: $props = array();
1110:
1111: if ($group == true) {
1112: // first get properties by existing groups, if desired
1113: $groups = $perm->getGroupsForUser($this->values['user_id']);
1114: foreach ($groups as $groupid) {
1115: $groupPropColl = new cApiGroupPropertyCollection($groupid);
1116: $groupProps = $groupPropColl->fetchByGroupIdType($type);
1117: foreach ($groupProps as $groupProp) {
1118: $props[$groupProp->get('name')] = $groupProp->get('value');
1119: }
1120: }
1121: }
1122:
1123: // get properties of user
1124: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1125: $userProps = $userPropColl->fetchByUserIdType($type);
1126: foreach ($userProps as $userProp) {
1127: $props[$userProp->get('name')] = $userProp->get('value');
1128: }
1129:
1130: return $props;
1131: }
1132:
1133: /**
1134: * Retrieves all available properties of the user.
1135: *
1136: * @return array
1137: * Return value in new mode is:
1138: * - $arr[iduserprop][name]
1139: * - $arr[iduserprop][type]
1140: * - $arr[iduserprop][value]
1141: *
1142: * @throws cDbException
1143: * @throws cException
1144: */
1145: public function getUserProperties() {
1146: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1147: $userProps = $userPropColl->fetchByUserId();
1148:
1149: $props = array();
1150:
1151: foreach ($userProps as $userProp) {
1152: $props[$userProp->get('iduserprop')] = array(
1153: 'name' => $userProp->get('name'),
1154: 'type' => $userProp->get('type'),
1155: 'value' => $userProp->get('value')
1156: );
1157: }
1158:
1159: return $props;
1160: }
1161:
1162: /**
1163: * Stores a property to the database
1164: *
1165: * @param string $type
1166: * Type (class, category etc) for the property to retrieve
1167: * @param string $name
1168: * Name of the property to retrieve
1169: * @param string $value
1170: * Value to insert
1171: *
1172: * @throws cDbException
1173: * @throws cException
1174: * @throws cInvalidArgumentException
1175: */
1176: public function setUserProperty($type, $name, $value) {
1177: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1178: $userProps = $userPropColl->setValueByTypeName($type, $name, $value);
1179: }
1180:
1181: /**
1182: * Deletes a user property from the table.
1183: *
1184: * @param string $type
1185: * Type (class, category etc) of property to retrieve
1186: * @param string $name
1187: * Name of property to retrieve
1188: *
1189: * @return bool
1190: *
1191: * @throws cDbException
1192: * @throws cException
1193: * @throws cInvalidArgumentException
1194: */
1195: public function deleteUserProperty($type, $name) {
1196: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1197: return $userPropColl->deleteByUserIdTypeName($type, $name);
1198: }
1199:
1200: /**
1201: * This static method provides a simple way to get error messages depending
1202: * on error code $iErrorCode, which is returned by checkPassword* methods.
1203: *
1204: * @param int $iErrorCode
1205: * @return string
1206: */
1207: public static function getErrorString($iErrorCode) {
1208: global $cfg;
1209:
1210: $sError = '';
1211:
1212: switch ($iErrorCode) {
1213: case self::PASS_NOT_ENOUGH_MIXED_CHARS:
1214: $sError = sprintf(i18n('Please use at least %d lower and upper case characters in your password!'), $cfg['password']['mixed_case_mandatory']);
1215: break;
1216: case self::PASS_NOT_ENOUGH_NUMBERS:
1217: $sError = sprintf(i18n('Please use at least %d numbers in your password!'), $cfg['password']['numbers_mandatory']);
1218: break;
1219: case self::PASS_NOT_ENOUGH_SYMBOLS:
1220: $sError = sprintf(i18n('Please use at least %d symbols in your password!'), $cfg['password']['symbols_mandatory']);
1221: break;
1222: case self::PASS_TO_SHORT:
1223: $sError = sprintf(i18n('Password is too short! Please use at least %d signs.'), ($cfg['password']['min_length'] > 0? $cfg['password']['min_length'] : self::MIN_PASS_LENGTH_DEFAULT));
1224: break;
1225: case self::PASS_NOT_ENOUGH_DIFFERENT_CHARS:
1226: $sError = sprintf(i18n('Password does not contain enough different characters.'));
1227: break;
1228: case self::PASS_NOT_STRONG:
1229: $sError = i18n('Please choose a more secure password!');
1230: break;
1231: default:
1232: $sError = 'I do not really know what has happened. But your password does not match the
1233: policies! Please consult your administrator. The error code is #' . $iErrorCode;
1234: }
1235:
1236: return $sError;
1237: }
1238: }
1239: