HEX
Server: Apache
System: Linux 185.122.168.184.host.secureserver.net 5.14.0-570.52.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Oct 15 06:39:08 EDT 2025 x86_64
User: barbeatleanalyti (1024)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/barbeatleanalyti/public_html/public_html/webmail/system/Api.php
<?php
/*
 * This code is licensed under AGPLv3 license or Afterlogic Software License
 * if commercial version of the product was purchased.
 * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
 */

namespace Aurora\System;

/**
 * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
 * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
 * @copyright Copyright (c) 2018, Afterlogic Corp.
 */
if (!defined('AU_APP_ROOT_PATH'))
{
	define('AU_APP_ROOT_PATH', rtrim(realpath(dirname(__DIR__)), '\\/').'/');
	define('AU_APP_START', microtime(true));
}

define('AU_API_PATH_TO_AURORA', '/../');

define('AU_API_CRLF', "\r\n");
define('AU_API_TAB', "\t");

define('AU_API_SESSION_WEBMAIL_NAME', 'PHPWEBMAILSESSID');

define('AU_API_HELPDESK_PUBLIC_NAME', '_helpdesk_');

// timezone fix
$sDefaultTimeZone = function_exists('date_default_timezone_get')
	? @date_default_timezone_get() : 'US/Pacific';

define('AU_API_SERVER_TIME_ZONE', ($sDefaultTimeZone && 0 < strlen($sDefaultTimeZone))
	? $sDefaultTimeZone : 'US/Pacific');

if (defined('AU_API_SERVER_TIME_ZONE') && function_exists('date_default_timezone_set'))
{
	@date_default_timezone_set(AU_API_SERVER_TIME_ZONE);
}

unset($sDefaultTimeZone);


/**
 * @package Api
 */
class Api
{
	/**
	 * @var \Aurora\System\Module\Manager
	 */
	static $oModuleManager;

	/**
	 * @var array
	 */
	static $aModuleDecorators;

	/**
	 * @var array
	 */
	static $aSecretWords;
	
	/**
	 * @var bool
	 */
	static $bIsValid;

	/**
	 * @var string
	 */
	static $sSalt;

	/**
	 * @var array
	 */
	static $aI18N;

	/**
	 * @var array
	 */
	static $aClientI18N;

	/**
	 * @var bool
	 */
	static $bUseDbLog;
	
	/**
	 * @var bool
	 */
	static $bDebug = false;
		
	
	/**
	 * @var string
	 */
	public static $sEventLogPrefix = 'event-';
	
	/**
	 * @var array
	 */
	protected static $aUserSession = array();
	
	/**
	 * @var bool
	 */
	protected static $__SKIP_CHECK_USER_ROLE__ = false;
	
	/**
	 * @var string 
	 */
	protected static $sLanguage = null;
	
	/**
	 * @var \Aurora\System\Settings
	 */
	protected static $oSettings;	

	/**
	 * @var \Aurora\System\Db\Storage
	 */
	protected static $oConnection;	
	
	/**
	 * 
	 * @return string
	 */
	public static function GetSaltPath()
	{
		return self::DataPath().'/salt8.php';
	}
	
	/**
	 * 
	 */
	public static function InitSalt()
	{
		$sSalt = '';
		$sSalt8File = self::GetSaltPath();
		$sSaltFile = self::DataPath().'/salt.php';

		if (!@file_exists($sSalt8File)) 
		{
			if (@file_exists($sSaltFile))
			{
				$sSalt = md5(@file_get_contents($sSaltFile));
				@unlink($sSaltFile);
			}
			else
			{
				$sSalt = base64_encode(microtime(true).rand(1000, 9999).microtime(true).rand(1000, 9999));
			}
			$sSalt = '<?php \\Aurora\\System\\Api::$sSalt = "'. $sSalt . '";';
			@file_put_contents($sSalt8File, $sSalt);
		}
		
		include_once $sSalt8File;
		self::$sSalt = '$2y$07$' . self::$sSalt . '$';
	}
	
	/**
	 * 
	 */
	public static function GrantAdminPrivileges()
	{
		self::$aUserSession['UserId'] = -1;
		self::$aUserSession['AuthToken'] = '';
	}
	
	public static function UseDbLogs($bUseDbLogs = false)
	{
		self::$bUseDbLog = $bUseDbLogs;
	}
	
	/**
	 * 
	 * @param type $bGrantAdminPrivileges
	 */
	public static function Init($bGrantAdminPrivileges = false)
	{
		include_once self::GetVendorPath().'autoload.php';
		
		if ($bGrantAdminPrivileges)
		{
			self::GrantAdminPrivileges();
		}

		self::$aI18N = null;
		self::$aClientI18N = array();
		self::$aSecretWords = array();
		self::$bUseDbLog = false;

		if (!is_object(self::$oModuleManager)) 
		{
			self::InitSalt();

			self::validateApi();
			self::GetModuleManager()->loadModules();
			
			self::removeOldLogs();
		}
	}

	/**
	 * 
	 * @param type $bSkip
	 * @return bool Previous state
	 */
	public static function skipCheckUserRole($bSkip)
	{
		$bResult = self::$__SKIP_CHECK_USER_ROLE__;
		self::$__SKIP_CHECK_USER_ROLE__ = $bSkip;
		return $bResult;
	}
	
	public static function accessCheckIsSkipped()
	{
		return self::$__SKIP_CHECK_USER_ROLE__;
	}
	
	/**
	 * @param string $sWord
	 *
	 * @return bool
	 */
	public static function AddSecret($sWord)
	{
		if (0 < \strlen(\trim($sWord))) 
		{
			self::$aSecretWords[] = $sWord;
			self::$aSecretWords = \array_unique(self::$aSecretWords);
		}
	}
	
	/**
	 * @return string
	 */
	public static function EncodeKeyValues(array $aValues)
	{
		return Utils::UrlSafeBase64Encode(
			Utils\Crypt::XxteaEncrypt(
				@\serialize($aValues), 
				\md5(self::$sSalt)
			)
		);
	}

	/**
	 * @return array
	 */
	public static function DecodeKeyValues($sEncodedValues)
	{
		$aResult = @\unserialize(
			Utils\Crypt::XxteaDecrypt(
			Utils::UrlSafeBase64Decode($sEncodedValues), \md5(self::$sSalt))
		);

		return \is_array($aResult) ? $aResult : array();
	}

	/**
	 * 
	 * @return \Aurora\System\Module\Manager
	 */
	public static function GetModuleManager()
	{
		if (!isset(self::$oModuleManager))
		{
			self::$oModuleManager = Module\Manager::createInstance();
			self::$aModuleDecorators = [];
		}
		
		return self::$oModuleManager;
	}
	
	/**
	 * 
	 * @param string $sModuleName
	 * @param int $iUser
	 * @return type
	 */
	public static function GetModuleDecorator($sModuleName, $iUser = null)
	{
		if (!isset(self::$aModuleDecorators[$sModuleName]) && self::GetModule($sModuleName) !== false)
		{
			self::$aModuleDecorators[$sModuleName] = new Module\Decorator($sModuleName, $iUser);
		}
		
		return isset(self::$aModuleDecorators[$sModuleName]) ? self::$aModuleDecorators[$sModuleName] : false;
	}

	/**
	 * 
	 * @param type $sModuleName
	 * @return type
	 */
	public static function GetModule($sModuleName)
	{
		return self::GetModuleManager()->GetModule($sModuleName);
	}
	
	public static function GetModules()
	{
		return self::GetModuleManager()->GetModules();
	}	

	/**
	 * 
	 * @param type $sMethodName
	 * @param type $aParameters
	 * @return type
	 */
	public static function ExecuteMethod($sMethodName, $aParameters = array())
	{
		list($sModuleName, $sMethodName) = explode(Module\AbstractModule::$Delimiter, $sMethodName);
		$oModule = self::GetModule($sModuleName);
		if ($oModule instanceof Module\AbstractModule)
		{
			return $oModule->CallMethod($sModuleName, $sMethodName, $aParameters);
		}
	}

	/**
	 * @return \MailSo\Cache\CacheClient
	 */
	public static function Cacher()
	{
		static $oCacher = null;
		if (null === $oCacher)
		{
			$oCacher = \MailSo\Cache\CacheClient::NewInstance();
			$oCacher->SetDriver(\MailSo\Cache\Drivers\File::NewInstance(self::DataPath().'/cache'));
			$oCacher->SetCacheIndex(self::Version());
		}

		return $oCacher;
	}
	
	/**
	 * @return \MailSo\Cache\CacheClient
	 */
	public static function UserSession()
	{
		static $oSession = null;
		if (null === $oSession)
		{
			$oSession = new UserSession();
		}

		return $oSession;
	}	

	/**
	 * @return \Aurora\System\Settings
	 */
	public static function &GetSettings()
	{
		if (null === self::$oSettings)
		{
			try
			{
				$sSettingsPath = \Aurora\System\Api::DataPath() . '/settings/';
				if (!\file_exists($sSettingsPath))
				{
					set_error_handler(function() {});					
					mkdir($sSettingsPath, 0777);
					restore_error_handler();
					if (!file_exists($sSettingsPath))
					{
						self::$oSettings = false;
						return self::$oSettings;
					}
				}
				
				self::$oSettings = new \Aurora\System\Settings($sSettingsPath . 'config.json');
			}
			catch (\Aurora\System\Exceptions\BaseException $oException)
			{
				self::$oSettings = false;
			}
		}
		return self::$oSettings;		
	}
	
	public static function &GetConnection()
	{
		if (null === self::$oConnection)
		{
			$oSettings =& self::GetSettings();

			if ($oSettings)
			{
				self::$oConnection = new \Aurora\System\Db\Storage($oSettings);
			}
			else
			{
				self::$oConnection = false;
			}
		}
		return self::$oConnection;
	}	

	/**
	 * @return PDO|false
	 */
	public static function GetPDO()
	{
		static $oPdoCache = null;
		if (null !== $oPdoCache)
		{
			return $oPdoCache;
		}

		$oPdo = false;
		$oSettings = &self::GetSettings();
		if ($oSettings)
		{
			$sDbPort = '';
			$sUnixSocket = '';

			$iDbType = $oSettings->DBType;
			$sDbHost = $oSettings->DBHost;
			$sDbName = $oSettings->DBName;
			$sDbLogin = $oSettings->DBLogin;
			$sDbPassword = $oSettings->DBPassword;

			$iPos = strpos($sDbHost, ':');
			if (false !== $iPos && 0 < $iPos) 
			{
				$sAfter = substr($sDbHost, $iPos + 1);
				$sDbHost = substr($sDbHost, 0, $iPos);

				if (is_numeric($sAfter)) 
				{
					$sDbPort = $sAfter;
				} 
				else 
				{
					$sUnixSocket = $sAfter;
				}
			}

			if (class_exists('PDO')) 
			{
				try
				{
					$oPdo = @new \PDO((Enums\DbType::PostgreSQL === $iDbType ? 'pgsql' : 'mysql').':dbname='.$sDbName.
						(empty($sDbHost) ? '' : ';host='.$sDbHost).
						(empty($sDbPort) ? '' : ';port='.$sDbPort).
						(empty($sUnixSocket) ? '' : ';unix_socket='.$sUnixSocket), $sDbLogin, $sDbPassword);

					if ($oPdo) 
					{
						$oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
					}
				}
				catch (\Exception $oException)
				{
					self::Log($oException->getMessage(), Enums\LogLevel::Error);
					self::Log($oException->getTraceAsString(), Enums\LogLevel::Error);
					$oPdo = false;
				}
			} 
			else 
			{
				self::Log('Class PDO dosn\'t exist', Enums\LogLevel::Error);
			}
		}

		if (false !== $oPdo) 
		{
			$oPdoCache = $oPdo;
		}

		return $oPdo;
	}

	/**
	 * @return bool
	 */
	public static function IsMobileApplication()
	{
		/* @var $oIntegrator \Aurora\System\Managers\Integrator */
		$oIntegrator = \Aurora\System\Managers\Integrator::getInstance();

		return (bool) $oIntegrator /*&& $oApiCapability->isNotLite()*/ && 1 === $oIntegrator->isMobile(); // todo
	}
	
	/**
	 * @param string $sNewLocation
	 */
	public static function Location($sNewLocation)
	{
		self::Log('Location: '.$sNewLocation);
		@header('Location: '.$sNewLocation);
	}
	
	/**
	 * @param string $sNewLocation
	 */
	public static function Location2($sNewLocation)
	{
		exit('<META HTTP-EQUIV="refresh" CONTENT="0; url='.$sNewLocation.'">');		
	}

	/**
	 * @param string $sDesc
	 * @param string $sModuleName
	 */
	public static function LogEvent($sDesc, $sModuleName = '')
	{
		$oSettings = &self::GetSettings();
		if ($oSettings && $oSettings->EnableEventLogging) 
		{
			$sDate = gmdate('H:i:s');
			$iIp = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown';
			$sUserId = self::getAuthenticatedUserId();

			self::Log('Event: '.$sUserId.' > '.$sDesc);
			self::LogOnly('['.$sDate.']['.$iIp.']['.$sUserId.']['.$sModuleName.'] > '.$sDesc, self::GetLogFileDir().self::GetLogFileName(self::$sEventLogPrefix));
		}
	}

	/**
	 * @param mixed $mObject
	 * @param int $iLogLevel = \Aurora\System\Enums\LogLevel::Full
	 * @param string $sFilePrefix = ''
	 */
	public static function LogObject($mObject, $iLogLevel = Enums\LogLevel::Full, $sFilePrefix = '')
	{
		self::Log(print_r($mObject, true), $iLogLevel, $sFilePrefix);
	}

	/**
	 * @param Exception $mObject
	 * @param int $iLogLevel = \Aurora\System\Enums\LogLevel::Error
	 * @param string $sFilePrefix = ''
	 */
	public static function LogException($mObject, $iLogLevel = Enums\LogLevel::Error, $sFilePrefix = '')
	{
		$sMessage = '';

		$oSettings =& self::GetSettings();
		if ($oSettings && $oSettings->GetValue('LogStackTrace', false))
		{
			$sMessage = (string) $mObject;
		}
		else
		{
			$sMessage = $mObject->getMessage();
		}		
		
		if (0 < \count(self::$aSecretWords)) 
		{
			$sMessage = \str_replace(self::$aSecretWords, '*******', $sMessage);
		}
		
		self::Log($sMessage, $iLogLevel, $sFilePrefix);
	}

	/**
	 * @param string $sFilePrefix = ''
	 *
	 * @return string
	 */
	public static function GetLogFileName($sFilePrefix = '', $iTimestamp = 0)
	{
		$oSettings =& self::GetSettings();

		$sFileName = "log.txt";
		
		if ($oSettings && $oSettings->LogFileName)
		{
			$fCallback = ($iTimestamp === 0) 
					? function ($matches) {return date($matches[1]);} 
					: function ($matches) use ($iTimestamp) {return date($matches[1], $iTimestamp);};
			$sFileName = preg_replace_callback('/\{([\w|-]*)\}/', $fCallback, $oSettings->LogFileName);
		}
		
		return $sFilePrefix.$sFileName;
	}
	
	public static function GetLogFileDir()
	{
		static $bDir = null;
		static $sLogDir = null;

		if (null === $sLogDir) 
		{
			$oSettings =& self::GetSettings();
			if ($oSettings)
			{
				$sS = $oSettings->GetValue('LogCustomFullPath', '');
				$sLogDir = empty($sS) ?self::DataPath().'/logs/' : rtrim(trim($sS), '\\/').'/';
			}
		}
		
		if (null === $bDir) 
		{
			$bDir = true;
			if (!@is_dir($sLogDir)) 
			{
				@mkdir($sLogDir, 0777);
			}
		}
		
		return $sLogDir;
	}

	/**
	 * @return \MailSo\Log\Logger
	 */
	public static function SystemLogger()
	{
		static $oLogger = null;
		if (null === $oLogger) 
		{
			$oLogger = \MailSo\Log\Logger::NewInstance()
				->Add(
					\MailSo\Log\Drivers\Callback::NewInstance(function ($sDesc) {
						self::Log($sDesc);
					})->DisableTimePrefix()->DisableGuidPrefix()
				)
				->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME)
			;
		}

		return $oLogger;
	}

	/**
	 * @param string $sDesc
	 * @param string $sLogFile
	 */
	private static function dbDebugBacktrace($sDesc, $sLogFile)
	{
		static $iDbBacktraceCount = null;
		
		if (null === $iDbBacktraceCount) 
		{
			$oSettings =& Api::GetSettings();
			$iDbBacktraceCount = (int) $oSettings->GetValue('DBDebugBacktraceLimit', 0);
			if (!function_exists('debug_backtrace') || version_compare(PHP_VERSION, '5.4.0') < 0) 
			{
				$iDbBacktraceCount = 0;
			}
		}

		if (0 < $iDbBacktraceCount && is_string($sDesc) && 
				(false !== strpos($sDesc, 'DB[') || false !== strpos($sDesc, 'DB ERROR'))) 
		{
			$bSkip = true;
			$sLogData = '';
			$iCount = $iDbBacktraceCount;

			foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 20) as $aData) 
			{
				if ($aData && isset($aData['function']) && !in_array(strtolower($aData['function']), array(
					'log', 'logonly', 'logend', 'logevent', 'logexception', 'logobject', 'dbdebugbacktrace')))	
				{
					$bSkip = false;
				}

				if (!$bSkip) 
				{
					$iCount--;
					if (isset($aData['class'], $aData['type'], $aData['function'])) 
					{
						$sLogData .= $aData['class'].$aData['type'].$aData['function'];
					} 
					else if (isset($aData['function'])) 
					{
						$sLogData .= $aData['function'];
					}

					if (isset($aData['file'])) 
					{
						$sLogData .= ' ../'.basename($aData['file']);
					}
					if (isset($aData['line'])) 
					{
						$sLogData .= ' *'.$aData['line'];
					}

					$sLogData .= "\n";
				}

				if (0 === $iCount) 
				{
					break;
				}
			}

			if (0 < strlen($sLogData)) 
			{
				try
				{
					@error_log('['.\MailSo\Log\Logger::Guid().'][DB/backtrace]'.AU_API_CRLF.trim($sLogData).AU_API_CRLF, 3, $sLogFile);
				}
				catch (Exception $oE) {}
			}
		}
	}

	/**
	 * @param string $sDesc
	 * @param int $iLogLevel = \Aurora\System\Enums\LogLevel::Full
	 * @param string $sFilePrefix = ''
	 * @param bool $bIdDb = false
	 */
	public static function Log($sDesc, $iLogLevel = Enums\LogLevel::Full, $sFilePrefix = '')
	{
		static $bIsFirst = true;

		$oSettings = &self::GetSettings();

		if ($oSettings && $oSettings->EnableLogging && $iLogLevel <= $oSettings->LoggingLevel) 
		{
			try 
			{
				$oAuthenticatedUser = self::getAuthenticatedUser();
			}
			catch (\Exception $oEx)
			{
				$oAuthenticatedUser = false;
			}
			$sFirstPrefix = $oAuthenticatedUser && $oAuthenticatedUser->WriteSeparateLog ? $oAuthenticatedUser->PublicId . '-' : '';
			$sLogFile = self::GetLogFileDir() . self::GetLogFileName($sFirstPrefix . $sFilePrefix);

			$sGuid = \MailSo\Log\Logger::Guid();
			$aMicro = explode('.', microtime(true));
			$sDate = gmdate('H:i:s.').str_pad((isset($aMicro[1]) ? substr($aMicro[1], 0, 2) : '0'), 2, '0');
			if ($bIsFirst) 
			{
				$sUri = Utils::RequestUri();
				$bIsFirst = false;
				$sPost = (isset($_POST) && count($_POST) > 0) ? '[POST('.count($_POST).')]' : '[GET]';

				self::LogOnly(AU_API_CRLF.'['.$sDate.']['.$sGuid.'] '.$sPost.'[ip:'.(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown').'] '.$sUri, $sLogFile);
				if (!empty($sPost)) 
				{
					if ($oSettings->GetValue('LogPostView', false)) 
					{
						self::LogOnly('['.$sDate.']['.$sGuid.'] POST > '.print_r($_POST, true), $sLogFile);
					} 
					else 
					{
						self::LogOnly('['.$sDate.']['.$sGuid.'] POST > ['.implode(', ', array_keys($_POST)).']', $sLogFile);
					}
				}
				self::LogOnly('['.$sDate.']['.$sGuid.']', $sLogFile);
			}

			self::LogOnly('['.$sDate.']['.$sGuid.'] '.(is_string($sDesc) ? $sDesc : print_r($sDesc, true)), $sLogFile);
		}
	}

	/**
	 * @param string $sDesc
	 * @param string $sLogFile
	 */
	public static function LogOnly($sDesc, $sLogFile)
	{
		try
		{
			@error_log($sDesc.AU_API_CRLF, 3, $sLogFile);
		}
		catch (Exception $oE) {}

		self::dbDebugBacktrace($sDesc, $sLogFile);
	}

	public static function ClearLog($sFileFullPath)
	{
		return (@file_exists($sFileFullPath)) ? @unlink($sFileFullPath) : true;
	}
	
	public static function RemoveSeparateLogs()
	{
		$sLogDir = self::GetLogFileDir();
		$sLogFile = self::GetLogFileName();
		if (is_dir($sLogDir))
		{
			$aLogFiles = array_diff(scandir($sLogDir), array('..', '.'));
			foreach($aLogFiles as $sFileName)
			{
				if ($sFileName !== $sLogFile && $sFileName !== (self::$sEventLogPrefix . $sLogFile) && strpos($sFileName, $sLogFile) !== false)
				{
					unlink($sLogDir.$sFileName);
				}
			}
		}
	}

	private static function removeOldLogs()
	{
		$sLogDir = self::GetLogFileDir();
		$sLogFile = self::GetLogFileName();
		$oSettings = &self::GetSettings();
		
		if ($oSettings)
		{
			$bRemoveOldLogs = $oSettings->GetValue('RemoveOldLogs', true);

			if (is_dir($sLogDir) && $bRemoveOldLogs/* && !file_exists($sLogDir.$sLogFile)*/)
			{
				$sYesterdayLogFile = self::GetLogFileName('', time() - 60 * 60 * 24);
				$aLogFiles = array_diff(scandir($sLogDir), array('..', '.'));
				foreach($aLogFiles as $sFileName)
				{
					if (strpos($sFileName, $sLogFile) === false && strpos($sFileName, $sYesterdayLogFile) === false)
					{
						unlink($sLogDir.$sFileName);
					}
				}
			}
		}
	}

	/**
	 * @return string
	 */
	public static function RootPath()
	{
		defined('AU_API_ROOTPATH') || define('AU_API_ROOTPATH', rtrim(dirname(__FILE__), '/\\').'/');
		return AU_API_ROOTPATH;
	}

	/**
	 * @return string
	 */
	public static function WebMailPath()
	{
		return self::RootPath().ltrim(AU_API_PATH_TO_AURORA, '/');
	}

	/**
	 * @return string
	 */
	public static function GetVendorPath()
	{
		return self::RootPath().'../vendor/';
	}

	/**
	 * @return string
	 */
	public static function VersionFull()
	{
		static $sVersion = null;
		$sAppVersion = @file_get_contents(self::WebMailPath().'VERSION');

		$sVersion = (empty($sAppVersion)) ? '0.0.0' : $sAppVersion;

		return $sVersion;
	}

	/**
	 * @return string
	 */
	public static function Version()
	{
		static $sVersion = null;
		if (null === $sVersion) 
		{
			preg_match('/[\d\.]+/', @file_get_contents(self::WebMailPath().'VERSION'), $matches);

			if (isset($matches[0]))
			{
				$sAppVersion = preg_replace('/[^0-9]/', '', $matches[0]);
			}

			$sVersion = (empty($sAppVersion)) ? '0.0.0' : $sAppVersion;
		}
		return $sVersion;
	}

	/**
	 * @return string
	 */
	public static function VersionJs()
	{
		$oSettings = &self::GetSettings();
		$sAppVersion = @file_get_contents(self::WebMailPath().'VERSION');
		$sAppVersion = empty($sAppVersion) ? '0.0.0' : $sAppVersion;
		
		return preg_replace('/[^0-9]/', '',$sAppVersion);
	}

	/**
	 * @return string
	 */
	public static function DataPath()
	{
		$dataPath = 'data';
		if (!defined('AU_API_DATA_FOLDER') && @file_exists(self::WebMailPath().'inc_settings_path.php')) 
		{
			include self::WebMailPath().'inc_settings_path.php';
		}
		if (!defined('AU_API_DATA_FOLDER') && isset($dataPath) && null !== $dataPath) 
		{
			define('AU_API_DATA_FOLDER', Utils::GetFullPath($dataPath,self::WebMailPath()));
		}
		$sDataFullPath = defined('AU_API_DATA_FOLDER') ? AU_API_DATA_FOLDER : '';

/*
		if (!\file_exists($sDataFullPath))
		{
			\mkdir($sDataFullPath, 0777);
		}
*/
		return $sDataFullPath;
	}

	/**
	 * @return bool
	 */
	protected static function validateApi()
	{
		$iResult = 1;

		$oSettings = &self::GetSettings();
		$iResult &= $oSettings && ($oSettings instanceof AbstractSettings);

		self::$bIsValid = (bool) $iResult;
	}

	/**
	 * @return bool
	 */
	public static function IsValid()
	{
		return (bool)self::$bIsValid;
	}

	/**
	 * @param string $sEmail
	 * @param string $sPassword
	 * @param string $sLogin = ''
	 * @return string
	 */
	public static function GenerateSsoToken($sEmail, $sPassword, $sLogin = '')
	{
		$sSsoHash = \md5($sEmail.$sPassword.$sLogin.\microtime(true).\rand(10000, 99999));
		return self::Cacher()->Set('SSO:'.$sSsoHash, self::EncodeKeyValues(array(
			'Email' => $sEmail,
			'Password' => $sPassword,
			'Login' => $sLogin
		))) ? $sSsoHash : '';
	}

	/**
	 * @param string $sLangFile
	 * @return array
	 */
	public static function convertIniToLang($sLangFile)
	{
		$aResultLang = false;

		$aLang = @\parse_ini_string(file_get_contents($sLangFile), true);
		if (is_array($aLang)) 
		{
			$aResultLang = array();
			foreach ($aLang as $sKey => $mValue) 
			{
				if (\is_array($mValue)) 
				{
					foreach ($mValue as $sSecKey => $mSecValue) 
					{
						$aResultLang[$sKey.'/'.$sSecKey] = $mSecValue;
					}
				} 
				else 
				{
					$aResultLang[$sKey] = $mValue;
				}
			}
		}

		return $aResultLang;
	}

	/**
	 * @param mixed $mLang
	 * @param string $sData
	 * @param array|null $aParams = null
	 * @return array
	 */
	public static function processTranslateParams($mLang, $sData, $aParams = null, $iPlural = null)
	{
		$sResult = $sData;
		if ($mLang && isset($mLang[$sData])) 
		{
			$sResult = $mLang[$sData];
		}

		if (isset($iPlural)) 
		{
			$aPluralParts = explode('|', $sResult);

			$sResult = ($aPluralParts && $aPluralParts[$iPlural]) ? $aPluralParts[$iPlural] : (
			$aPluralParts && $aPluralParts[0] ? $aPluralParts[0] : $sResult);
		}

		if (null !== $aParams && is_array($aParams)) 
		{
			foreach ($aParams as $sKey => $sValue) 
			{
				$sResult = str_replace('%'.$sKey.'%', $sValue, $sResult);
			}
		}

		return $sResult;
	}
	
	/**
	 * 
	 * @param string $sLanguage
	 */
	public static function SetLanguage($sLanguage)
	{
		self::$sLanguage = $sLanguage;
	}		

	/**
	 * 
	 * @param bool $bForNewUser
	 * @return string
	 */
	public static function GetLanguage($bForNewUser = false)
	{
		$sResult = null;
		if (isset(self::$sLanguage))
		{
			$sResult = self::$sLanguage;
		}
		else
		{
			$iAuthUserId = self::getAuthenticatedUserId();
			$bSuperAdmin = $iAuthUserId === -1;
			$oModuleManager = self::GetModuleManager();

			$sResult = $oModuleManager->getModuleConfigValue('Core', 'Language');
			if ($oModuleManager->getModuleConfigValue('Core', 'AutodetectLanguage', true))
			{
				$sResult = self::getBrowserLanguage();
			}

			if ($bSuperAdmin)
			{
				$oSettings = &self::GetSettings();
				$sResult = $oSettings->AdminLanguage;
			}
			else if (!$bForNewUser)
			{
				$oUser = self::getAuthenticatedUser();
				if ($oUser)
				{
					$sResult = $oUser->Language;
				}
				else if (isset($_COOKIE['aurora-lang-on-login']))
				{
					$sResult = $_COOKIE['aurora-lang-on-login'];
				}
			}
		}
		
		return $sResult;
	}
	
	protected static function getBrowserLanguage()
	{
		$aLanguages = array(
			'ar-dz' => 'Arabic', 'ar-bh' => 'Arabic', 'ar-eg' => 'Arabic', 'ar-iq' => 'Arabic', 'ar-jo' => 'Arabic', 'ar-kw' => 'Arabic',
			'ar-lb' => 'Arabic', 'ar-ly' => 'Arabic', 'ar-ma' => 'Arabic', 'ar-om' => 'Arabic', 'ar-qa' => 'Arabic', 'ar-sa' => 'Arabic',
			'ar-sy' => 'Arabic', 'ar-tn' => 'Arabic', 'ar-ae' => 'Arabic', 'ar-ye' => 'Arabic', 'ar' => 'Arabic',
			'bg' => 'Bulgarian',
			'zh-cn' => 'Chinese-Simplified', 'zh-hk' => 'Chinese-Simplified', 'zh-mo' => 'Chinese-Simplified', 'zh-sg' => 'Chinese-Simplified',
			'zh-tw' => 'Chinese-Simplified', 'zh' => 'Chinese-Simplified',
			'cs' => 'Czech',
			'da' => 'Danish',
			'nl-be' => 'Dutch', 'nl' => 'Dutch',
			'en-au' => 'English', 'en-bz' => 'English ', 'en-ca' => 'English', 'en-ie' => 'English', 'en-jm' => 'English',
			'en-nz' => 'English', 'en-ph' => 'English', 'en-za' => 'English', 'en-tt' => 'English', 'en-gb' => 'English',
			'en-us' => 'English', 'en-zw' => 'English', 'en' => 'English', 'us' => 'English',
			'et' => 'Estonian', 'fi' => 'Finnish',
			'fr-be' => 'French', 'fr-ca' => 'French', 'fr-lu' => 'French', 'fr-mc' => 'French', 'fr-ch' => 'French', 'fr' => 'French',
			'de-at' => 'German', 'de-li' => 'German', 'de-lu' => 'German', 'de-ch' => 'German', 'de' => 'German',
			'el' => 'Greek', 'he' => 'Hebrew', 'hu' => 'Hungarian', 'it-ch' => 'Italian', 'it' => 'Italian',
			'ja' => 'Japanese', 'ko' => 'Korean', 'lv' => 'Latvian', 'lt' => 'Lithuanian',
			'nb-no' => 'Norwegian', 'nn-no' => 'Norwegian', 'no' => 'Norwegian', 'pl' => 'Polish',
			'pt-br' => 'Portuguese-Brazil', 'pt' => 'Portuguese-Portuguese', 'pt-pt' => 'Portuguese-Portuguese',
			'ro-md' => 'Romanian', 'ro' => 'Romanian',
			'ru-md' => 'Russian', 'ru' => 'Russian', 'sr' => 'Serbian',
			'es-ar' => 'Spanish', 'es-bo' => 'Spanish', 'es-cl' => 'Spanish', 'es-co' => 'Spanish', 'es-cr' => 'Spanish',
			'es-do' => 'Spanish', 'es-ec' => 'Spanish', 'es-sv' => 'Spanish', 'es-gt' => 'Spanish', 'es-hn' => 'Spanish)',
			'es-mx' => 'Spanish', 'es-ni' => 'Spanish', 'es-pa' => 'Spanish', 'es-py' => 'Spanish', 'es-pe' => 'Spanish',
			'es-pr' => 'Spanish', 'es-us' => 'Spanish ', 'es-uy' => 'Spanish', 'es-ve' => 'Spanish', 'es' => 'Spanish',
			'sv-fi' => 'Swedish', 'sv' => 'Swedish', 'th' => 'Thai', 'tr' => 'Turkish', 'uk' => 'Ukrainian', 'vi' => 'Vietnamese', 'sl' => 'Slovenian'
		);
		
		$sLanguage = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']) : 'en';
		$aTempLanguages = preg_split('/[,;]+/', $sLanguage);
		$sLanguage = !empty($aTempLanguages[0]) ? $aTempLanguages[0] : 'en';

		$sLanguageShort = substr($sLanguage, 0, 2);
		
		return \array_key_exists($sLanguage, $aLanguages) ? $aLanguages[$sLanguage] :
			(\array_key_exists($sLanguageShort, $aLanguages) ? $aLanguages[$sLanguageShort] : '');
	}
	
	/**
	 * @param string $sData
	 * @param \Aurora\Modules\StandardAuth\Classes\Account $oAccount
	 * @param array $aParams = null
	 *
	 * @return string
	 */
	public static function ClientI18N($sData, $oAccount = null, $aParams = null, $iPluralCount = null)
	{
		$sLanguage = self::GetLanguage();
		
		$aLang = null;
		if (isset(self::$aClientI18N[$sLanguage])) 
		{
			$aLang = self::$aClientI18N[$sLanguage];
		} 
		else 
		{
			self::$aClientI18N[$sLanguage] = false;
				
			$sLangFile = self::WebMailPath().'i18n/'.$sLanguage.'.ini';
			if (!@file_exists($sLangFile)) 
			{
				$sLangFile = self::WebMailPath().'i18n/English.ini';
				$sLangFile = @file_exists($sLangFile) ? $sLangFile : '';
			}

			if (0 < strlen($sLangFile)) 
			{
				$aLang = self::convertIniToLang($sLangFile);
				if (is_array($aLang)) 
				{
					self::$aClientI18N[$sLanguage] = $aLang;
				}
			}
		}

		//return self::processTranslateParams($aLang, $sData, $aParams);
		return isset($iPluralCount) ? self::processTranslateParams($aLang, $sData, $aParams, self::getPlural($sLanguage, $iPluralCount)) : self::processTranslateParams($aLang, $sData, $aParams);
	}

	public static function getPlural($sLang = '', $iNumber = 0)
	{
		$iResult = 0;
		$iNumber = (int) $iNumber;

		switch ($sLang)
		{
			case 'Arabic':
				$iResult = ($iNumber === 0 ? 0 : $iNumber === 1 ? 1 : ($iNumber === 2 ? 2 : ($iNumber % 100 >= 3 && $iNumber % 100 <= 10 ? 3 : ($iNumber % 100 >= 11 ? 4 : 5))));
				break;
			case 'Bulgarian':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Chinese-Simplified':
				$iResult = 0;
				break;
			case 'Chinese-Traditional':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Czech':
				$iResult = ($iNumber === 1) ? 0 : (($iNumber >= 2 && $iNumber <= 4) ? 1 : 2);
				break;
			case 'Danish':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Dutch':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'English':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Estonian':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Finnish':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'French':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'German':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Greek':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Hebrew':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Hungarian':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Italian':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Japanese':
				$iResult = 0;
				break;
			case 'Korean':
				$iResult = 0;
				break;
			case 'Latvian':
				$iResult = ($iNumber % 10 === 1 && $iNumber % 100 !== 11 ? 0 : ($iNumber !== 0 ? 1 : 2));
				break;
			case 'Lithuanian':
				$iResult = ($iNumber % 10 === 1 && $iNumber % 100 !== 11 ? 0 : ($iNumber % 10 >= 2 && ($iNumber % 100 < 10 || $iNumber % 100 >= 20) ? 1 : 2));
				break;
			case 'Norwegian':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Persian':
				$iResult = 0;
				break;
			case 'Polish':
				$iResult = ($iNumber === 1 ? 0 : ($iNumber % 10 >= 2 && $iNumber % 10 <= 4 && ($iNumber % 100 < 10 || $iNumber % 100 >= 20) ? 1 : 2));
				break;
			case 'Portuguese-Portuguese':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Portuguese-Brazil':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Romanian':
				$iResult = ($iNumber === 1 ? 0 : (($iNumber === 0 || ($iNumber % 100 > 0 && $iNumber % 100 < 20)) ? 1 : 2));
				break;
			case 'Russian':
				$iResult = ($iNumber % 10 === 1 && $iNumber % 100 !== 11 ? 0 : ($iNumber % 10 >= 2 && $iNumber % 10 <= 4 && ($iNumber % 100 < 10 || $iNumber % 100 >= 20) ? 1 : 2));
				break;
			case 'Serbian':
				$iResult = ($iNumber % 10 === 1 && $iNumber % 100 !== 11 ? 0 : ($iNumber % 10 >= 2 && $iNumber % 10 <= 4 && ($iNumber % 100 < 10 || $iNumber % 100 >= 20) ? 1 : 2));
				break;
			case 'Slovenian':
				$iResult = (($iNumber % 10 === 1 && $iNumber % 100 !== 11) ? 0 : (($iNumber % 10 === 2 && $iNumber % 100 !== 12) ? 1 : 2));
				break;
			case 'Spanish':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Swedish':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Thai':
				$iResult = 0;
				break;
			case 'Turkish':
				$iResult = ($iNumber === 1 ? 0 : 1);
				break;
			case 'Ukrainian':
				$iResult = ($iNumber % 10 === 1 && $iNumber % 100 !== 11 ? 0 : ($iNumber % 10 >= 2 && $iNumber % 10 <= 4 && ($iNumber % 100 < 10 || $iNumber % 100 >= 20) ? 1 : 2));
				break;
			case 'Vietnamese':
				$iResult = 0;
				break;
			default:
				$iResult = 0;
				break;
		}

		return $iResult;
	}

	/**
	 * @param string $sData
	 * @param array $aParams = null
	 *
	 * @return string
	 */
	public static function I18N($sData, $aParams = null, $sForceCustomInitialisationLang = '')
	{
		if (null === self::$aI18N) 
		{
			self::$aI18N = false;

			$sLangFile = '';
			if (0 < strlen($sForceCustomInitialisationLang))
			{
				$sLangFile = self::RootPath().'common/i18n/'.$sForceCustomInitialisationLang.'.ini';
			}

			if (0 === strlen($sLangFile) || !@file_exists($sLangFile))
			{
				$sLangFile = self::RootPath().'common/i18n/English.ini';
			}

			if (0 < strlen($sLangFile) && @file_exists($sLangFile))
			{
				$aResultLang = self::convertIniToLang($sLangFile);
				if (is_array($aResultLang))
				{
					self::$aI18N = $aResultLang;
				}
			}
		}

		return self::processTranslateParams(self::$aI18N, $sData, $aParams);
	}
	
	/**
	 * Checks if authenticated user has at least specified role.
	 * @param int $iRole
	 * @throws \Aurora\System\Exceptions\ApiException
	 */
	public static function checkUserRoleIsAtLeast($iRole)
	{
		if (!self::$__SKIP_CHECK_USER_ROLE__)
		{
			$oUser = self::getAuthenticatedUser();
			$bUserRoleIsAtLeast = empty($oUser) && $iRole === Enums\UserRole::Anonymous ||
				!empty($oUser) && $oUser->Role === Enums\UserRole::Customer && 
					($iRole === Enums\UserRole::Customer || $iRole === Enums\UserRole::Anonymous) ||
				!empty($oUser) && $oUser->Role === Enums\UserRole::NormalUser && 
					($iRole === Enums\UserRole::NormalUser || $iRole === Enums\UserRole::Customer || $iRole === Enums\UserRole::Anonymous) ||
				!empty($oUser) && $oUser->Role === Enums\UserRole::TenantAdmin && 
					($iRole === Enums\UserRole::TenantAdmin || $iRole === Enums\UserRole::NormalUser || $iRole === Enums\UserRole::Customer || $iRole === Enums\UserRole::Anonymous) ||
				!empty($oUser) && $oUser->Role === Enums\UserRole::SuperAdmin && 
					($iRole === Enums\UserRole::SuperAdmin || $iRole === Enums\UserRole::TenantAdmin || $iRole === Enums\UserRole::NormalUser || $iRole === Enums\UserRole::Customer || $iRole === Enums\UserRole::Anonymous);
			if (!$bUserRoleIsAtLeast)
			{
				throw new Exceptions\ApiException(Notifications::AccessDenied);
			}
		}
	}
	
	public static function getAuthTokenFromHeaders()
	{
		$sResult = false;
		$sAuthHeader =  \MailSo\Base\Http::SingletonInstance()->GetHeader('Authorization');
		if (!empty($sAuthHeader))
		{
			list($sAuthTypeFromHeader, $sAuthTokenFromHeader) = explode(' ', $sAuthHeader);
			if (strtolower($sAuthTypeFromHeader) === 'bearer' && !empty($sAuthTokenFromHeader))
			{
				$sResult = $sAuthTokenFromHeader;
			}
		}	
		
		return $sResult;
	}

	/**
	 * 
	 * @return string
	 */
	public static function getAuthToken()
	{
		$sAuthToken = self::getAuthTokenFromHeaders();
		if (!$sAuthToken)
		{
			$sAuthToken = isset($_COOKIE[Application::AUTH_TOKEN_KEY]) ? 
					$_COOKIE[Application::AUTH_TOKEN_KEY] : '';
		}
		
		return $sAuthToken;
	}		
	
	/**
	 * 
	 * @return bool
	 */
	public static function validateCsrfToken()
	{
		$bResult = true;
		if (isset($_COOKIE[Application::AUTH_TOKEN_KEY]))
		{
			$sAuthToken = self::getAuthTokenFromHeaders();

			$bResult = ($sAuthToken === $_COOKIE[Application::AUTH_TOKEN_KEY]);
		}
		
		return $bResult;
	}		

	/**
	 * 
	 * @return \Aurora\Modules\Core\Classes\User
	 */
	public static function authorise($sAuthToken = '')
	{
		$oUser = null;
		$mUserId = false;
		try
		{
			if (isset(self::$aUserSession['UserId']))
			{
				$mUserId = self::$aUserSession['UserId'];
			}
			else
			{
				$sAuthToken = empty($sAuthToken) ? self::getAuthToken() : $sAuthToken;
				$mUserId = self::getAuthenticatedUserId($sAuthToken);
			}
			$oUser = Managers\Integrator::getInstance()->getAuthenticatedUserByIdHelper($mUserId);
		}
		catch (\Exception $oException) {}
		return $oUser;
	}	
	
	public static function getAuthenticatedUserInfo($sAuthToken = '')
	{
		$mResult = false;
		if (empty($sAuthToken))
		{
			if (is_array(self::$aUserSession) && isset(self::$aUserSession['AuthToken']))
			{
				$sAuthToken = self::$aUserSession['AuthToken'];
			}
		}
		/* @var $oIntegrator \Aurora\System\Managers\Integrator */
		$oIntegrator = \Aurora\System\Managers\Integrator::getInstance();
		if ($oIntegrator)
		{
			$mResult = $oIntegrator->getAuthenticatedUserInfo($sAuthToken);
		}
		
		return $mResult;
	}

	public static function validateAuthToken()
	{
		$bResult = false;
		/* @var $oIntegrator \Aurora\System\Managers\Integrator */
		$oIntegrator = \Aurora\System\Managers\Integrator::getInstance();
		if ($oIntegrator)
		{
			$bResult = $oIntegrator->validateAuthToken(self::getAuthToken());
		}
		
		return $bResult;
	}
	
	public static function getCookiePath()
	{
		static $sPath = false;
		
		if (false === $sPath)
		{
			$sScriptName = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '';
			$aPath = explode('/', $sScriptName);
			$sLastPathItem = count($aPath) > 0 ? $aPath[count($aPath) - 1] : '';
			if (count($aPath) > 0 && ($sLastPathItem !== '' || tolowercase(substr($sLastPathItem, -1)) === '.php'))
			{
				array_pop($aPath);
			}
			$sPath = implode('/', $aPath) . '/';
		}

		return $sPath;
	}
	
	public static function getAuthenticatedUserId($sAuthToken = '')
	{
		$mResult = false;
		if (!empty($sAuthToken))
		{
			if (!empty(self::$aUserSession['UserId']) && self::getAuthenticatedUserAuthToken() === $sAuthToken)
			{
				$mResult = (int) self::$aUserSession['UserId'];
			}
			else
			{
				$aInfo = \Aurora\System\Managers\Integrator::getInstance()->getAuthenticatedUserInfo($sAuthToken);
				$mResult = $aInfo['userId'];
				self::$aUserSession['UserId'] = (int) $mResult;
				self::$aUserSession['AuthToken'] = $sAuthToken;
			}
		}
		else 
		{
			if (is_array(self::$aUserSession) && isset(self::$aUserSession['UserId']))
			{
				$mResult = self::$aUserSession['UserId'];
			}
			else
			{
				$mResult = 0;
			}
		}
		
		return $mResult;
	}
	
	public static function getAuthenticatedUser($sAuthToken = '')
	{
		static $oUser = null;
		$sStoredAuthToken = self::getAuthenticatedUserAuthToken();
		if ($oUser === null || (!empty($sAuthToken) && $sAuthToken !== $sStoredAuthToken))
		{
			$iUserId = 0;
			if (!empty($sAuthToken))
			{
				$iUserId = self::getAuthenticatedUserId($sAuthToken); // called for saving in session
			}
			else if (!empty(self::$aUserSession['UserId']))
			{
				$iUserId = self::$aUserSession['UserId'];
			}

			$oIntegrator = \Aurora\System\Managers\Integrator::getInstance();
			if ($oIntegrator)
			{
				$oUser = $oIntegrator->getAuthenticatedUserByIdHelper($iUserId);
			}
		}
		return $oUser;
	}
	
	public static function getAuthenticatedUserAuthToken()
	{
		$mResult = false;
		
		if (is_array(self::$aUserSession) && isset(self::$aUserSession['AuthToken']))
		{
			$mResult = self::$aUserSession['AuthToken'];
		}
		
		return $mResult;
	}
	
	/**
	 * @param int $iUserId
	 * @return string
	 */
	public static function getUserUUIDById($iUserId)
	{
		$sUUID = '';
		static $aUUIDs = []; // cache
		
		if (\is_numeric($iUserId))
		{
			if (isset($aUUIDs[$iUserId]))
			{
				$sUUID = $aUUIDs[$iUserId];
			}
			else
			{
				$mUser = self::getUserById($iUserId);
				if ($mUser instanceof EAV\Entity)
				{
					$sUUID = $mUser->UUID;
					$aUUIDs[$iUserId] = $sUUID;
				}
			}
		}
		else 
		{
			$sUUID = $iUserId;
		}
		
		return $sUUID;
	}
	
	/**
	 * @param int $iUserId
	 * @return string
	 */
	public static function getUserPublicIdById($iUserId)
	{
		$sPublicId = '';
		
		if (\is_numeric($iUserId))
		{
			$mUser = self::getUserById($iUserId);
			if ($mUser instanceof EAV\Entity)
			{
				$sPublicId = $mUser->PublicId;
			}
		}
		else 
		{
			$sPublicId = $iUserId;
		}
		
		return $sPublicId;
	}	
	
	public static function getUserById($iUserId)
	{
		$mUser = false;

		try
		{
			$mUser = Managers\Integrator::getInstance()->getAuthenticatedUserByIdHelper($iUserId);
			if (!($mUser instanceof \Aurora\Modules\Core\Classes\User))
			{
				$mUser = false;
			}
		}
		catch (\Exception $oEx)
		{
			$mUser = false;
		}
		
		return $mUser;
	}
	
	public static function getTenantById($iUserId)
	{
		$mUser = Managers\Eav::getInstance()->getEntity($iUserId, \Aurora\Modules\Core\Classes\Tenant::class);
		if (!($mUser instanceof \Aurora\Modules\Core\Classes\Tenant))
		{
			$mUser = false;
		}
		
		return $mUser;
	}	

	public static function setTenantName($sTenantName)
	{
		self::$aUserSession['TenantName'] = $sTenantName;
	}

	public static function setUserId($iUserId)
	{
		self::$aUserSession['UserId'] = (int) $iUserId;
	}
	
	public static function setAuthToken($sAuthToken)
	{
		self::$aUserSession['AuthToken'] = $sAuthToken;
	}

	public static function getCurrentTenant()
	{
		static $bTenantInitialized = false;
		static $oTenant = null;
		
		if (!$bTenantInitialized)
		{
			$oUser = self::getAuthenticatedUser();
			
			if ($oUser && !$oUser->isAdmin())
			{
				$oTenant = self::getTenantById($oUser->IdTenant);
			}

			if (!$oUser && !$oTenant)
			{
				$oTenant = self::getTenantByWebDomain();
			}

//			$bTenantInitialized = true;
		}
		
		return $oTenant;
	}

	public static function getTenantByWebDomain()
	{
		static $bTenantInitialized = false;
		static $oTenant = null;
		
		if (!$bTenantInitialized)
		{
			if (!empty($_SERVER['SERVER_NAME']))
			{
				$aTenants = Managers\Eav::getInstance()->getEntities(\Aurora\Modules\Core\Classes\Tenant::class, array(), 0, 0, array('WebDomain' => $_SERVER['SERVER_NAME']));
				if (is_array($aTenants) && count($aTenants) > 0)
				{
					$oTenant = $aTenants[0];
				}
			}
			$bTenantInitialized = true;
		}
		
		return $oTenant;
	}
	
	/**
	 * 
	 * @return string
	 */
	public static function getTenantName()
	{
		static $bTenantInitialized = false;
		static $mResult = false;

		if (!$bTenantInitialized)
		{
			if (is_array(self::$aUserSession) && !empty(self::$aUserSession['TenantName']))
			{
				$mResult = self::$aUserSession['TenantName'];
			}
			else
			{
				try
				{
					$oTenant = self::getCurrentTenant();
					if ($oTenant)
					{
						$mResult = $oTenant->Name;
					}
				}
				catch (\Exception $oEx)
				{
					$mResult = false;				
				}
			}
//			$bTenantInitialized = true;
		}
		
		return $mResult;
	}
}