Вход Регистрация
Файл: contao-3.5.8/system/modules/core/library/Contao/User.php
Строк: 607
<?php

/**
 * Contao Open Source CMS
 *
 * Copyright (c) 2005-2016 Leo Feyer
 *
 * @license LGPL-3.0+
 */

namespace Contao;


/**
 * Authenticates and initializes user objects
 *
 * The class supports user authentication, login and logout, persisting the
 * session data and initializing the user object from a database row. It
 * functions as abstract parent class for the "BackendUser" and "FrontendUser"
 * classes of the core.
 *
 * Usage:
 *
 *     $user = BackendUser::getInstance();
 *
 *     if ($user->findBy('username', 'leo'))
 *     {
 *         echo $user->name;
 *     }
 *
 * @property integer $id
 * @property integer $tstamp
 * @property string  $username
 * @property string  $name
 * @property string  $email
 * @property string  $language
 * @property string  $backendTheme
 * @property string  $uploader
 * @property boolean $showHelp
 * @property boolean $thumbnails
 * @property boolean $useRTE
 * @property boolean $useCE
 * @property string  $password
 * @property boolean $pwChange
 * @property boolean $admin
 * @property string  $groups
 * @property string  $inherit
 * @property string  $modules
 * @property string  $themes
 * @property array   $pagemounts
 * @property string  $alpty
 * @property array   $filemounts
 * @property string  $fop
 * @property string  $forms
 * @property string  $formp
 * @property boolean $disable
 * @property string  $start
 * @property string  $stop
 * @property string  $session
 * @property integer $dateAdded
 * @property integer $lastLogin
 * @property integer $currentLogin
 * @property integer $loginCount
 * @property integer $locked
 * @property string  $calendars
 * @property string  $calendarp
 * @property string  $calendarfeeds
 * @property string  $calendarfeedp
 * @property string  $faqs
 * @property string  $faqp
 * @property string  $news
 * @property string  $newp
 * @property string  $newsfeeds
 * @property string  $newsfeedp
 * @property string  $newsletters
 * @property string  $newsletterp
 * @property string  $firstname
 * @property string  $lastname
 * @property string  $dateOfBirth
 * @property string  $gender
 * @property string  $company
 * @property string  $street
 * @property string  $postal
 * @property string  $city
 * @property string  $state
 * @property string  $country
 * @property string  $phone
 * @property string  $mobile
 * @property string  $fax
 * @property string  $website
 * @property boolean $login
 * @property boolean $assignDir
 * @property string  $homeDir
 * @property string  $autologin
 * @property integer $createdOn
 * @property string  $activation
 * @property string  $newsletter
 * @property string  $loginPage
 * @property object  $objImport
 * @property object  $objAuth
 * @property object  $objLogin
 * @property object  $objLogout
 *
 * @author Leo Feyer <https://github.com/leofeyer>
 */
abstract class User extends System
{

    
/**
     * Object instance (Singleton)
     * @var User
     */
    
protected static $objInstance;

    
/**
     * User ID
     * @var integer
     */
    
protected $intId;

    
/**
     * IP address
     * @var string
     */
    
protected $strIp;

    
/**
     * Authentication hash
     * @var string
     */
    
protected $strHash;

    
/**
     * Table
     * @var string
     */
    
protected $strTable;

    
/**
     * Cookie name
     * @var string
     */
    
protected $strCookie;

    
/**
     * Data
     * @var array
     */
    
protected $arrData = array();


    
/**
     * Import the database object
     */
    
protected function __construct()
    {
        
parent::__construct();
        
$this->import('Database');
    }


    
/**
     * Prevent cloning of the object (Singleton)
     */
    
final public function __clone() {}


    
/**
     * Set an object property
     *
     * @param string $strKey   The property name
     * @param mixed  $varValue The property value
     */
    
public function __set($strKey$varValue)
    {
        
$this->arrData[$strKey] = $varValue;
    }


    
/**
     * Return an object property
     *
     * @param string $strKey The property name
     *
     * @return mixed The property value
     */
    
public function __get($strKey)
    {
        if (isset(
$this->arrData[$strKey]))
        {
            return 
$this->arrData[$strKey];
        }

        return 
parent::__get($strKey);
    }


    
/**
     * Check whether a property is set
     *
     * @param string $strKey The property name
     *
     * @return boolean True if the property is set
     */
    
public function __isset($strKey)
    {
        return isset(
$this->arrData[$strKey]);
    }


    
/**
     * Instantiate a new user object (Factory)
     *
     * @return static The object instance
     */
    
public static function getInstance()
    {
        if (static::
$objInstance === null)
        {
            static::
$objInstance = new static();
        }

        return static::
$objInstance;
    }


    
/**
     * Return the current record as associative array
     *
     * @return array
     */
    
public function getData()
    {
        return 
$this->arrData;
    }


    
/**
     * Authenticate a user
     *
     * @return boolean True if the user could be authenticated
     */
    
public function authenticate()
    {
        
// Check the cookie hash
        
if ($this->strHash != sha1(session_id() . (!Config::get('disableIpCheck') ? $this->strIp '') . $this->strCookie))
        {
            return 
false;
        }

        
$objSession $this->Database->prepare("SELECT * FROM tl_session WHERE hash=? AND name=?")
                                     ->
execute($this->strHash$this->strCookie);

        
// Try to find the session in the database
        
if ($objSession->numRows 1)
        {
            return 
false;
        }

        
$time time();

        
// Validate the session
        
if ($objSession->sessionID != session_id() || (!Config::get('disableIpCheck') && $objSession->ip != $this->strIp) || $objSession->hash != $this->strHash || ($objSession->tstamp Config::get('sessionTimeout')) < $time)
        {
            return 
false;
        }

        
$this->intId $objSession->pid;

        
// Load the user object
        
if ($this->findBy('id'$this->intId) == false)
        {
            return 
false;
        }

        
$this->setUserFromDb();

        
// Update session
        
$this->Database->prepare("UPDATE tl_session SET tstamp=$time WHERE sessionID=?")
                       ->
execute(session_id());

        
$this->setCookie($this->strCookie$this->strHash, ($time Config::get('sessionTimeout')), nullnullfalsetrue);

        
// HOOK: post authenticate callback
        
if (isset($GLOBALS['TL_HOOKS']['postAuthenticate']) && is_array($GLOBALS['TL_HOOKS']['postAuthenticate']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['postAuthenticate'] as $callback)
            {
                
$this->import($callback[0], 'objAuth'true);
                
$this->objAuth->{$callback[1]}($this);
            }
        }

        return 
true;
    }


    
/**
     * Try to login the current user
     *
     * @return boolean True if the user could be logged in
     */
    
public function login()
    {
        
System::loadLanguageFile('default');

        
// Do not continue if username or password are missing
        
if (empty($_POST['username']) || empty($_POST['password']))
        {
            return 
false;
        }

        
// Load the user object
        
if ($this->findBy('username'Input::post('username'true)) == false)
        {
            
$blnLoaded false;

            
// HOOK: pass credentials to callback functions
            
if (isset($GLOBALS['TL_HOOKS']['importUser']) && is_array($GLOBALS['TL_HOOKS']['importUser']))
            {
                foreach (
$GLOBALS['TL_HOOKS']['importUser'] as $callback)
                {
                    
$this->import($callback[0], 'objImport'true);
                    
$blnLoaded $this->objImport->{$callback[1]}(Input::post('username'true), Input::postUnsafeRaw('password'), $this->strTable);

                    
// Load successfull
                    
if ($blnLoaded === true)
                    {
                        break;
                    }
                }
            }

            
// Return if the user still cannot be loaded
            
if (!$blnLoaded || $this->findBy('username'Input::post('username'true)) == false)
            {
                
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
                
$this->log('Could not find user "' Input::post('username'true) . '"'__METHOD__TL_ACCESS);

                return 
false;
            }
        }

        
$time time();

        
// Set the user language
        
if (Input::post('language'))
        {
            
$this->language Input::post('language');
        }

        
// Lock the account if there are too many login attempts
        
if ($this->loginCount 1)
        {
            
$this->locked $time;
            
$this->loginCount Config::get('loginCount');
            
$this->save();

            
// Add a log entry and the error message, because checkAccountStatus() will not be called (see #4444)
            
$this->log('User "' $this->username '" has been locked for ' ceil(Config::get('lockPeriod') / 60) . ' minutes'__METHOD__TL_ACCESS);
            
Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['accountLocked'], ceil((($this->locked Config::get('lockPeriod')) - $time) / 60)));

            
// Send admin notification
            
if (Config::get('adminEmail') != '')
            {
                
$objEmail = new Email();
                
$objEmail->subject $GLOBALS['TL_LANG']['MSC']['lockedAccount'][0];
                
$objEmail->text sprintf($GLOBALS['TL_LANG']['MSC']['lockedAccount'][1], $this->username, ((TL_MODE == 'FE') ? $this->firstname " " $this->lastname $this->name), Idna::decode(Environment::get('base')), ceil(Config::get('lockPeriod') / 60));
                
$objEmail->sendTo(Config::get('adminEmail'));
            }

            return 
false;
        }

        
// Check the account status
        
if ($this->checkAccountStatus() == false)
        {
            return 
false;
        }

        
// The password has been generated with crypt()
        
if (Encryption::test($this->password))
        {
            
$blnAuthenticated Encryption::verify(Input::postUnsafeRaw('password'), $this->password);
        }
        else
        {
            list(
$strPassword$strSalt) = explode(':'$this->password);
            
$blnAuthenticated = ($strSalt == '') ? ($strPassword === sha1(Input::postUnsafeRaw('password'))) : ($strPassword === sha1($strSalt Input::postUnsafeRaw('password')));

            
// Store a SHA-512 encrpyted version of the password
            
if ($blnAuthenticated)
            {
                
$this->password Encryption::hash(Input::postUnsafeRaw('password'));
            }
        }

        
// HOOK: pass credentials to callback functions
        
if (!$blnAuthenticated && isset($GLOBALS['TL_HOOKS']['checkCredentials']) && is_array($GLOBALS['TL_HOOKS']['checkCredentials']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['checkCredentials'] as $callback)
            {
                
$this->import($callback[0], 'objAuth'true);
                
$blnAuthenticated $this->objAuth->{$callback[1]}(Input::post('username'true), Input::postUnsafeRaw('password'), $this);

                
// Authentication successfull
                
if ($blnAuthenticated === true)
                {
                    break;
                }
            }
        }

        
// Redirect if the user could not be authenticated
        
if (!$blnAuthenticated)
        {
            --
$this->loginCount;
            
$this->save();

            
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
            
$this->log('Invalid password submitted for username "' $this->username '"'__METHOD__TL_ACCESS);

            return 
false;
        }

        
$this->setUserFromDb();

        
// Update the record
        
$this->lastLogin $this->currentLogin;
        
$this->currentLogin $time;
        
$this->loginCount Config::get('loginCount');
        
$this->save();

        
// Generate the session
        
$this->generateSession();
        
$this->log('User "' $this->username '" has logged in'__METHOD__TL_ACCESS);

        
// HOOK: post login callback
        
if (isset($GLOBALS['TL_HOOKS']['postLogin']) && is_array($GLOBALS['TL_HOOKS']['postLogin']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['postLogin'] as $callback)
            {
                
$this->import($callback[0], 'objLogin'true);
                
$this->objLogin->{$callback[1]}($this);
            }
        }

        return 
true;
    }


    
/**
     * Check the account status and return true if it is active
     *
     * @return boolean True if the account is active
     */
    
protected function checkAccountStatus()
    {
        
$time time();

        
// Check whether the account is locked
        
if (($this->locked Config::get('lockPeriod')) > $time)
        {
            
Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['accountLocked'], ceil((($this->locked Config::get('lockPeriod')) - $time) / 60)));

            return 
false;
        }

        
// Check whether the account is disabled
        
elseif ($this->disable)
        {
            
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
            
$this->log('The account has been disabled'__METHOD__TL_ACCESS);

            return 
false;
        }

        
// Check wether login is allowed (front end only)
        
elseif ($this instanceof FrontendUser && !$this->login)
        {
            
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
            
$this->log('User "' $this->username '" is not allowed to log in'__METHOD__TL_ACCESS);

            return 
false;
        }

        
// Check whether account is not active yet or anymore
        
elseif ($this->start != '' || $this->stop != '')
        {
            
$time Date::floorToMinute($time);

            if (
$this->start != '' && $this->start $time)
            {
                
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
                
$this->log('The account was not active yet (activation date: ' Date::parse(Config::get('dateFormat'), $this->start) . ')'__METHOD__TL_ACCESS);

                return 
false;
            }

            if (
$this->stop != '' && $this->stop <= ($time 60))
            {
                
Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']);
                
$this->log('The account was not active anymore (deactivation date: ' Date::parse(Config::get('dateFormat'), $this->stop) . ')'__METHOD__TL_ACCESS);

                return 
false;
            }
        }

        return 
true;
    }


    
/**
     * Find a user in the database
     *
     * @param string $strColumn The field name
     * @param mixed  $varValue  The field value
     *
     * @return boolean True if the user was found
     */
    
public function findBy($strColumn$varValue)
    {
        
$objResult $this->Database->prepare("SELECT * FROM " $this->strTable " WHERE " $strColumn "=?")
                                    ->
limit(1)
                                    ->
execute($varValue);

        if (
$objResult->numRows 0)
        {
            
$this->arrData $objResult->row();

            return 
true;
        }

        return 
false;
    }


    
/**
     * Update the current record
     */
    
public function save()
    {
        
$this->Database->prepare("UPDATE " $this->strTable " %s WHERE id=?")
                       ->
set($this->arrData)
                       ->
execute($this->id);
    }


    
/**
     * Generate a session
     */
    
protected function generateSession()
    {
        
$time time();

        
// Generate the cookie hash
        
$this->strHash sha1(session_id() . (!Config::get('disableIpCheck') ? $this->strIp '') . $this->strCookie);

        
// Clean up old sessions
        
$this->Database->prepare("DELETE FROM tl_session WHERE tstamp<? OR hash=?")
                       ->
execute(($time Config::get('sessionTimeout')), $this->strHash);

        
// Save the session in the database
        
$this->Database->prepare("INSERT INTO tl_session (pid, tstamp, name, sessionID, ip, hash) VALUES (?, ?, ?, ?, ?, ?)")
                       ->
execute($this->intId$time$this->strCookiesession_id(), $this->strIp$this->strHash);

        
// Set the authentication cookie
        
$this->setCookie($this->strCookie$this->strHash, ($time Config::get('sessionTimeout')), nullnullfalsetrue);

        
// Set the login status (backwards compatibility)
        
$_SESSION['TL_USER_LOGGED_IN'] = true;
    }


    
/**
     * Remove the authentication cookie and destroy the current session
     *
     * @return boolean True if the user could be logged out
     */
    
public function logout()
    {
        
// Return if the user has been logged out already
        
if (!Input::cookie($this->strCookie))
        {
            return 
false;
        }

        
$intUserid null;

        
// Find the session
        
$objSession $this->Database->prepare("SELECT * FROM tl_session WHERE hash=? AND name=?")
                                     ->
limit(1)
                                     ->
execute($this->strHash$this->strCookie);

        if (
$objSession->numRows)
        {
            
$this->strIp $objSession->ip;
            
$this->strHash $objSession->hash;
            
$intUserid $objSession->pid;
        }

        
$time time();

        
// Remove the session from the database
        
$this->Database->prepare("DELETE FROM tl_session WHERE hash=?")
                       ->
execute($this->strHash);

        
// Remove cookie and hash
        
$this->setCookie($this->strCookie$this->strHash, ($time 86400), nullnullfalsetrue);
        
$this->strHash '';

        
// Destroy the current session
        
session_destroy();
        
session_write_close();

        
// Reset the session cookie
        
$params session_get_cookie_params();
        
$this->setCookie(session_name(), session_id(), ($time 86400), $params['path'], $params['domain'], $params['secure'], $params['httponly']);

        
// Set the login status (backwards compatibility)
        
$_SESSION['TL_USER_LOGGED_IN'] = false;

        
// Add a log entry
        
if ($this->findBy('id'$intUserid) != false)
        {
            
$GLOBALS['TL_USERNAME'] = $this->username;
            
$this->log('User "' $this->username '" has logged out'__METHOD__TL_ACCESS);
        }

        
// HOOK: post logout callback
        
if (isset($GLOBALS['TL_HOOKS']['postLogout']) && is_array($GLOBALS['TL_HOOKS']['postLogout']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['postLogout'] as $callback)
            {
                
$this->import($callback[0], 'objLogout'true);
                
$this->objLogout->{$callback[1]}($this);
            }
        }

        return 
true;
    }


    
/**
     * Return true if the user is member of a particular group
     *
     * @param integer $id The group ID
     *
     * @return boolean True if the user is a member of the group
     */
    
public function isMemberOf($id)
    {
        
// ID not numeric
        
if (!is_numeric($id))
        {
            return 
false;
        }

        
$groups deserialize($this->arrData['groups']);

        
// No groups assigned
        
if (empty($groups) || !is_array($groups))
        {
            return 
false;
        }

        
// Group ID found
        
if (in_array($id$groups))
        {
            return 
true;
        }

        return 
false;
    }


    
/**
     * Set all user properties from a database record
     */
    
abstract protected function setUserFromDb();
}
Онлайн: 0
Реклама