Overhauled page tracking in sessions / user online locations
authorMarcel Werk <burntime@woltlab.com>
Wed, 25 May 2016 15:40:08 +0000 (17:40 +0200)
committerMarcel Werk <burntime@woltlab.com>
Wed, 25 May 2016 15:40:17 +0000 (17:40 +0200)
24 files changed:
CHANGELOG.md
wcfsetup/install/files/lib/data/user/UserProfileList.class.php
wcfsetup/install/files/lib/data/user/online/UserOnline.class.php
wcfsetup/install/files/lib/form/AccountManagementForm.class.php
wcfsetup/install/files/lib/form/AvatarEditForm.class.php
wcfsetup/install/files/lib/form/LoginForm.class.php
wcfsetup/install/files/lib/form/LostPasswordForm.class.php
wcfsetup/install/files/lib/form/NewPasswordForm.class.php
wcfsetup/install/files/lib/form/RegisterForm.class.php
wcfsetup/install/files/lib/form/SettingsForm.class.php
wcfsetup/install/files/lib/form/SignatureEditForm.class.php
wcfsetup/install/files/lib/page/AbstractPage.class.php
wcfsetup/install/files/lib/page/CmsPage.class.php
wcfsetup/install/files/lib/page/ITrackablePage.class.php
wcfsetup/install/files/lib/page/MembersListPage.class.php
wcfsetup/install/files/lib/page/TeamPage.class.php
wcfsetup/install/files/lib/page/UserPage.class.php
wcfsetup/install/files/lib/page/UsersOnlineListPage.class.php
wcfsetup/install/files/lib/system/exception/NamedUserException.class.php
wcfsetup/install/files/lib/system/exception/PermissionDeniedException.class.php
wcfsetup/install/files/lib/system/page/PageLocationManager.class.php
wcfsetup/install/files/lib/system/page/handler/UserPageHandler.class.php
wcfsetup/install/files/lib/system/session/SessionHandler.class.php
wcfsetup/setup/db/install.sql

index 116194eaf80d42e5f0d115d59f8ed3e3ec8092dd..0588dbf993293156ea21487af6b7d90c39d6169d 100644 (file)
@@ -54,6 +54,7 @@
 * Scaled embedded youtube videos to maximum width
 * `\wcf\form\AbstractCaptchaForm`: added parameter to force captcha usage for registered users.
 * Added global disable switch for languages.
+* Overhauled page tracking in sessions / user online locations
 
 #### CMS
 
 * Option `message_sidebar_enable_rank` removed.
 * Option `message_sidebar_enable_avatar` removed.
 * Removed obsolete `$activeMenuItem` in frontend forms/pages
+* Obsolete interface `wcf\page\ITrackablePage` deprecated.
 
 #### Documentation
 
index c0af048f16cf49eda61ddadbb553caaee0ac7578..00e981749016ca9dc7b2f1eda51564f5fc70a3ef 100644 (file)
@@ -43,7 +43,7 @@ class UserProfileList extends UserList {
                }
                
                // get current location
-               $this->sqlSelects .= ", session.controller, session.objectID AS locationObjectID, session.lastActivityTime AS sessionLastActivityTime";
+               $this->sqlSelects .= ", session.pageID, session.pageObjectID, session.lastActivityTime AS sessionLastActivityTime";
                $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_session session ON (session.userID = user_table.userID)";
        }
        
index 7a915c38a7b09a7f354998578cb9e3ab16e0c4fe..033a3ea369cb00410f4bd61ea47cc1bce63c8499 100644 (file)
@@ -62,42 +62,27 @@ class UserOnline extends UserProfile {
         */
        public function setLocation($location = null) {
                if ($location === null) {
-                       if ($this->controller) {
-                               if ($this->controller === CmsPage::class) {
-                                       // create location based on cms page title
-                                       if ($this->objectType) {
-                                               $page = PageCache::getInstance()->getPageByIdentifier($this->objectType);
-                                               if ($page !== null) {
-                                                       // TODO: check if active user may access the page
-                                                       $pageContent = $page->getPageContentByLanguage(WCF::getLanguage()->languageID);
-                                                       if (isset($pageContent['title'])) {
-                                                               $this->location = $pageContent['title'];
-                                                               
-                                                               return false;
-                                                       }
-                                               }
+                       if ($this->pageID) {
+                               $page = PageCache::getInstance()->getPage($this->pageID);
+                               if ($page !== null) {
+                                       if ($page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
+                                               // refer to page handler
+                                               $this->location = $page->getHandler()->getOnlineLocation($page, $this);
+                                               return true;
                                        }
-                               }
-                               else {
-                                       $page = PageCache::getInstance()->getPageByController($this->controller);
-                                       if ($page !== null) {
-                                               if ($page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
-                                                       // refer to page handler
-                                                       $this->location = $page->getHandler()->getOnlineLocation($page, $this);
-                                                       
-                                                       return true;
-                                               }
-                                               else {
-                                                       // check if static language item exists
-                                                       $languageItem = 'wcf.page.onlineLocation.' . $page->identifier;
-                                                       $languageItemValue = WCF::getLanguage()->get($languageItem);
-                                                       
-                                                       if ($languageItemValue !== $languageItem) {
-                                                               $this->location = $languageItemValue;
-                                                               
-                                                               return true;
+                                       else {
+                                               // TODO: check if active user may access the page
+                                               $title = $page->getTitle();
+                                               if (!empty($title)) {
+                                                       if ($page->pageType != 'system') {
+                                                               $this->location = '<a href="' . StringUtil::encodeHTML($page->getLink()) . '">' . StringUtil::encodeHTML($title) . '</a>';
+                                                       }
+                                                       else {
+                                                               $this->location = StringUtil::encodeHTML($title);
                                                        }
                                                }
+                                               
+                                               return ($this->location != ''); 
                                        }
                                }
                        }
index f749874a92af09654d77c27427dc4cd4bd1f3fab..c87e37a92def750961c4e287863f038b012edc25 100644 (file)
@@ -23,11 +23,6 @@ use wcf\util\UserUtil;
  * @category   Community Framework
  */
 class AccountManagementForm extends AbstractForm {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index f4471be47bd31fc5762e69ce37bb9f92920e0c2b..8fb7532c9a9d0847e672714d588707e6ee22aee8 100644 (file)
@@ -21,11 +21,6 @@ use wcf\system\WCF;
  * @category   Community Framework
  */
 class AvatarEditForm extends AbstractForm {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index 03e03def322fd9272f7aca1d5478a6f19b052b18..3b131d9d3956d56ccfdf01b05cf953f99c9e80fd 100644 (file)
@@ -18,11 +18,6 @@ use wcf\util\HeaderUtil;
 class LoginForm extends \wcf\acp\form\LoginForm {
        const AVAILABLE_DURING_OFFLINE_MODE = true;
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * true enables the usage of cookies to save login credentials
         * @var boolean
index 12422d523e3912750885d335ff6fb11f49e06f27..a908e026fc6fe61fb47f4cf2976bc40a79c3b1d2 100644 (file)
@@ -23,11 +23,6 @@ use wcf\util\StringUtil;
 class LostPasswordForm extends AbstractCaptchaForm {
        const AVAILABLE_DURING_OFFLINE_MODE = true;
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * username
         * @var string
index e488f9cf9770db96c0ed422206bff531436ddc72..4915fe47421e65f0dbc3d49c7992db52a564dedd 100644 (file)
@@ -24,11 +24,6 @@ use wcf\util\StringUtil;
 class NewPasswordForm extends AbstractForm {
        const AVAILABLE_DURING_OFFLINE_MODE = true;
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * user id
         * @var integer
index ffb0c8521c21fd98c0236b0051d3f239ef307e07..8b2da8ef5ce74463a0b85d91b5078f295c6cdcf1 100644 (file)
@@ -34,11 +34,6 @@ use wcf\util\UserRegistrationUtil;
  * @category   Community Framework
  */
 class RegisterForm extends UserAddForm {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * true if external authentication is used
         * @var boolean
index 9f745c8bd87ca669721de5e98cb0e57d8bf00117..f8dfb7e4e280bb9600c6d8edf4b0ce2df3dcaf60 100644 (file)
@@ -25,11 +25,6 @@ use wcf\util\ArrayUtil;
  * @category   Community Framework
  */
 class SettingsForm extends AbstractForm {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index 824cfeff1f6b1fcc58c8908b026f68af14842112..02758507cf71afbd84f5dbd7abf7c64b3b0cbfd7 100644 (file)
@@ -18,11 +18,6 @@ use wcf\system\WCF;
  * @category   Community Framework
  */
 class SignatureEditForm extends MessageForm {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index a8e2d5c493ca073db2f67f0d2d96b466ec1b781c..7ebd0f9419df4b4b737d90da77f69cf9bd445806 100644 (file)
@@ -24,7 +24,7 @@ use wcf\util\StringUtil;
  * @subpackage page
  * @category   Community Framework
  */
-abstract class AbstractPage implements IPage, ITrackablePage {
+abstract class AbstractPage implements IPage {
        /**
         * name of the active menu item
         * @var string
@@ -43,12 +43,6 @@ abstract class AbstractPage implements IPage, ITrackablePage {
         */
        public $canonicalURL = '';
        
-       /**
-        * enables the tracking of this page
-        * @var boolean
-        */
-       public $enableTracking = false;
-       
        /**
         * is true if canonical URL will be enforced even if POST data is represent
         * @var boolean
@@ -324,46 +318,4 @@ abstract class AbstractPage implements IPage, ITrackablePage {
                        }
                }
        }
-       
-       /**
-        * @inheritDoc
-        */
-       public function isTracked() {
-               return $this->enableTracking;
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getController() {
-               return get_class($this);
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getParentObjectType() {
-               return '';
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getParentObjectID() {
-               return 0;
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getObjectType() {
-               return '';
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getObjectID() {
-               return 0;
-       }
 }
index 9485cd32e4106c3a1a3556a934665c050dfb35e8..44874fa4f9353bbcdde506f33a7c23c6aadabb54 100644 (file)
@@ -23,11 +23,6 @@ class CmsPage extends AbstractPage {
         */
        public $content;
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @var integer
         */
@@ -91,11 +86,4 @@ class CmsPage extends AbstractPage {
                        'pageID' => $this->pageID
                ]);
        }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getObjectType() {
-               return $this->page ? $this->page->identifier : '';
-       }
 }
index a7aeb8182c4b37ccebb88cf33a665518fd181545..819240ece6cbc6bb546a4b09b05b30331e8f778f 100644 (file)
@@ -10,6 +10,7 @@ namespace wcf\page;
  * @package    com.woltlab.wcf
  * @subpackage page
  * @category   Community Framework
+ * @deprecated  2.2
  */
 interface ITrackablePage {
        /**
index 0f09a63b3eadc521c16fca43b5df16be9514f5ed..604f59d0328c0c1ad4af96388fe0fe7305a11597 100644 (file)
@@ -39,11 +39,6 @@ class MembersListPage extends SortablePage {
         */
        public $neededModules = ['MODULE_MEMBERS_LIST'];
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index ae65ee50638192c87e23a07f5a47db8707b8002d..812d4739f9950aa6620796677a6f672e0746d3da 100644 (file)
@@ -27,11 +27,6 @@ class TeamPage extends MultipleLinkPage {
         */
        public $neededModules = ['MODULE_TEAM_PAGE'];
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
index 78d3d67f977b553554abe36a170ea75066ede2f9..a0cae9c944e27fe2dcdb2ae8b28d15f8f1b1ee72 100644 (file)
@@ -29,11 +29,6 @@ use wcf\system\WCF;
  * @category   Community Framework
  */
 class UserPage extends AbstractPage {
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * edit profile on page load
         * @var boolean
@@ -200,18 +195,4 @@ class UserPage extends AbstractPage {
                
                parent::show();
        }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getObjectType() {
-               return 'com.woltlab.wcf.user';
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function getObjectID() {
-               return $this->userID;
-       }
 }
index 2527b5d6f124eb16cb473379bb3840416f12321a..826c92e535fccef05529ac24950665b2d5c4fafe 100644 (file)
@@ -27,11 +27,6 @@ class UsersOnlineListPage extends SortablePage {
         */
        public $neededPermissions = ['user.profile.canViewUsersOnlineList'];
        
-       /**
-        * @inheritDoc
-        */
-       public $enableTracking = true;
-       
        /**
         * @inheritDoc
         */
@@ -113,7 +108,7 @@ class UsersOnlineListPage extends SortablePage {
                // cache all necessary data for showing locations
                foreach ($this->objectList as $userOnline) {
                        if ($userOnline->controller) {
-                               $page = PageCache::getInstance()->getPageByController($userOnline->controller);
+                               $page = PageCache::getInstance()->getPage($userOnline->pageID);
                                if ($page !== null && $page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
                                        $page->getHandler()->prepareOnlineLocation($page, $userOnline);
                                }
index fb31c44da7e6e522b3be19698b875d1e77a8fe59..50e0cab3fa6f13bc7f89b9a42681c0e81910bcd1 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\exception;
+use wcf\system\session\SessionHandler;
 use wcf\system\WCF;
 
 /**
@@ -17,6 +18,8 @@ class NamedUserException extends UserException {
         * Shows a styled page with the given error message.
         */
        public function show() {
+               SessionHandler::getInstance()->disableTracking();
+               
                WCF::getTPL()->assign([
                        'name' => get_class($this),
                        'file' => $this->getFile(),
index b707b413ef4694a62314d81ae293a3cdb16a1f51..9f4718a5846dfaa11e119a0fc95455484c05bb15 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\exception;
+use wcf\system\session\SessionHandler;
 use wcf\system\WCF;
 
 /**
@@ -25,6 +26,8 @@ class PermissionDeniedException extends UserException {
         * Prints a permission denied exception.
         */
        public function show() {
+               SessionHandler::getInstance()->disableTracking();
+               
                @header('HTTP/1.0 403 Forbidden');
                
                WCF::getTPL()->assign([
index 2bd7323a6c26786d891c8e07078a1da0f6c7dfb1..87f27ff31a3084260dd4843cd49b490bf2c9d7cf 100644 (file)
@@ -69,9 +69,10 @@ class PageLocationManager extends SingletonFactory {
         * @param       string                  $identifier             internal page identifier
         * @param       integer                 $pageObjectID           page object id
         * @param       ITitledLinkObject       $locationObject         optional label for breadcrumbs usage
+        * @param       boolean                 $useAsParentLocation
         * @throws      SystemException
         */
-       public function addParentLocation($identifier, $pageObjectID = 0, ITitledLinkObject $locationObject = null) {
+       public function addParentLocation($identifier, $pageObjectID = 0, ITitledLinkObject $locationObject = null, $useAsParentLocation = false) {
                $page = PageCache::getInstance()->getPageByIdentifier($identifier);
                if ($page === null) {
                        throw new SystemException("Unknown page identifier '".$identifier."'.");
@@ -98,7 +99,8 @@ class PageLocationManager extends SingletonFactory {
                        'link' => $link,
                        'pageID' => $page->pageID,
                        'pageObjectID' => $pageObjectID,
-                       'title' => $title
+                       'title' => $title,
+                       'useAsParentLocation' => $useAsParentLocation,
                ];
        }
        
index 87982f0f43f4d86fcc82080c50ff179e5a873862..37f2299ac8001a36f565de6aed1adf5a2149f6a2 100644 (file)
@@ -23,11 +23,11 @@ class UserPageHandler extends AbstractMenuPageHandler implements IOnlineLocation
         * @inheritDoc
         */
        public function getOnlineLocation(Page $page, UserOnline $user) {
-               if ($user->objectID === null) {
+               if ($user->pageObjectID === null) {
                        return '';
                }
                
-               $visitedUser = UserRuntimeCache::getInstance()->getObject($user->objectID);
+               $visitedUser = UserRuntimeCache::getInstance()->getObject($user->pageObjectID);
                if ($visitedUser === null) {
                        return '';
                }
@@ -39,8 +39,8 @@ class UserPageHandler extends AbstractMenuPageHandler implements IOnlineLocation
         * @inheritDoc
         */
        public function prepareOnlineLocation(Page $page, UserOnline $user) {
-               if ($user->objectID !== null) {
-                       UserRuntimeCache::getInstance()->cacheObjectID($user->objectID);
+               if ($user->pageObjectID !== null) {
+                       UserRuntimeCache::getInstance()->cacheObjectID($user->pageObjectID);
                }
        }
 }
index aa421c1e85b4ebcd06599142f090fd9a37f94f5a..1cf6e0a02722d151a4cd13e8abc52e9ea55b21ae 100644 (file)
@@ -9,14 +9,13 @@ use wcf\data\session\virtual\SessionVirtualEditor;
 use wcf\data\session\SessionEditor;
 use wcf\data\user\User;
 use wcf\data\user\UserEditor;
-use wcf\page\ITrackablePage;
 use wcf\system\cache\builder\SpiderCacheBuilder;
 use wcf\system\cache\builder\UserGroupOptionCacheBuilder;
 use wcf\system\cache\builder\UserGroupPermissionCacheBuilder;
 use wcf\system\database\DatabaseException;
 use wcf\system\event\EventHandler;
 use wcf\system\exception\PermissionDeniedException;
-use wcf\system\request\RequestHandler;
+use wcf\system\page\PageLocationManager;
 use wcf\system\user\authentication\UserAuthenticationFactory;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\SingletonFactory;
@@ -50,6 +49,12 @@ class SessionHandler extends SingletonFactory {
         */
        protected $doNotUpdate = false;
        
+       /**
+        * disables page tracking
+        * @var boolean
+        */
+       protected $disableTracking = false;
+       
        /**
         * various environment variables
         * @var array
@@ -292,6 +297,13 @@ class SessionHandler extends SingletonFactory {
                $this->doNotUpdate = true;
        }
        
+       /**
+        * Disables page tracking.
+        */
+       public function disableTracking() {
+               $this->disableTracking = true;
+       }
+       
        /**
         * Defines global wcf constants related to session.
         */
@@ -852,12 +864,22 @@ class SessionHandler extends SingletonFactory {
                        'requestMethod' => $this->requestMethod,
                        'lastActivityTime' => TIME_NOW
                ];
-               if (!class_exists('wcf\system\CLIWCF', false) && PACKAGE_ID && RequestHandler::getInstance()->getActiveRequest() && RequestHandler::getInstance()->getActiveRequest()->getRequestObject() instanceof ITrackablePage && RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->isTracked()) {
-                       $data['controller'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getController();
-                       $data['parentObjectType'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getParentObjectType();
-                       $data['parentObjectID'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getParentObjectID();
-                       $data['objectType'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getObjectType();
-                       $data['objectID'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getObjectID();
+               if (!class_exists('wcf\system\CLIWCF', false) && !$this->isACP && !$this->disableTracking) {
+                       $pageLocations = PageLocationManager::getInstance()->getLocations();
+                       if (isset($pageLocations[0])) {
+                               $data['pageID'] = $pageLocations[0]['pageID'];
+                               $data['pageObjectID'] = ($pageLocations[0]['pageObjectID'] ?: null);
+                               $data['parentPageID'] = null;
+                               $data['parentPageObjectID'] = null;
+                               
+                               for ($i = 1; $i < count($pageLocations); $i++) {
+                                       if (!empty($pageLocations[$i]['useAsParentLocation'])) {
+                                               $data['parentPageID'] = $pageLocations[$i]['pageID'];
+                                               $data['parentPageObjectID'] = ($pageLocations[$i]['pageObjectID'] ?: null);
+                                               break;
+                                       }
+                               }
+                       }
                }
                
                // update session
index 29f617b29acfa27597e029a63f8e26a5d9ec441a..e1075d5dbfa0a3b318d410eba6095bad9737142e 100644 (file)
@@ -69,12 +69,7 @@ CREATE TABLE wcf1_acp_session (
        userAgent VARCHAR(255) NOT NULL DEFAULT '',
        lastActivityTime INT(10) NOT NULL DEFAULT 0,
        requestURI VARCHAR(255) NOT NULL DEFAULT '',
-       requestMethod VARCHAR(7) NOT NULL DEFAULT '',
-       controller VARCHAR(255) NOT NULL DEFAULT '',
-       parentObjectType VARCHAR(255) NOT NULL DEFAULT '',
-       parentObjectID INT(10) NOT NULL DEFAULT 0,
-       objectType VARCHAR(255) NOT NULL DEFAULT '',
-       objectID INT(10) NOT NULL DEFAULT 0
+       requestMethod VARCHAR(7) NOT NULL DEFAULT ''    
 );
 
 DROP TABLE IF EXISTS wcf1_acp_session_access_log;
@@ -1043,13 +1038,14 @@ CREATE TABLE wcf1_session (
        lastActivityTime INT(10) NOT NULL DEFAULT 0,
        requestURI VARCHAR(255) NOT NULL DEFAULT '',
        requestMethod VARCHAR(7) NOT NULL DEFAULT '',
-       controller VARCHAR(255) NOT NULL DEFAULT '',
-       parentObjectType VARCHAR(255) NOT NULL DEFAULT '',
-       parentObjectID INT(10) NOT NULL DEFAULT 0,
-       objectType VARCHAR(255) NOT NULL DEFAULT '',
-       objectID INT(10) NOT NULL DEFAULT 0,
+       pageID INT(10),
+       pageObjectID INT(10),
+       parentPageID INT(10),
+       parentPageObjectID INT(10),
        spiderID INT(10),
        KEY packageID (lastActivityTime, spiderID),
+       KEY pageID (pageID, pageObjectID),
+       KEY parentPageID (parentPageID, parentPageObjectID),
        UNIQUE KEY uniqueUserID (userID)
 );
 
@@ -1759,6 +1755,8 @@ ALTER TABLE wcf1_search ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) O
 
 ALTER TABLE wcf1_session ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
 ALTER TABLE wcf1_session ADD FOREIGN KEY (spiderID) REFERENCES wcf1_spider (spiderID) ON DELETE CASCADE;
+ALTER TABLE wcf1_session ADD FOREIGN KEY (pageID) REFERENCES wcf1_page (pageID) ON DELETE SET NULL;
+ALTER TABLE wcf1_session ADD FOREIGN KEY (parentPageID) REFERENCES wcf1_page (pageID) ON DELETE SET NULL;
 
 ALTER TABLE wcf1_session_virtual ADD FOREIGN KEY (sessionID) REFERENCES wcf1_session (sessionID) ON DELETE CASCADE ON UPDATE CASCADE;