1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
17:
18: 19: 20: 21: 22: 23:
24: class cApiUserCollection extends ItemCollection {
25:
26: 27: 28: 29: 30: 31: 32: 33:
34: public function __construct($where = false) {
35: global $cfg;
36: parent::__construct($cfg['tab']['user'], 'user_id');
37: $this->_setItemClass('cApiUser');
38: if ($where !== false) {
39: $this->select($where);
40: }
41: }
42:
43: 44: 45: 46: 47: 48:
49: public function create($username) {
50: $primaryKeyValue = md5($username);
51:
52: $item = $this->createNewItem($primaryKeyValue);
53: if ($item->usernameExists($username)) {
54: return false;
55: }
56:
57: $item->set('username', $username);
58: $item->set('salt', md5($username . rand(1000, 9999) . rand(1000, 9999) . rand(1000, 9999)));
59: $item->store();
60:
61: return $item;
62: }
63:
64: 65: 66: 67: 68: 69: 70: 71:
72: public function deleteUserByUsername($username) {
73: $result = $this->deleteBy('username', $username);
74: return ($result > 0) ? true : false;
75: }
76:
77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88:
89: public function fetchAccessibleUsers($perms, $includeAdmins = false, $orderBy = '') {
90: $users = array();
91: $limit = array();
92: $where = '';
93:
94: if (!in_array('sysadmin', $perms)) {
95:
96: $clientColl = new cApiClientCollection();
97: $allClients = $clientColl->getAvailableClients();
98:
99: foreach ($allClients as $key => $value) {
100: if (in_array('client[' . $key . ']', $perms) || in_array('admin[' . $key . ']', $perms)) {
101: $limit[] = 'perms LIKE "%client[' . $this->escape($key) . ']%"';
102: if ($includeAdmins) {
103: $limit[] = 'perms LIKE "%admin[' . $this->escape($key) . ']%"';
104: }
105: }
106: if (in_array('admin[' . $key . ']', $perms)) {
107: $limit[] = 'perms LIKE "%admin[' . $key . ']%"';
108: }
109: }
110:
111: if ($includeAdmins) {
112: $limit[] = 'perms LIKE "%sysadmin%"';
113: }
114:
115: if (count($limit) > 0) {
116: $where = '1 AND ' . implode(' OR ', $limit);
117: }
118: }
119:
120: if (empty($orderBy)) {
121: $orderBy = 'realname, username';
122: }
123:
124: $this->select($where, '', $this->escape($orderBy));
125: while (($oItem = $this->next()) !== false) {
126: $users[] = clone $oItem;
127: }
128:
129: return $users;
130: }
131:
132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146:
147: public function getAccessibleUsers($perms, $includeAdmins = false, $orderBy = '') {
148: $users = array();
149: $oUsers = $this->fetchAccessibleUsers($perms, $includeAdmins, $orderBy);
150: foreach ($oUsers as $oItem) {
151: $users[$oItem->get('user_id')] = array(
152: 'username' => $oItem->get('username'),
153: 'realname' => $oItem->get('realname')
154: );
155: }
156: return $users;
157: }
158:
159: 160: 161: 162: 163: 164: 165:
166: public function fetchAvailableUsers($orderBy = 'realname ASC') {
167: $users = array();
168:
169: $this->select('', '', $this->escape($orderBy));
170: while (($oItem = $this->next()) !== false) {
171: $users[] = clone $oItem;
172: }
173:
174: return $users;
175: }
176:
177: 178: 179: 180: 181: 182: 183: 184:
185: public function fetchSystemAdmins($forceActive = false) {
186: $users = array();
187:
188: $where = 'perms LIKE "%sysadmin%"';
189: if ($forceActive === true) {
190: $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')";
191: }
192:
193: $this->select($where);
194: while (($item = $this->next()) !== false) {
195: $users[] = clone $item;
196: }
197:
198: return $users;
199: }
200:
201: 202: 203: 204: 205: 206: 207:
208: public function fetchClientAdmins($client) {
209: $client = (int) $client;
210: $users = array();
211:
212: $where = 'perms LIKE "%admin[' . $client . ']%"';
213:
214: $this->select($where);
215: while (($item = $this->next()) !== false) {
216: $users[] = clone $item;
217: }
218:
219: return $users;
220: }
221: }
222:
223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276:
277: class cApiUser extends Item {
278:
279: 280: 281: 282: 283: 284:
285: const PASS_OK = 0;
286:
287: 288: 289: 290: 291: 292:
293: const PASS_TO_SHORT = 1;
294:
295: 296: 297: 298: 299: 300:
301: const PASS_NOT_STRONG = 2;
302:
303: 304: 305: 306: 307: 308:
309: const PASS_NOT_COMPLEX = 3;
310:
311: 312: 313: 314: 315: 316:
317: const PASS_NOT_ENOUGH_NUMBERS = 4;
318:
319: 320: 321: 322: 323:
324: const PASS_NOT_ENOUGH_SYMBOLS = 5;
325:
326: 327: 328: 329: 330: 331:
332: const PASS_NOT_ENOUGH_MIXED_CHARS = 6;
333:
334: 335: 336: 337: 338: 339:
340: const PASS_NOT_ENOUGH_DIFFERENT_CHARS = 7;
341:
342: 343: 344: 345: 346: 347: 348:
349: const EXCEPTION_USERNAME_EXISTS = 8;
350:
351: 352: 353: 354: 355: 356: 357:
358: const EXCEPTION_PASSWORD_INVALID = 9;
359:
360: 361: 362: 363: 364: 365: 366:
367: const MIN_PASS_LENGTH_DEFAULT = 8;
368:
369: 370: 371: 372: 373: 374:
375: public function __construct($mId = false) {
376: global $cfg;
377: parent::__construct($cfg['tab']['user'], 'user_id');
378: $this->setFilters(array(), array());
379: if ($mId !== false) {
380: $this->loadByPrimaryKey($mId);
381: }
382: }
383:
384: 385: 386: 387: 388: 389: 390: 391:
392: public function loadUserByUserID($userId) {
393: return $this->loadByPrimaryKey($userId);
394: }
395:
396: 397: 398: 399: 400: 401: 402: 403:
404: public function loadUserByUsername($userName) {
405: return $this->loadBy('username', $userName);
406: }
407:
408: 409: 410: 411: 412: 413: 414:
415: public static function userExists($userId) {
416: $test = new cApiUser();
417:
418: return $test->loadByPrimaryKey($userId);
419: }
420:
421: 422: 423: 424: 425: 426: 427: 428:
429: public static function usernameExists($username) {
430: $user = new cApiUser();
431: return $user->loadBy('username', $username);
432: }
433:
434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444:
445: public static function checkPasswordMask($password) {
446: global $cfg;
447:
448: $iResult = self::PASS_OK;
449:
450: $cfgPw = $cfg['password'];
451:
452: if (!isset($cfgPw['check_password_mask']) || $cfgPw['check_password_mask'] == false) {
453:
454: return $iResult;
455: }
456:
457:
458: $iMinLength = self::MIN_PASS_LENGTH_DEFAULT;
459: if (isset($cfgPw['min_length'])) {
460: $iMinLength = (int) $cfgPw['min_length'];
461: }
462:
463:
464: if (strlen($password) < $iMinLength) {
465: $iResult = self::PASS_TO_SHORT;
466: }
467:
468:
469:
470: if ($iResult == self::PASS_OK && isset($cfgPw['numbers_mandatory']) && (int) $cfgPw['numbers_mandatory'] > 0) {
471:
472: $aNumbersInPassword = array();
473: preg_match_all('/[0-9]/', $password, $aNumbersInPassword);
474:
475: if (count($aNumbersInPassword[0]) < (int) $cfgPw['numbers_mandatory']) {
476: $iResult = self::PASS_NOT_ENOUGH_NUMBERS;
477: }
478: }
479:
480:
481: if ($iResult == self::PASS_OK && isset($cfgPw['symbols_mandatory']) && (int) $cfgPw['symbols_mandatory'] > 0) {
482:
483: $aSymbols = array();
484: $sSymbolsDefault = "/[|!@#$%&*\/=?,;.:\-_+~^ยจ\\\]/";
485: if (isset($cfgPw['symbols_regex']) && !empty($cfgPw['symbols_regex'])) {
486: $sSymbolsDefault = $cfgPw['symbols_regex'];
487: }
488:
489: preg_match_all($sSymbolsDefault, $password, $aSymbols);
490:
491: if (count($aSymbols[0]) < (int) $cfgPw['symbols_mandatory']) {
492: $iResult = self::PASS_NOT_ENOUGH_SYMBOLS;
493: }
494: }
495:
496:
497: if ($iResult == self::PASS_OK && isset($cfgPw['mixed_case_mandatory']) && (int) $cfgPw['mixed_case_mandatory'] > 0) {
498:
499: $aLowerCaseChars = array();
500: $aUpperCaseChars = array();
501:
502: preg_match_all('/[a-z]/', $password, $aLowerCaseChars);
503: preg_match_all('/[A-Z]/', $password, $aUpperCaseChars);
504:
505: if ((count($aLowerCaseChars[0]) < (int) $cfgPw['mixed_case_mandatory']) || (count($aUpperCaseChars[0]) < (int) $cfgPw['mixed_case_mandatory'])) {
506: $iResult = self::PASS_NOT_ENOUGH_MIXED_CHARS;
507: }
508: }
509:
510: return $iResult;
511: }
512:
513: 514: 515: 516: 517: 518: 519: 520:
521: public function encodePassword($password) {
522: return hash("sha256", md5($password) . $this->get("salt"));
523: }
524:
525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536:
537: public function setField($sField, $mValue, $bSafe = true) {
538: if ('perms' === $sField) {
539: if (is_array($mValue)) {
540: $mValue = implode(',', $mValue);
541: }
542: }
543:
544: return parent::setField($sField, $mValue, $bSafe);
545: }
546:
547: 548: 549: 550: 551:
552: public function getUserId() {
553: return $this->get('user_id');
554: }
555:
556: 557: 558: 559: 560: 561:
562: public function setUserId($uid) {
563: $this->loadByPrimaryKey($uid);
564: }
565:
566: 567: 568: 569: 570: 571: 572:
573: public function setPassword($password) {
574: $result = self::checkPasswordMask($password);
575: if ($result != self::PASS_OK) {
576: return $result;
577: }
578:
579: $encPass = $this->encodePassword($password);
580:
581: if ($this->get('password') != $encPass) {
582: $this->set('password', $encPass);
583: $this->set('using_pw_request', '0');
584: }
585:
586: return $result;
587: }
588:
589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601:
602: public function savePassword($password) {
603: if ($this->get('password') == $this->encodePassword($password)) {
604: return self::PASS_OK;
605: }
606:
607: $result = $this->setPassword($password);
608:
609: if ($this->store() === false) {
610: return false;
611: } else {
612: return $result;
613: }
614: }
615:
616: 617: 618: 619: 620:
621: public function getUserName() {
622: return $this->get('username');
623: }
624:
625: 626: 627: 628: 629:
630: public function setUserName($sUserName) {
631: if ($this->get('username') != $sUserName) {
632: $this->set('username', $sUserName);
633: }
634: }
635:
636: 637: 638: 639: 640: 641:
642: public function getRealName() {
643: return $this->get('realname');
644: }
645:
646: 647: 648: 649: 650: 651:
652: public function getEffectiveName() {
653: $name = trim($this->get('realname'));
654: if (strlen($name) == 0) {
655: $name = trim($this->get('username'));
656: }
657: return $name;
658: }
659:
660: 661: 662: 663: 664:
665: public function getMail() {
666: return $this->get('email');
667: }
668:
669: 670: 671: 672: 673:
674: public function getTelNumber() {
675: return $this->get('telephone');
676: }
677:
678: 679: 680: 681: 682: 683: 684: 685: 686: 687:
688: public function getAddressData() {
689: $aret = array(
690: 'street' => $this->get('address_street'),
691: 'city' => $this->get('address_city'),
692: 'country' => $this->get('address_country'),
693: 'zip' => $this->get('address_zip')
694: );
695:
696: return $aret;
697: }
698:
699: 700: 701: 702: 703:
704: public function getUseWysi() {
705: return $this->get('wysi');
706: }
707:
708: 709: 710: 711: 712:
713: public function getValidDateTo() {
714: return $this->get('valid_to');
715: }
716:
717: 718: 719: 720: 721:
722: public function getValidDateFrom() {
723: return $this->get('valid_from');
724: }
725:
726: 727: 728: 729: 730:
731: public function getPerms() {
732: return $this->get('perms');
733: }
734:
735: 736: 737: 738: 739:
740: public function getPermsArray() {
741: return explode(',', $this->get('perms'));
742: }
743:
744: 745: 746: 747: 748:
749: public function setRealName($sRealName) {
750: if ($this->get('realname') != $sRealName) {
751: $this->set('realname', $sRealName);
752: }
753: }
754:
755: 756: 757: 758: 759:
760: public function setMail($sMail) {
761: if ($this->get('email') != $sMail) {
762: $this->set('email', $sMail);
763: }
764: }
765:
766: 767: 768: 769: 770:
771: public function setTelNumber($sTelNumber) {
772: if ($this->get('telephone') != $sTelNumber) {
773: $this->set('telephone', $sTelNumber);
774: }
775: }
776:
777: 778: 779: 780: 781: 782: 783: 784:
785: public function setAddressData($sStreet, $sCity, $sZip, $sCountry) {
786: if ($this->get('address_street') != $sStreet) {
787: $this->set('address_street', $sStreet);
788: }
789: if ($this->get('address_city') != $sCity) {
790: $this->set('address_city', $sCity);
791: }
792: if ($this->get('address_zip') != $sZip) {
793: $this->set('address_zip', $sZip);
794: }
795: if ($this->get('address_country') != $sCountry) {
796: $this->set('address_country', $sCountry);
797: }
798: }
799:
800: 801: 802: 803: 804:
805: public function setStreet($sStreet) {
806: if ($this->get('address_street') != $sStreet) {
807: $this->set('address_street', $sStreet);
808: }
809: }
810:
811: 812: 813: 814: 815:
816: public function setCity($sCity) {
817: if ($this->get('address_city') != $sCity) {
818: $this->set('address_city', $sCity);
819: }
820: }
821:
822: 823: 824: 825: 826:
827: public function setZip($sZip) {
828: if ($this->get('address_zip') != $sZip) {
829: $this->set('address_zip', $sZip);
830: }
831: }
832:
833: 834: 835: 836: 837:
838: public function setCountry($sCountry) {
839: if ($this->get('address_country') != $sCountry) {
840: $this->set('address_country', $sCountry);
841: }
842: }
843:
844: 845: 846: 847: 848:
849: public function setUseWysi($iUseWysi) {
850: if ($this->get('wysi') != $iUseWysi) {
851: $this->set('wysi', $iUseWysi);
852: }
853: }
854:
855: 856: 857: 858: 859: 860:
861: public function setValidDateTo($sValidateTo) {
862: if ('0000-00-00' == $this->get('valid_to') && 0 == strlen(trim($sValidateTo))) {
863: return;
864: }
865: if ($this->get('valid_to') != $sValidateTo) {
866: $this->set('valid_to', $sValidateTo);
867: }
868: }
869:
870: 871: 872: 873: 874: 875:
876: public function setValidDateFrom($sValidateFrom) {
877: if ('0000-00-00' == $this->get('valid_from') && 0 == strlen(trim($sValidateFrom))) {
878: return;
879: }
880: if ($this->get('valid_from') != $sValidateFrom) {
881: $this->set('valid_from', $sValidateFrom);
882: }
883: }
884:
885: 886: 887: 888: 889:
890: public function setPerms($perms) {
891: if ($this->get('perms') != $perms) {
892: $this->set('perms', $perms);
893: }
894: }
895:
896: 897: 898: 899: 900: 901: 902: 903:
904: public function getEffectiveUserPerms() {
905: global $perm;
906:
907:
908:
909: $aUserPerms = array();
910: $aUserPermsSelf = explode(',', $this->values['perms']);
911: foreach ($aUserPermsSelf as $sPerm) {
912: if (trim($sPerm) != '') {
913: $aUserPerms[] = $sPerm;
914: }
915: }
916:
917:
918: $groups = $perm->getGroupsForUser($this->values['user_id']);
919:
920: foreach ($groups as $value) {
921:
922: $oGroup = new cApiGroup($value);
923: $aGroupPerms = $oGroup->getPermsArray();
924:
925:
926:
927: foreach ($aGroupPerms as $sPerm) {
928: if (trim($sPerm) != '' && !in_array($sPerm, $aUserPerms)) {
929: $aUserPerms[] = $sPerm;
930: }
931: }
932: }
933: return implode(',', $aUserPerms);
934: }
935:
936: 937: 938: 939: 940: 941: 942: 943: 944:
945: public function getGroupNamesByUserID($userid = NULL, $bAddDescription = true) {
946: $userid = (NULL === $userid) ? $this->get('user_id') : $userid;
947:
948: $aGroups = array();
949:
950: $oGroupColl = new cApiGroupCollection();
951: $groups = $oGroupColl->fetchByUserID($userid);
952:
953: foreach ($groups as $group) {
954: $sTemp = $group->get('groupname');
955: $sTemp = substr($sTemp, 4, strlen($sTemp) - 4);
956:
957: if (true === $bAddDescription) {
958: $sDescription = trim($group->get('description'));
959: if ($sDescription != '') {
960: $sTemp .= ' (' . $sDescription . ')';
961: }
962: }
963:
964: $aGroups[] = $sTemp;
965: }
966:
967: return $aGroups;
968: }
969:
970: 971: 972: 973: 974: 975: 976:
977: public function getGroupIDsByUserID($userid) {
978: $userid = (NULL === $userid) ? $this->get('user_id') : $userid;
979:
980: $aGroups = array();
981:
982: $oGroupColl = new cApiGroupCollection();
983: $groups = $oGroupColl->fetchByUserID($userid);
984:
985: foreach ($groups as $group) {
986: $aGroups[] = $group->get('group_id');
987: }
988:
989: return $aGroups;
990: }
991:
992: 993: 994: 995: 996: 997: 998: 999: 1000: 1001: 1002: 1003:
1004: public function getUserProperty($type, $name, $group = false) {
1005: global $perm;
1006:
1007: if (!is_object($perm)) {
1008: $perm = new cPermission();
1009: }
1010:
1011: $result = false;
1012:
1013: if ($group == true) {
1014:
1015: $groups = $perm->getGroupsForUser($this->values['user_id']);
1016:
1017: foreach ($groups as $groupid) {
1018: $groupPropColl = new cApiGroupPropertyCollection($groupid);
1019: $groupProp = $groupPropColl->fetchByGroupIdTypeName($type, $name);
1020: if ($groupProp) {
1021: $result = $groupProp->get('value');
1022: }
1023: }
1024: }
1025:
1026:
1027: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1028: $userProp = $userPropColl->fetchByUserIdTypeName($type, $name);
1029: if ($userProp) {
1030: $result = $userProp->get('value');
1031: }
1032:
1033: return ($result !== false) ? $result : false;
1034: }
1035:
1036: 1037: 1038: 1039: 1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050:
1051: public function getUserPropertiesByType($type, $group = false) {
1052: global $perm;
1053:
1054: if (!is_object($perm)) {
1055: $perm = new cPermission();
1056: }
1057:
1058: $props = array();
1059:
1060: if ($group == true) {
1061:
1062: $groups = $perm->getGroupsForUser($this->values['user_id']);
1063: foreach ($groups as $groupid) {
1064: $groupPropColl = new cApiGroupPropertyCollection($groupid);
1065: $groupProps = $groupPropColl->fetchByGroupIdType($type);
1066: foreach ($groupProps as $groupProp) {
1067: $props[$groupProp->get('name')] = $groupProp->get('value');
1068: }
1069: }
1070: }
1071:
1072:
1073: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1074: $userProps = $userPropColl->fetchByUserIdType($type);
1075: foreach ($userProps as $userProp) {
1076: $props[$userProp->get('name')] = $userProp->get('value');
1077: }
1078:
1079: return $props;
1080: }
1081:
1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: 1090:
1091: public function getUserProperties() {
1092: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1093: $userProps = $userPropColl->fetchByUserId();
1094:
1095: $props = array();
1096:
1097: foreach ($userProps as $userProp) {
1098: $props[$userProp->get('iduserprop')] = array(
1099: 'name' => $userProp->get('name'),
1100: 'type' => $userProp->get('type'),
1101: 'value' => $userProp->get('value')
1102: );
1103: }
1104:
1105: return $props;
1106: }
1107:
1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117:
1118: public function setUserProperty($type, $name, $value) {
1119: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1120: $userProps = $userPropColl->setValueByTypeName($type, $name, $value);
1121: }
1122:
1123: 1124: 1125: 1126: 1127: 1128: 1129: 1130: 1131:
1132: public function deleteUserProperty($type, $name) {
1133: $userPropColl = new cApiUserPropertyCollection($this->values['user_id']);
1134: return $userPropColl->deleteByUserIdTypeName($type, $name);
1135: }
1136:
1137: 1138: 1139: 1140: 1141: 1142: 1143:
1144: public static function getErrorString($iErrorCode) {
1145: global $cfg;
1146:
1147: $sError = '';
1148:
1149: switch ($iErrorCode) {
1150: case self::PASS_NOT_ENOUGH_MIXED_CHARS:
1151: $sError = sprintf(i18n('Please use at least %d lower and upper case characters in your password!'), $cfg['password']['mixed_case_mandatory']);
1152: break;
1153: case self::PASS_NOT_ENOUGH_NUMBERS:
1154: $sError = sprintf(i18n('Please use at least %d numbers in your password!'), $cfg['password']['numbers_mandatory']);
1155: break;
1156: case self::PASS_NOT_ENOUGH_SYMBOLS:
1157: $sError = sprintf(i18n('Please use at least %d symbols in your password!'), $cfg['password']['symbols_mandatory']);
1158: break;
1159: case self::PASS_TO_SHORT:
1160: $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));
1161: break;
1162: case self::PASS_NOT_ENOUGH_DIFFERENT_CHARS:
1163: $sError = sprintf(i18n('Password does not contain enough different characters.'));
1164: break;
1165: case self::PASS_NOT_STRONG:
1166: $sError = i18n('Please choose a more secure password!');
1167: break;
1168: default:
1169: $sError = 'I do not really know what has happened. But your password does not match the
1170: policies! Please consult your administrator. The error code is #' . $iErrorCode;
1171: }
1172:
1173: return $sError;
1174: }
1175: }
1176: