source: trunk/Modules/User/User.php

Last change on this file was 9, checked in by chronos, 19 months ago
  • Fixed: Modules initialization.
File size: 18.0 KB
Line 
1<?php
2
3include_once(dirname(__FILE__).'/PasswordHash.php');
4
5define('LOGIN_USED', 'Přihlašovací jméno již použito.');
6define('NAME_USED', 'Jméno uživatele již použito');
7define('EMAIL_USED', 'Email je již použitý. Použijte jiný email nebo si můžete nechat zaslat nové heslo na email.');
8define('USER_REGISTRATED', 'Uživatel registrován. Na zadanou emailovou adresu byl poslán mail s odkazem pro aktivování účtu.');
9define('USER_REGISTRATION_CONFIRMED', 'Vaše registrace byla potvrzena.');
10define('DATA_MISSING', 'Chybí emailová adresa, přezdívka, nebo některé z hesel.');
11define('PASSWORDS_UNMATCHED', 'Hesla si neodpovídají.');
12define('ACCOUNT_LOCKED', 'Účet je uzamčen. Po registraci je nutné provést aktivaci účtu pomocí odkazu zaslaného v aktivačním emailu.');
13define('USER_NOT_LOGGED', 'Nejste přihlášen.');
14define('USER_LOGGED', 'Uživatel přihlášen.');
15define('USER_NOT_REGISTRED', 'Uživatel neregistrován.');
16define('USER_ALREADY_LOGGED', 'Uživatel již přihlášen.');
17define('USER_LOGGED_IN', 'Byl jste přihlášen.');
18define('USER_LOGGED_OUT', 'Byl jste odhlášen.');
19define('BAD_PASSWORD', 'Špatné heslo.');
20define('USER_NOT_FOUND', 'Uživatel nenalezen.');
21define('USER_PASSWORD_RECOVERY_SUCCESS', 'Přihlašovací údaje byly odeslány na zadanou emailovou adresu.');
22define('USER_PASSWORD_RECOVERY_FAIL', 'Podle zadaných údajů nebyl nalezen žádný uživatel.');
23define('USER_PASSWORD_RECOVERY_CONFIRMED', 'Nové heslo bylo aktivováno.');
24
25define('USER_EVENT_REGISTER', 1);
26define('USER_EVENT_LOGIN', 2);
27define('USER_EVENT_LOGOUT', 3);
28define('USER_EVENT_OPTIONS_CHANGED', 4);
29
30define('DEFAULT_GROUP', 1);
31
32// TODO: Make User class more general without dependencies to System, Mail, Log
33
34class User extends Model
35{
36 var $Roles = array();
37 var $User = array();
38 var $OnlineStateTimeout;
39 var $PermissionCache = array();
40 var $PermissionGroupCache = array();
41 var $PermissionGroupCacheOp = array();
42 /** @var Password */
43 var $PasswordHash;
44
45 function __construct($System)
46 {
47 parent::__construct($System);
48 $this->OnlineStateTimeout = 600; // in seconds
49 $this->PasswordHash = new PasswordHash();
50 $this->User = array('Id' => null, 'Member' => null);
51 }
52
53 function Check()
54 {
55 $SID = session_id();
56 // Lookup user record
57 $Query = $this->Database->select('UserOnline', '*', 'SessionId="'.$SID.'"');
58 if ($Query->num_rows > 0)
59 {
60 // Refresh time of last access
61 $this->Database->update('UserOnline', '`SessionId`="'.$SID.'"', array('ActivityTime' => 'NOW()'));
62 } else $this->Database->insert('UserOnline', array('SessionId' => $SID,
63 'User' => null, 'LoginTime' => 'NOW()', 'ActivityTime' => 'NOW()',
64 'IpAddress' => GetRemoteAddress(), 'HostName' => gethostbyaddr(GetRemoteAddress()),
65 'ScriptName' => $_SERVER['PHP_SELF'], 'StayLogged' => 0, 'StayLoggedHash' => ''));
66
67 // Logged permanently?
68 if (array_key_exists('LoginHash', $_COOKIE))
69 {
70 $DbResult = $this->Database->query('SELECT * FROM `UserOnline` WHERE `User`='.$_COOKIE['LoginUserId'].
71 ' AND `StayLogged`=1 AND SessionId!="'.$SID.'"');
72 if ($DbResult->num_rows > 0)
73 {
74 $DbRow = $DbResult->fetch_assoc();
75 if (sha1($_COOKIE['LoginUserId'].$DbRow['StayLoggedHash']) == $_COOKIE['LoginHash'])
76 {
77 $this->Database->query('DELETE FROM `UserOnline` WHERE `SessionId`="'.$SID.'"');
78 $this->Database->query('UPDATE `UserOnline` SET `SessionId`="'.$SID.'" WHERE `Id`='.$DbRow['Id']);
79 }
80 }
81 }
82
83 // Check login
84 $Query = $this->Database->select('UserOnline', '*', '`SessionId`="'.$SID.'"');
85 $Row = $Query->fetch_assoc();
86 if ($Row['User'] != '')
87 {
88 $Query = $this->Database->query('SELECT `User`.* FROM `User` '.
89 ' WHERE `User`.`Id`='.$Row['User']);
90 $this->User = $Query->fetch_assoc();
91 $Result = USER_LOGGED;
92 } else
93 {
94 $Query = $this->Database->select('User', '*', 'Id IS NULL');
95 $this->User = array('Id' => null, 'Member' => null);
96 $Result = USER_NOT_LOGGED;
97 }
98
99 // Remove nonactive users
100 $DbResult = $this->Database->select('UserOnline', '`Id`, `User`', '(`ActivityTime` < DATE_SUB(NOW(), INTERVAL '.$this->OnlineStateTimeout.' SECOND)) AND (`StayLogged` = 0)');
101 while ($DbRow = $DbResult->fetch_array())
102 {
103 $this->Database->delete('UserOnline', 'Id='.$DbRow['Id']);
104 if (($DbRow['User'] != null) and $this->System->ModuleManager->ModulePresent('Log'))
105 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'Logout');
106 }
107 //$this->LoadPermission($this->User['Role']);
108
109 // Role and permission
110 //$this->LoadRoles();
111 }
112
113 function Register($Login, $Password, $Password2, $Email, $Name)
114 {
115 if (($Email == '') || ($Login == '') || ($Password == '') || ($Password2 == '') || ($Name == '')) $Result = DATA_MISSING;
116 else if ($Password != $Password2) $Result = PASSWORDS_UNMATCHED;
117 else
118 {
119 // Is user registred yet?
120 $Query = $this->Database->select('User', '*', 'Login = "'.$Login.'"');
121 if ($Query->num_rows > 0) $Result = LOGIN_USED;
122 else
123 {
124 $Query = $this->Database->select('User', '*', 'Name = "'.$Name.'"');
125 if ($Query->num_rows > 0) $Result = NAME_USED;
126 else
127 {
128 $Query = $this->Database->select('User', '*', 'Email = "'.$Email.'"');
129 if ($Query->num_rows > 0) $Result = EMAIL_USED;
130 else
131 {
132 $PasswordHash = new PasswordHash();
133 $Salt = $PasswordHash->GetSalt();
134 $this->Database->insert('User', array('Name' => $Name, 'Login' => $Login,
135 'Password' => $PasswordHash->Hash($Password, $Salt), 'Salt' => $Salt,
136 'Email' => $Email, 'RegistrationTime' => 'NOW()',
137 'Locked' => 1));
138 $UserId = $this->Database->insert_id;
139 $this->Database->insert('PermissionUserAssignment', array('User' => $UserId,
140 'AssignedGroup' => DEFAULT_GROUP));
141
142 $NewPassword = substr(sha1(strtoupper($Login)), 0, 7);
143
144 // Send activation mail to user email
145 $ServerURL = 'http://'.Core::Cast($this->System)->Config['Web']['Host'].Core::Cast($this->System)->Config['Web']['RootFolder'];
146 $Mail = new Mail();
147 $Mail->Subject = 'Registrace nového účtu';
148 $Mail->AddBody('Provedli jste registraci nového účtu na serveru <a href="'.$ServerURL.'">'.$ServerURL.'"</a>.'.
149 '<br/>\nPokud jste tak neučinili, měli by jste tento email ignorovat.<br/><br/>\n\n'.
150 'Váš účet je: '.$Login."\n<br/>Pro dokončení registrace klikněte na tento odkaz: ".'<a href="'.
151 $ServerURL.'/user/?Action=UserRegisterConfirm&User='.
152 $UserId.'&H='.$NewPassword.'">'.$ServerURL.'/?Action=UserRegisterConfirm&User='.
153 $UserId.'&H='.$NewPassword.'</a>.'."\n<br> \n\n'.
154 '<br/><br/>Na tento email neodpovídejte.", 'text/html');
155 $Mail->AddTo($Email, $Name);
156 $Mail->From = Core::Cast($this->System)->Config['Web']['Title'].' <noreplay@zdechov.net>';
157 $Mail->Send();
158
159 $Result = USER_REGISTRATED;
160 if ($this->System->ModuleManager->ModulePresent('Log'))
161 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'NewRegistration', $Login);
162 }
163 }
164 }
165 }
166 return $Result;
167 }
168
169 function RegisterConfirm($Id, $Hash)
170 {
171 $DbResult = $this->Database->select('User', 'Id, Login, Password', 'Id = '.$Id);
172 if ($DbResult->num_rows > 0)
173 {
174 $Row = $DbResult->fetch_array();
175 $NewPassword = substr(sha1(strtoupper($Row['Login'])), 0, 7);
176 if ($Hash == $NewPassword)
177 {
178 $this->Database->update('User', 'Id='.$Row['Id'], array('Locked' => 0));
179 $Output = USER_REGISTRATION_CONFIRMED;
180 if ($this->System->ModuleManager->ModulePresent('Log'))
181 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'RegisterConfirm', 'Login='.
182 $Row['Login'].', Id='.$Row['Id']);
183 } else $Output = PASSWORDS_UNMATCHED;
184 } else $Output = USER_NOT_FOUND;
185 return $Output;
186 }
187
188 function Login($Login, $Password, $StayLogged = false)
189 {
190 if ($StayLogged) $StayLogged = 1; else $StayLogged = 0;
191 $SID = session_id();
192 $Query = $this->Database->select('User', '*', 'Login="'.$Login.'"');
193 if ($Query->num_rows > 0)
194 {
195 $Row = $Query->fetch_assoc();
196 $PasswordHash = new PasswordHash();
197 if (!$PasswordHash->Verify($Password, $Row['Salt'], $Row['Password'])) $Result = BAD_PASSWORD;
198 else if ($Row['Locked'] == 1) $Result = ACCOUNT_LOCKED;
199 else
200 {
201 $this->Database->update('User', 'Id='.$Row['Id'], array('LastLoginTime' => 'NOW()',
202 'LastIpAddress' => GetRemoteAddress()));
203 $Hash = new PasswordHash();
204 $StayLoggedSalt = $Hash->GetSalt();
205 $this->Database->update('UserOnline', 'SessionId="'.$SID.'"', array(
206 'User' => $Row['Id'], 'StayLogged' => $StayLogged, 'StayLoggedHash' => $StayLoggedSalt));
207 if ($StayLogged)
208 {
209 setcookie('LoginUserId', $Row['Id'], time()+365*24*60*60, $this->System->Link('/'));
210 setcookie('LoginHash', sha1($Row['Id'].$StayLoggedSalt), time()+365*24*60*60, $this->System->Link('/'));
211 } else {
212 setcookie('LoginUserId', '', time() - 3600, $this->System->Link('/'));
213 setcookie('LoginHash', '', time() - 3600, $this->System->Link('/'));
214 }
215
216 $Result = USER_LOGGED_IN;
217 $this->Check();
218 if (array_key_exists('Log', $this->System->ModuleManager->Modules))
219 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'Login', 'Login='.$Login.',Host='.gethostbyaddr(GetRemoteAddress()));
220 }
221 } else $Result = USER_NOT_REGISTRED;
222 return $Result;
223 }
224
225 function Logout()
226 {
227 $SID = session_id();
228 $this->Database->update('UserOnline', 'SessionId="'.$SID.'"', array('User' => null));
229 if ($this->System->ModuleManager->ModulePresent('Log'))
230 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'Logout', $this->User['Login']);
231 $this->Check();
232 return USER_LOGGED_OUT;
233 }
234
235 function LoadRoles()
236 {
237 $this->Roles = array();
238 $DbResult = $this->Database->select('UserRole', '*');
239 while ($DbRow = $DbResult->fetch_array())
240 $this->Roles[] = $DbRow;
241 }
242
243 function LoadPermission($Role)
244 {
245 $this->User['Permission'] = array();
246 $DbResult = $this->Database->query('SELECT `UserRolePermission`.*, `PermissionOperation`.`Description` FROM `UserRolePermission` JOIN `PermissionOperation` ON `PermissionOperation`.`Id` = `UserRolePermission`.`Operation` WHERE `UserRolePermission`.`Role` = '.$Role);
247 if ($DbResult->num_rows > 0)
248 while ($DbRow = $DbResult->fetch_array())
249 $this->User['Permission'][$DbRow['Operation']] = $DbRow;
250 }
251
252 function PermissionMatrix()
253 {
254 $Result = array();
255 $DbResult = $this->Database->query('SELECT `UserRolePermission`.*, `PermissionOperation`.`Description`, `UserRole`.`Title` FROM `UserRolePermission` LEFT JOIN `PermissionOperation` ON `PermissionOperation`.`Id` = `UserRolePermission`.`Operation` LEFT JOIN `UserRole` ON `UserRole`.`Id` = `UserRolePermission`.`Role`');
256 while ($DbRow = $DbResult->fetch_array())
257 {
258 $Value = '';
259 if ($DbRow['Read']) $Value .= 'R';
260 if ($DbRow['Write']) $Value .= 'W';
261 $Result[$DbRow['Description']][$DbRow['Title']] = $Value;
262 }
263 return $Result;
264 }
265
266 function CheckGroupPermission($GroupId, $OperationId)
267 {
268 $PermissionExists = false;
269 // First try to check cache group-group relation
270 if (array_key_exists($GroupId, $this->PermissionGroupCache))
271 {
272 $PermissionExists = true;
273 } else
274 {
275 // If no permission combination exists in cache, do new check of database items
276 $DbResult = $this->Database->select('PermissionGroupAssignment', '*', '(`Group`="'.$GroupId.
277 '") AND (`AssignedGroup` IS NOT NULL)');
278 $DbRow = array();
279 while ($DbRow[] = $DbResult->fetch_array());
280 $this->PermissionGroupCache[$GroupId] = $DbRow;
281 $PermissionExists = true;
282 }
283 if ($PermissionExists)
284 {
285 foreach ($this->PermissionGroupCache[$GroupId] as $DbRow)
286 {
287 if ($DbRow['AssignedGroup'] != '')
288 if ($this->CheckGroupPermission($DbRow['AssignedGroup'], $OperationId) == true) return true;
289 }
290 }
291
292 // Check group-operation relation
293 if (array_key_exists($GroupId.','.$OperationId, $this->PermissionGroupCacheOp))
294 {
295 $PermissionExists = true;
296 } else
297 {
298 // If no permission combination exists in cache, do new check of database items
299 $DbResult = $this->Database->select('PermissionGroupAssignment', '*', '`Group`="'.$GroupId.'" AND `AssignedOperation`="'.$OperationId.'"');
300 if ($DbResult->num_rows > 0) $this->PermissionGroupCacheOp[$GroupId.','.$OperationId] = true;
301 else $this->PermissionGroupCacheOp[$GroupId.','.$OperationId] = false;
302 $PermissionExists = true;
303 }
304 if ($PermissionExists)
305 {
306 return $this->PermissionGroupCacheOp[$GroupId.','.$OperationId];
307 }
308 return false;
309 }
310
311 function CheckPermission($Module, $Operation, $ItemType = '', $ItemIndex = 0)
312 {
313 // Get module id
314 $DbResult = $this->Database->select('Module', 'Id', '`Name`="'.$Module.'"');
315 if ($DbResult->num_rows > 0)
316 {
317 $DbRow = $DbResult->fetch_assoc();
318 $ModuleId = $DbRow['Id'];
319 } else return false;
320
321 // First try to check cache
322 if (in_array(array($Module, $Operation, $ItemType, $ItemType), $this->PermissionCache))
323 {
324 $OperationId = array_search(array($Module, $Operation, $ItemType, $ItemIndex), $this->PermissionCache);
325 $PermissionExists = is_numeric($OperationId);
326 } else
327 {
328 // If no permission combination exists in cache, do new check of database items
329 $DbResult = $this->Database->select('PermissionOperation', 'Id', '(`Module`="'.$ModuleId.
330 '") AND (`Item`="'.$ItemType.'") AND (`ItemId`='.$ItemIndex.') AND (`Operation`="'.$Operation.'")');
331 if ($DbResult->num_rows > 0)
332 {
333 $DbRow = $DbResult->fetch_array();
334 $OperationId = $DbRow['Id'];
335 $this->PermissionCache[$DbRow['Id']] = array($Module, $Operation, $ItemType, $ItemIndex);
336 $PermissionExists = true;
337 } else
338 {
339 $this->PermissionCache[count($this->PermissionCache).'_'] = array($Module, $Operation, $ItemType, $ItemIndex);
340 $PermissionExists = false;
341 }
342 }
343
344 if ($PermissionExists)
345 {
346 if ($this->User['Id'] == null) $UserCondition = '(`User` IS NULL)';
347 else $UserCondition = '(`User`="'.$this->User['Id'].'")';
348 // Check user-operation relation
349 $DbResult = $this->Database->select('PermissionUserAssignment', '*', $UserCondition.' AND (`AssignedOperation`="'.$OperationId.'")');
350 if ($DbResult->num_rows > 0) return true;
351
352 // Check user-group relation
353 $DbResult = $this->Database->select('PermissionUserAssignment', 'AssignedGroup', $UserCondition);
354 while ($DbRow = $DbResult->fetch_array())
355 {
356 if ($this->CheckGroupPermission($DbRow['AssignedGroup'], $OperationId) == true) return true;
357 }
358 return false;
359 } else return false;
360 }
361
362 function PasswordRecoveryRequest($Login, $Email)
363 {
364 $DbResult = $this->Database->select('User', 'Login, Name, Id, Email, Password', '`Login`="'.$Login.'" AND `Email`="'.$Email.'"');
365 if ($DbResult->num_rows > 0)
366 {
367 $Row = $DbResult->fetch_array();
368 $NewPassword = substr(sha1(strtoupper($Row['Login'])), 0, 7);
369
370 $ServerURL = 'http://'.Core::Cast($this->System)->Config['Web']['Host'].Core::Cast($this->System)->Config['Web']['RootFolder'];
371 $Mail = new Mail();
372 $Mail->Subject = 'Obnova hesla';
373 $Mail->From = Core::Cast($this->System)->Config['Web']['Title'].' <noreplay@zdechov.net>';
374 $Mail->AddTo($Row['Email'], $Row['Name']);
375 $Mail->AddBody('Požádali jste o zaslání nového hesla na serveru <a href="'.$ServerURL.'">'.$ServerURL.'"</a>.<br />\n'.
376 "Pokud jste tak neučinili, měli by jste tento email ignorovat.<br /><br />\n\nVaše nové heslo k účtu ".
377 $Row['Login'].' je: '.$NewPassword."\n<br/>".
378 'Pro aktivaci tohoto hesla klikněte na <a href="'.$ServerURL.'/user/?Action=PasswordRecoveryConfirm&User='.
379 $Row['Id'].'&H='.$Row['Password'].'&P='.$NewPassword.'">tento odkaz</a>.'."\n<br />".
380 "Po přihlášení si prosím změňte heslo na nové.\n\n<br><br>Na tento email neodpovídejte.", 'text/html');
381 $Mail->Send();
382
383 $Output = USER_PASSWORD_RECOVERY_SUCCESS;
384 if ($this->System->ModuleManager->ModulePresent('Log'))
385 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'PasswordRecoveryRequest', 'Login='.$Login.',Email='.$Email);
386 } else $Output = USER_PASSWORD_RECOVERY_FAIL;
387 return $Output;
388 }
389
390 function PasswordRecoveryConfirm($Id, $Hash, $NewPassword)
391 {
392 $DbResult = $this->Database->select('User', 'Id, Login, Password', 'Id = '.$Id);
393 if ($DbResult->num_rows > 0)
394 {
395 $Row = $DbResult->fetch_array();
396 $NewPassword2 = substr(sha1(strtoupper($Row['Login'])), 0, 7);
397 if (($NewPassword == $NewPassword2) and ($Hash == $Row['Password']))
398 {
399 $PasswordHash = new PasswordHash();
400 $Salt = $PasswordHash->GetSalt();
401 $this->Database->update('User', 'Id='.$Row['Id'], array('Password' => $PasswordHash->Hash($NewPassword, $Salt),
402 'Salt' => $Salt, 'Locked' => 0));
403 if ($this->System->ModuleManager->ModulePresent('Log'))
404 $this->System->ModuleManager->Modules['Log']->NewRecord('User', 'PasswordRecoveryConfirm', 'Login='.$Row['Login']);
405 } else $Output = PASSWORDS_UNMATCHED;
406 } else $Output = USER_NOT_FOUND;
407 return $Output;
408 }
409
410 function CheckToken($Module, $Operation, $Token)
411 {
412 $DbResult = $this->Database->select('APIToken', 'User', '`Token`="'.$Token.'"');
413 if ($DbResult->num_rows > 0)
414 {
415 $DbRow = $DbResult->fetch_assoc();
416 $User = new User($this->System);
417 $User->User = array('Id' => $DbRow['User']);
418 return $User->CheckPermission($Module, $Operation);
419 } else return false;
420 }
421}
Note: See TracBrowser for help on using the repository browser.