%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/security/classes/general/ |
| Current File : //home/bitrix/www/bitrix/modules/security/classes/general/session_mc.php |
<?
class CSecuritySessionMC
{
/** @var Memcache $connection*/
protected static $connection = null;
protected static $sessionId = null;
protected static $isReadOnly = false;
protected static $isSessionReady = false;
/**
* @return bool
*/
public static function Init()
{
if(self::isConnected())
return true;
self::$isReadOnly = defined('BX_SECURITY_SESSION_READONLY');
return self::newConnection();
}
/**
* @param string $savePath - unused on this handler
* @param string $sessionName - unused on this handler
* @return bool
*/
public static function open($savePath, $sessionName)
{
return CSecuritySessionMC::Init();
}
/**
* @return bool
*/
public static function close()
{
if(!self::isConnected() || !self::isValidId(self::$sessionId))
return false;
if (!self::$isReadOnly && self::$isSessionReady)
{
if(isSessionExpired())
self::destroy(self::$sessionId);
self::$connection->replace(self::getPrefix().self::$sessionId.".lock", 0, 0, 1);
}
self::$sessionId = null;
self::closeConnection();
return true;
}
/**
* @param string $id - session id, must be valid hash
* @return string
*/
public static function read($id)
{
if(!self::isConnected() || !self::isValidId($id))
return "";
$sid = self::getPrefix();
if (!self::$isReadOnly)
{
$lockTimeout = 55;//TODO: add setting
$lockWait = 59000000;//micro seconds = 60 seconds TODO: add setting
$waitStep = 100;
if (defined('BX_SECURITY_SESSION_MEMCACHE_EXLOCK') && BX_SECURITY_SESSION_MEMCACHE_EXLOCK)
$lock = Bitrix\Main\Context::getCurrent()->getRequest()->getRequestedPage();
else
$lock = 1;
while(!self::$connection->add($sid.$id.".lock", $lock, 0, $lockTimeout))
{
if(self::$connection->increment($sid.$id.".lock", 1) === 1)
{
self::$connection->replace($sid.$id.".lock", $lock, 0, $lockTimeout);
break;
}
usleep($waitStep);
$lockWait -= $waitStep;
if($lockWait < 0)
{
$errorText = 'Unable to get session lock within 60 seconds.';
if ($lock !== 1)
{
$lockedUri = self::$connection->get($sid.$id.".lock");
if ($lockedUri && $lockedUri != 1)
$errorText .= sprintf(' Locked by "%s".', $lockedUri);
}
CSecuritySession::triggerFatalError($errorText);
}
if($waitStep < 1000000)
$waitStep *= 2;
}
}
self::$sessionId = $id;
self::$isSessionReady = true;
$res = self::$connection->get($sid.$id);
if($res === false)
$res = "";
return $res;
}
/**
* @param string $id - session id, must be valid hash
* @param string $sessionData
* @return bool
*/
public static function write($id, $sessionData)
{
if(!self::isConnected() || !self::isValidId($id))
return false;
if (!self::$isSessionReady)
return false;
if (self::$isReadOnly)
{
if (!CSecuritySession::isOldSessionIdExist())
{
return true;
}
}
$sid = self::getPrefix();
$maxLifetime = intval(ini_get("session.gc_maxlifetime"));
if(CSecuritySession::isOldSessionIdExist())
{
$oldSessionId = CSecuritySession::getOldSessionId(true);
self::$connection->replace($sid.$oldSessionId, "", 0, 1);
}
self::$connection->set($sid.$id, $sessionData, 0, $maxLifetime);
return true;
}
/**
* @param string $id - session id, must be valid hash
* @return bool
*/
public static function destroy($id)
{
if(!self::isValidId($id))
return false;
if (!self::$isSessionReady)
return false;
if (self::$isReadOnly)
return false;
$isConnectionRestored = false;
if(!self::isConnected())
$isConnectionRestored = self::newConnection();
if(!self::isConnected())
return false;
$sid = self::getPrefix();
self::$connection->replace($sid.$id, "", 0, 1);
if(CSecuritySession::isOldSessionIdExist())
self::$connection->replace($sid.CSecuritySession::getOldSessionId(true), "", 0, 1);
if($isConnectionRestored)
self::closeConnection();
return true;
}
/**
* @param int $maxLifeTime - unused on this handler
* @return bool
*/
public static function gc($maxLifeTime)
{
return true;
}
/**
* @return bool
*/
public static function isStorageEnabled()
{
return defined("BX_SECURITY_SESSION_MEMCACHE_HOST");
}
/**
* @return bool
*/
protected static function isConnected()
{
return self::$connection !== null;
}
/**
* @param string $pId
* @return bool
*/
protected static function isValidId($pId)
{
return (
$pId
&& is_string($pId)
&& preg_match('/^[\da-z\-,]{6,}$/iD', $pId)
);
}
/**
* @return string
*/
protected static function getPrefix()
{
return defined("BX_CACHE_SID")? BX_CACHE_SID: "BX";
}
/**
* @return bool
*/
protected static function newConnection()
{
$result = false;
$exception = null;
if (!extension_loaded('memcache'))
{
$result = false;
$exception = new \ErrorException("memcache extention not loaded.", 0, E_USER_ERROR, __FILE__, __LINE__);
}
if (!$exception)
{
if (!self::isStorageEnabled())
{
$result = false;
$exception = new \ErrorException("BX_SECURITY_SESSION_MEMCACHE_HOST constant is not defined.", 0, E_USER_ERROR, __FILE__, __LINE__);
}
}
if (!$exception)
{
$port = defined("BX_SECURITY_SESSION_MEMCACHE_PORT")? intval(BX_SECURITY_SESSION_MEMCACHE_PORT): 11211;
self::$connection = new Memcache;
$result = self::$connection->pconnect(BX_SECURITY_SESSION_MEMCACHE_HOST, $port);
if (!$result)
{
$error = error_get_last();
if ($error && $error["type"] == E_WARNING)
{
$exception = new \ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']);
}
}
}
if ($exception)
{
$application = \Bitrix\Main\Application::getInstance();
$exceptionHandler = $application->getExceptionHandler();
$exceptionHandler->writeToLog($exception);
}
return $result;
}
protected static function closeConnection()
{
self::$connection->close();
self::$connection = null;
}
}