From e1622bfa30aada74f43f63a177b12aed10fd3857 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Fri, 25 Mar 2016 20:43:07 +0100 Subject: [PATCH] Add virtual sessions for ACP --- .../virtual/ACPSessionVirtual.class.php | 72 +++++++++++++++++++ .../virtual/ACPSessionVirtualAction.class.php | 42 +++++++++++ .../virtual/ACPSessionVirtualEditor.class.php | 42 +++++++++++ .../virtual/ACPSessionVirtualList.class.php | 20 ++++++ .../session/virtual/SessionVirtual.class.php | 60 ++-------------- .../virtual/SessionVirtualAction.class.php | 35 ++------- .../virtual/SessionVirtualEditor.class.php | 35 ++------- .../virtual/SessionVirtualList.class.php | 13 ++-- .../system/session/SessionHandler.class.php | 67 +++++++++++++---- wcfsetup/setup/db/install.sql | 12 ++++ 10 files changed, 270 insertions(+), 128 deletions(-) create mode 100644 wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtual.class.php create mode 100644 wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualAction.class.php create mode 100644 wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualEditor.class.php create mode 100644 wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualList.class.php diff --git a/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtual.class.php b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtual.class.php new file mode 100644 index 0000000000..dd4b98bfa8 --- /dev/null +++ b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtual.class.php @@ -0,0 +1,72 @@ + + * @package com.woltlab.wcf + * @subpackage data.acp.session.virtual + * @category Community Framework + */ +class ACPSessionVirtual extends DatabaseObject { + /** + * @see \wcf\data\DatabaseObject::$databaseTableName + */ + protected static $databaseTableName = 'acp_session_virtual'; + + /** + * @see \wcf\data\DatabaseObject::$databaseTableIndexName + */ + protected static $databaseTableIndexName = 'virtualSessionID'; + + /** + * Returns the active virtual session object or null. + * + * @param string $sessionID + * @return \wcf\data\session\virtual\SessionVirtual + */ + public static function getExistingSession($sessionID) { + $sql = "SELECT * + FROM ".static::getDatabaseTableName()." + WHERE sessionID = ? + AND ipAddress = ? + AND userAgent = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array( + $sessionID, + UserUtil::getIpAddress(), + UserUtil::getUserAgent() + )); + + return $statement->fetchObject(static::class); + } + + /** + * Returns the number of virtual sessions associated with the given session id. + * + * @param string $sessionID + * @return integer + */ + public static function countVirtualSessions($sessionID) { + $sql = "SELECT COUNT(*) AS count + FROM ".static::getDatabaseTableName()." + WHERE sessionID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($sessionID)); + $row = $statement->fetchArray(); + + return $row['count']; + } +} diff --git a/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualAction.class.php b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualAction.class.php new file mode 100644 index 0000000000..6a81565cc8 --- /dev/null +++ b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualAction.class.php @@ -0,0 +1,42 @@ + + * @package com.woltlab.wcf + * @subpackage data.acp.session.virtual + * @category Community Framework + */ +class ACPSessionVirtualAction extends AbstractDatabaseObjectAction { + /** + * @see \wcf\data\AbstractDatabaseObjectAction::$className + */ + protected $className = ACPSessionVirtualEditor::class; + + /** + * Attention: This method does not always return a new object, in case a matching virtual session + * already exists, the existing session will be returned rather than a new session being created. + * + * @see \wcf\data\AbstractDatabaseObjectAction::create() + */ + public function create() { + // try to find an existing virtual session + $baseClass = call_user_func(array($this->className, 'getBaseClass')); + $virtualSession = call_user_func(array($baseClass, 'getExistingSession'), $this->parameters['data']['sessionID']); + if ($virtualSession !== null) { + return $virtualSession; + } + + if (!isset($this->parameters['data']['lastActivityTime'])) $this->parameters['data']['lastActivityTime'] = TIME_NOW; + if (!isset($this->parameters['data']['ipAddress'])) $this->parameters['data']['ipAddress'] = UserUtil::getIpAddress(); + if (!isset($this->parameters['data']['userAgent'])) $this->parameters['data']['userAgent'] = UserUtil::getUserAgent(); + + return parent::create(); + } +} diff --git a/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualEditor.class.php b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualEditor.class.php new file mode 100644 index 0000000000..e0ae8abfbd --- /dev/null +++ b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualEditor.class.php @@ -0,0 +1,42 @@ + + * @package com.woltlab.wcf + * @subpackage data.acp.session.virtual + * @category Community Framework + */ +class ACPSessionVirtualEditor extends DatabaseObjectEditor { + /** + * @see \wcf\data\DatabaseObjectDecorator::$baseClass + */ + protected static $baseClass = ACPSessionVirtual::class; + + /** + * Updates last activity time of this virtual session. + */ + public function updateLastActivityTime() { + $this->update(array( + 'lastActivityTime' => TIME_NOW + )); + } + + /** + * Deletes the expired virtual sessions. + * + * @param integer $timestamp + */ + public static function deleteExpiredSessions($timestamp) { + $sql = "DELETE FROM ".call_user_func(array(static::$baseClass, 'getDatabaseTableName'))." + WHERE lastActivityTime < ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($timestamp)); + } +} diff --git a/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualList.class.php b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualList.class.php new file mode 100644 index 0000000000..14ea365c2e --- /dev/null +++ b/wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualList.class.php @@ -0,0 +1,20 @@ + + * @package com.woltlab.wcf + * @subpackage data.acp.session.virtual + * @category Community Framework + */ +class ACPSessionVirtualList extends DatabaseObjectList { + /** + * @see \wcf\data\DatabaseObjectList::$className + */ + public $className = ACPSessionVirtual::class; +} diff --git a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtual.class.php b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtual.class.php index 8fe7420a21..71c1e0f322 100644 --- a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtual.class.php +++ b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtual.class.php @@ -1,19 +1,12 @@ * @package com.woltlab.wcf @@ -26,53 +19,14 @@ use wcf\util\UserUtil; * @property-read string $userAgent * @property-read integer $lastActivityTime */ -class SessionVirtual extends DatabaseObject { +class SessionVirtual extends ACPSessionVirtual { /** - * @see \wcf\data\DatabaseObject::$databaseTableName + * @inheritDoc */ protected static $databaseTableName = 'session_virtual'; /** - * @see \wcf\data\DatabaseObject::$databaseTableIndexName + * @inheritDoc */ protected static $databaseTableIndexName = 'virtualSessionID'; - - /** - * Returns the active virtual session object or null. - * - * @param string $sessionID - * @return \wcf\data\session\virtual\SessionVirtual - */ - public static function getExistingSession($sessionID) { - $sql = "SELECT * - FROM ".static::getDatabaseTableName()." - WHERE sessionID = ? - AND ipAddress = ? - AND userAgent = ?"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute(array( - $sessionID, - UserUtil::getIpAddress(), - UserUtil::getUserAgent() - )); - - return $statement->fetchObject(__CLASS__); - } - - /** - * Returns the number of virtual sessions associated with the given session id. - * - * @param string $sessionID - * @return integer - */ - public static function countVirtualSessions($sessionID) { - $sql = "SELECT COUNT(*) AS count - FROM ".static::getDatabaseTableName()." - WHERE sessionID = ?"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute(array($sessionID)); - $row = $statement->fetchArray(); - - return $row['count']; - } } diff --git a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualAction.class.php b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualAction.class.php index cb4051e2f2..d1a8107553 100644 --- a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualAction.class.php +++ b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualAction.class.php @@ -1,42 +1,21 @@ * @package com.woltlab.wcf * @subpackage data.session.virtual * @category Community Framework */ -class SessionVirtualAction extends AbstractDatabaseObjectAction { +class SessionVirtualAction extends ACPSessionVirtualAction { /** - * @see \wcf\data\AbstractDatabaseObjectAction::$className + * @inheritDoc */ - protected $className = 'wcf\data\session\virtual\SessionVirtualEditor'; - - /** - * Attention: This method does not always return a new object, in case a matching virtual session - * already exists, the existing session will be returned rather than a new session being created. - * - * @see \wcf\data\AbstractDatabaseObjectAction::create() - */ - public function create() { - // try to find an existing virtual session - $baseClass = call_user_func(array($this->className, 'getBaseClass')); - $virtualSession = call_user_func(array($baseClass, 'getExistingSession'), $this->parameters['data']['sessionID']); - if ($virtualSession !== null) { - return $virtualSession; - } - - if (!isset($this->parameters['data']['lastActivityTime'])) $this->parameters['data']['lastActivityTime'] = TIME_NOW; - if (!isset($this->parameters['data']['ipAddress'])) $this->parameters['data']['ipAddress'] = UserUtil::getIpAddress(); - if (!isset($this->parameters['data']['userAgent'])) $this->parameters['data']['userAgent'] = UserUtil::getUserAgent(); - - return parent::create(); - } + protected $className = SessionVirtualEditor::class; } diff --git a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualEditor.class.php b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualEditor.class.php index d1e74ffb30..90193aada3 100644 --- a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualEditor.class.php +++ b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualEditor.class.php @@ -1,42 +1,21 @@ * @package com.woltlab.wcf * @subpackage data.session.virtual * @category Community Framework */ -class SessionVirtualEditor extends DatabaseObjectEditor { +class SessionVirtualEditor extends ACPSessionVirtualEditor { /** - * @see \wcf\data\DatabaseObjectDecorator::$baseClass + * @inheritDoc */ - protected static $baseClass = 'wcf\data\session\virtual\SessionVirtual'; - - /** - * Updates last activity time of this virtual session. - */ - public function updateLastActivityTime() { - $this->update(array( - 'lastActivityTime' => TIME_NOW - )); - } - - /** - * Deletes the expired virtual sessions. - * - * @param integer $timestamp - */ - public static function deleteExpiredSessions($timestamp) { - $sql = "DELETE FROM ".call_user_func(array(static::$baseClass, 'getDatabaseTableName'))." - WHERE lastActivityTime < ?"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute(array($timestamp)); - } + protected static $baseClass = SessionVirtual::class; } diff --git a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualList.class.php b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualList.class.php index 11c5ff0e0f..c424da1c9b 100644 --- a/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualList.class.php +++ b/wcfsetup/install/files/lib/data/session/virtual/SessionVirtualList.class.php @@ -1,20 +1,21 @@ * @package com.woltlab.wcf * @subpackage data.session.virtual * @category Community Framework */ -class SessionVirtualList extends DatabaseObjectList { +class SessionVirtualList extends ACPSessionVirtualList { /** - * @see \wcf\data\DatabaseObjectList::$className + * @inheritDoc */ - public $className = 'wcf\data\session\virtual\SessionVirtual'; + public $className = SessionVirtual::class; } diff --git a/wcfsetup/install/files/lib/system/session/SessionHandler.class.php b/wcfsetup/install/files/lib/system/session/SessionHandler.class.php index 06b2f16a41..c4d200189a 100644 --- a/wcfsetup/install/files/lib/system/session/SessionHandler.class.php +++ b/wcfsetup/install/files/lib/system/session/SessionHandler.class.php @@ -1,5 +1,8 @@ user = new User($this->session->userID); - if ($this->supportsVirtualSessions) $this->virtualSession = SessionVirtual::getExistingSession($sessionID); + if (class_exists(WCFACP::class, false)) { + $this->virtualSession = ACPSessionVirtual::getExistingSession($sessionID); + } + else { + $this->virtualSession = SessionVirtual::getExistingSession($sessionID); + } if (!$this->validate()) { $this->session = null; @@ -420,7 +429,7 @@ class SessionHandler extends SingletonFactory { return; } - if ($this->supportsVirtualSessions) $this->loadVirtualSession(); + $this->loadVirtualSession(); } /** @@ -434,7 +443,12 @@ class SessionHandler extends SingletonFactory { if ($this->virtualSession === null || $forceReload) { $this->virtualSession = null; if ($this->supportsVirtualSessions) { - $virtualSessionAction = new SessionVirtualAction(array(), 'create', array('data' => array('sessionID' => $this->session->sessionID))); + if (class_exists(WCFACP::class, false)) { + $virtualSessionAction = new ACPSessionVirtualAction(array(), 'create', array('data' => array('sessionID' => $this->session->sessionID))); + } + else { + $virtualSessionAction = new SessionVirtualAction(array(), 'create', array('data' => array('sessionID' => $this->session->sessionID))); + } try { $returnValues = $virtualSessionAction->executeAction(); @@ -444,7 +458,12 @@ class SessionHandler extends SingletonFactory { // MySQL error 23000 = unique key // do not check against the message itself, some weird systems localize them if ($e->getCode() == 23000) { - $this->virtualSession = SessionVirtual::getExistingSession($this->session->sessionID); + if (class_exists(WCFACP::class, false)) { + $this->virtualSession = ACPSessionVirtual::getExistingSession($this->session->sessionID); + } + else { + $this->virtualSession = SessionVirtual::getExistingSession($this->session->sessionID); + } } } } @@ -458,7 +477,7 @@ class SessionHandler extends SingletonFactory { */ protected function validate() { if (SESSION_VALIDATE_IP_ADDRESS) { - if ($this->supportsVirtualSessions && ($this->virtualSession instanceof SessionVirtual)) { + if ($this->supportsVirtualSessions && ($this->virtualSession instanceof ACPSessionVirtual)) { if ($this->virtualSession->ipAddress != UserUtil::getIpAddress()) { return false; } @@ -469,7 +488,7 @@ class SessionHandler extends SingletonFactory { } if (SESSION_VALIDATE_USER_AGENT) { - if ($this->supportsVirtualSessions && ($this->virtualSession instanceof SessionVirtual)) { + if ($this->supportsVirtualSessions && ($this->virtualSession instanceof ACPSessionVirtual)) { if ($this->virtualSession->userAgent != UserUtil::getUserAgent()) { return false; } @@ -772,12 +791,24 @@ class SessionHandler extends SingletonFactory { case 0: // delete virtual session if ($this->virtualSession) { - $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + if (class_exists(WCFACP::class, false)) { + $virtualSessionEditor = new ACPSessionVirtualEditor($this->virtualSession); + } + else { + $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + } $virtualSessionEditor->delete(); } + if (class_exists(WCFACP::class, false)) { + $sessionCount = ACPSessionVirtual::countVirtualSessions($this->session->sessionID); + } + else { + $sessionCount = SessionVirtual::countVirtualSessions($this->session->sessionID); + } + // there are still other virtual sessions, create a new session - if (SessionVirtual::countVirtualSessions($this->session->sessionID)) { + if ($sessionCount) { // save session $sessionData = array( 'sessionID' => StringUtil::getRandomID(), @@ -892,8 +923,13 @@ class SessionHandler extends SingletonFactory { $sessionEditor = new $this->sessionEditorClassName($this->session); $sessionEditor->update($data); - if ($this->virtualSession instanceof SessionVirtual) { - $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + if ($this->virtualSession instanceof ACPSessionVirtual) { + if (class_exists(WCFACP::class, false)) { + $virtualSessionEditor = new ACPSessionVirtualEditor($this->virtualSession); + } + else { + $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + } $virtualSessionEditor->updateLastActivityTime(); } } @@ -911,8 +947,13 @@ class SessionHandler extends SingletonFactory { 'lastActivityTime' => TIME_NOW )); - if ($this->virtualSession instanceof SessionVirtual) { - $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + if ($this->virtualSession instanceof ACPSessionVirtual) { + if (class_exists(WCFACP::class, false)) { + $virtualSessionEditor = new ACPSessionVirtualEditor($this->virtualSession); + } + else { + $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + } $virtualSessionEditor->updateLastActivityTime(); } } @@ -926,7 +967,7 @@ class SessionHandler extends SingletonFactory { self::resetSessions(array($this->user->userID)); // update last activity time - if (!class_exists('\wcf\system\WCFACP', false)) { + if (!class_exists(WCFACP::class, false)) { $editor = new UserEditor($this->user); $editor->update(array('lastActivityTime' => TIME_NOW)); } diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index 9e8412db33..383938ae78 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -103,6 +103,16 @@ CREATE TABLE wcf1_acp_session_log ( KEY sessionID (sessionID) ); +DROP TABLE IF EXISTS wcf1_acp_session_virtual; +CREATE TABLE wcf1_acp_session_virtual ( + virtualSessionID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + sessionID CHAR(40) NOT NULL, + ipAddress VARCHAR(39) NOT NULL DEFAULT '', + userAgent VARCHAR(255) NOT NULL DEFAULT '', + lastActivityTime INT(10) NOT NULL DEFAULT 0, + UNIQUE KEY (sessionID, ipAddress, userAgent) +); + DROP TABLE IF EXISTS wcf1_acp_template; CREATE TABLE wcf1_acp_template ( templateID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -1643,6 +1653,8 @@ ALTER TABLE wcf1_acp_session_access_log ADD FOREIGN KEY (sessionLogID) REFERENCE ALTER TABLE wcf1_acp_session_log ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE SET NULL; +ALTER TABLE wcf1_acp_session_virtual ADD FOREIGN KEY (sessionID) REFERENCES wcf1_acp_session (sessionID) ON DELETE CASCADE ON UPDATE CASCADE; + ALTER TABLE wcf1_acp_template ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE; ALTER TABLE wcf1_ad ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE; -- 2.20.1