Add virtual sessions for ACP
authorTim Düsterhus <duesterhus@woltlab.com>
Fri, 25 Mar 2016 19:43:07 +0000 (20:43 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 25 Mar 2016 19:43:23 +0000 (20:43 +0100)
wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtual.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualEditor.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/acp/session/virtual/ACPSessionVirtualList.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/session/virtual/SessionVirtual.class.php
wcfsetup/install/files/lib/data/session/virtual/SessionVirtualAction.class.php
wcfsetup/install/files/lib/data/session/virtual/SessionVirtualEditor.class.php
wcfsetup/install/files/lib/data/session/virtual/SessionVirtualList.class.php
wcfsetup/install/files/lib/system/session/SessionHandler.class.php
wcfsetup/setup/db/install.sql

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 (file)
index 0000000..dd4b98b
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+namespace wcf\data\acp\session\virtual;
+use wcf\data\DatabaseObject;
+use wcf\system\WCF;
+use wcf\util\UserUtil;
+
+/**
+ * Virtual Sessions extend the original session system with a transparent layer. 
+ * It's only purpose is to enforce session validation based on IP address and/or user agent.
+ * 
+ * The legacy session system does not allow the same user being logged-in more than once 
+ * and the same is true for WCF 2.1 unless we break most parts of the API. 
+ * In order to solve this, we do allow multiple clients to share the exact same session 
+ * among them, while the individual clients are tracked within wcf1_session_virtual.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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 (file)
index 0000000..6a81565
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+namespace wcf\data\acp\session\virtual;
+use wcf\data\AbstractDatabaseObjectAction;
+use wcf\util\UserUtil;
+
+/**
+ * Executes virtual session-related actions.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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 (file)
index 0000000..e0ae8ab
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+namespace wcf\data\acp\session\virtual;
+use wcf\data\DatabaseObjectEditor;
+use wcf\system\WCF;
+
+/**
+ * Provides functions to edit virtual sessions.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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 (file)
index 0000000..14ea365
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+namespace wcf\data\acp\session\virtual;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of virtual sessions.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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;
+}
index 8fe7420a2109bfcbda5923a531ddeeb3605ba088..71c1e0f32215e8f29e6f665a6cd5412f364b6880 100644 (file)
@@ -1,19 +1,12 @@
 <?php
 namespace wcf\data\session\virtual;
-use wcf\data\DatabaseObject;
-use wcf\system\WCF;
-use wcf\util\UserUtil;
+use wcf\data\acp\session\virtual\ACPSessionVirtual;
 
 /**
- * Virtual Sessions extend the original session system with a transparent layer. 
- * It's only purpose is to enforce session validation based on IP address and/or user agent.
+ * Virtual sessions for the frontend.
  * 
- * The legacy session system does not allow the same user being logged-in more than once 
- * and the same is true for WCF 2.1 unless we break most parts of the API. 
- * In order to solve this, we do allow multiple clients to share the exact same session 
- * among them, while the individual clients are tracked within wcf1_session_virtual.
- * 
- * @author     Alexander Ebert
+ * @see                \wcf\data\acp\session\virtual\ACPSessionVirtual
+ * @author     Tim Duesterhus
  * @copyright  2001-2015 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @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'];
-       }
 }
index cb4051e2f2683110e722ccbce6924b3024b532e6..d1a8107553ce2686d09fe41c90c2f1d2429c0f0d 100644 (file)
@@ -1,42 +1,21 @@
 <?php
 namespace wcf\data\session\virtual;
-use wcf\data\AbstractDatabaseObjectAction;
-use wcf\util\UserUtil;
+use wcf\data\acp\session\virtual\ACPSessionVirtualAction;
 
 /**
- * Executes virtual session-related actions.
+ * Virtual sessions for the frontend.
  * 
- * @author     Alexander Ebert
+ * @see                \wcf\data\acp\session\virtual\ACPSessionVirtualAction
+ * @author     Tim Duesterhus
  * @copyright  2001-2015 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @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;
 }
index d1e74ffb3075324044f94eeb2563ecf7ea653d48..90193aada38ececfd9f76ccb7e9c66c11f3fe82b 100644 (file)
@@ -1,42 +1,21 @@
 <?php
 namespace wcf\data\session\virtual;
-use wcf\data\DatabaseObjectEditor;
-use wcf\system\WCF;
+use wcf\data\acp\session\virtual\ACPSessionVirtualEditor;
 
 /**
- * Provides functions to edit virtual sessions.
+ * Virtual sessions for the frontend.
  * 
- * @author     Alexander Ebert
+ * @see                \wcf\data\acp\session\virtual\ACPSessionVirtualEditor
+ * @author     Tim Duesterhus
  * @copyright  2001-2015 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @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;
 }
index 11c5ff0e0f4ad16324ecb610f5aba24fcab2fcf7..c424da1c9bf376c45f75ea09f42335e995d282e3 100644 (file)
@@ -1,20 +1,21 @@
 <?php
 namespace wcf\data\session\virtual;
-use wcf\data\DatabaseObjectList;
+use wcf\data\acp\session\virtual\ACPSessionVirtualList;
 
 /**
- * Represents a list of virtual sessions.
+ * Virtual sessions for the frontend.
  * 
- * @author     Alexander Ebert
+ * @see                \wcf\data\acp\session\virtual\ACPSessionVirtualList
+ * @author     Tim Duesterhus
  * @copyright  2001-2015 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @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;
 }
index 06b2f16a411a6f94c0f711afbe6929e8fc50944c..c4d200189a9e00f5e4aa1b3d3c723d7cf398b707 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 namespace wcf\system\session;
+use wcf\data\acp\session\virtual\ACPSessionVirtual;
+use wcf\data\acp\session\virtual\ACPSessionVirtualAction;
+use wcf\data\acp\session\virtual\ACPSessionVirtualEditor;
 use wcf\data\session\virtual\SessionVirtual;
 use wcf\data\session\virtual\SessionVirtualAction;
 use wcf\data\session\virtual\SessionVirtualEditor;
@@ -17,6 +20,7 @@ use wcf\system\user\authentication\UserAuthenticationFactory;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
+use wcf\system\WCFACP;
 use wcf\util\HeaderUtil;
 use wcf\util\PasswordUtil;
 use wcf\util\StringUtil;
@@ -410,7 +414,12 @@ class SessionHandler extends SingletonFactory {
                }
                
                $this->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));
                        }
index 9e8412db33c041a95f2e2db6653af2f059d0619a..383938ae78af9656bbb06831c7523c93f0814f3c 100644 (file)
@@ -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;