Changeset 746 for trunk/Modules/User


Ignore:
Timestamp:
Sep 10, 2015, 10:10:34 PM (9 years ago)
Author:
chronos
Message:
  • Modified: Moved common files used for multiple projects to separate package. Package Common will be maintained in PHPlib subversion repository.
  • Modified: UserModel now contains main User model.
Location:
trunk/Modules/User
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Modules/User/User.php

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