From: Alexander Ebert Date: Sun, 20 Apr 2014 14:12:32 +0000 (+0200) Subject: Improved session handling, added changeUserVirtual() X-Git-Tag: 2.1.0_Alpha_1~872 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=ac094463c6d04389f41a628662900feec34418cf;p=GitHub%2FWoltLab%2FWCF.git Improved session handling, added changeUserVirtual() Instead of altering changeUser(), I've added changeUserVirtual() (and reverted the original method), because all these numerous different cases would have caused the method to be a nightmare. --- diff --git a/wcfsetup/install/files/lib/system/session/SessionHandler.class.php b/wcfsetup/install/files/lib/system/session/SessionHandler.class.php index 670b2ad96e..4f1151a1d6 100644 --- a/wcfsetup/install/files/lib/system/session/SessionHandler.class.php +++ b/wcfsetup/install/files/lib/system/session/SessionHandler.class.php @@ -14,6 +14,7 @@ use wcf\system\user\authentication\UserAuthenticationFactory; use wcf\system\user\storage\UserStorageHandler; use wcf\system\SingletonFactory; use wcf\system\WCF; +use wcf\util\HeaderUtil; use wcf\util\PasswordUtil; use wcf\util\StringUtil; use wcf\util\UserUtil; @@ -545,61 +546,131 @@ class SessionHandler extends SingletonFactory { * * @param \wcf\data\userUser $user * @param boolean $hideSession if true, database won't be updated + * @return boolean */ public function changeUser(User $user, $hideSession = false) { + if ($this->supportsVirtualSessions) { + return $this->changeUserVirtual($user); + } + $sessionTable = call_user_func(array($this->sessionClassName, 'getDatabaseTableName')); - $isNewSession = true; - if ($user->userID) { - if ($this->supportsVirtualSessions) { - // find existing session + if ($user->userID && !$hideSession) { + // user is not a guest, delete all other sessions of this user + $sql = "DELETE FROM ".$sessionTable." + WHERE sessionID <> ? + AND userID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($this->sessionID, $user->userID)); + + // reset session variables + $this->variables = array(); + $this->variablesChanged = true; + } + + // update user reference + $this->user = $user; + + if (!$hideSession) { + // update session + $sessionEditor = new $this->sessionEditorClassName($this->session); + $sessionEditor->update(array( + 'userID' => $this->user->userID + )); + } + + // reset caches + $this->groupData = null; + $this->languageIDs = null; + $this->languageID = $this->user->languageID; + $this->styleID = $this->user->styleID; + + return true; + } + + /** + * Changes the user stored in the session, this method is different from changeUser() because it + * attempts to re-use sessions unless there are other virtual sessions for the same user (userID != 0). + * In reverse, logging out attempts to re-use the current session or spawns a new session depending + * on other virtual sessions. + * + * @param \wcf\data\user\User $user + */ + protected function changeUserVirtual(User $user) { + $sessionTable = call_user_func(array($this->sessionClassName, 'getDatabaseTableName')); + + switch ($user->userID) { + // + // user -> guest (logout) + // + case 0: + // delete virtual session + $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); + $virtualSessionEditor->delete(); + + // there are still other virtual sessions, create a new session + if (SessionVirtual::countVirtualSessions($this->session->sessionID)) { + // save session + $sessionData = array( + 'sessionID' => StringUtil::getRandomID(), + 'userID' => $user->userID, + 'ipAddress' => UserUtil::getIpAddress(), + 'userAgent' => UserUtil::getUserAgent(), + 'lastActivityTime' => TIME_NOW, + 'requestURI' => UserUtil::getRequestURI(), + 'requestMethod' => (!empty($_SERVER['REQUEST_METHOD']) ? substr($_SERVER['REQUEST_METHOD'], 0, 7) : '') + ); + + $this->session = call_user_func(array($this->sessionEditorClassName, 'create'), $sessionData); + + HeaderUtil::setCookie('cookieHash', $this->session->sessionID); + } + else { + // this was the last virtual session, re-use current session + // update session + $sessionEditor = new $this->sessionEditorClassName($this->session); + $sessionEditor->update(array( + 'userID' => $user->userID + )); + } + break; + + // + // guest -> user (login) + // + default: + // find existing session for this user $session = call_user_func(array($this->sessionClassName, 'getSessionByUserID'), $user->userID); - if ($session !== null) { + // no session exists, re-use current session + if ($session === null) { + // update session + $sessionEditor = new $this->sessionEditorClassName($this->session); + $sessionEditor->update(array( + 'userID' => $user->userID + )); + } + else { // delete guest session $sessionEditor = new $this->sessionEditorClassName($this->session); $sessionEditor->delete(); // inherit existing session $this->session = $session; - $this->user = $user; - $this->loadVirtualSession(true); - - $isNewSession = false; } - } - else if (!$hideSession) { - // user is not a guest, delete all other sessions of this user - $sql = "DELETE FROM ".$sessionTable." - WHERE sessionID <> ? - AND userID = ?"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute(array($this->sessionID, $user->userID)); - - // reset session variables - $this->variables = array(); - $this->variablesChanged = true; - } + break; } - if ($isNewSession) { - // update user reference - $this->user = $user; - - if (!$hideSession) { - // update session - $sessionEditor = new $this->sessionEditorClassName($this->session); - $sessionEditor->update(array( - 'userID' => $this->user->userID - )); - } - } + $this->user = $user; + $this->loadVirtualSession(true); // reset caches $this->groupData = null; $this->languageIDs = null; $this->languageID = $this->user->languageID; $this->styleID = $this->user->styleID; + + return false; } /** @@ -671,22 +742,10 @@ class SessionHandler extends SingletonFactory { } // set user to guest - $this->changeUser(new User(null), true); + $deleteSession = $this->changeUser(new User(null), true); // remove session - $deleteSession = true; - if ($this->supportsVirtualSessions && ($this->virtualSession instanceof SessionVirtual)) { - // delete the virtual session - $virtualSessionEditor = new SessionVirtualEditor($this->virtualSession); - $virtualSessionEditor->delete(); - - if (SessionVirtual::countVirtualSessions($this->session->sessionID)) { - // there are still remaining virtual sessions, do not delete master session - $deleteSession = false; - } - } - - if ($deleteSession) { + if ($deleteSession !== false) { $sessionEditor = new $this->sessionEditorClassName($this->session); $sessionEditor->delete(); }