Release 5.3.27 5.3.27
authorAlexander Ebert <ebert@woltlab.com>
Thu, 16 Mar 2023 15:06:57 +0000 (16:06 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 16 Mar 2023 15:06:57 +0000 (16:06 +0100)
com.woltlab.wcf/package.xml
wcfsetup/install/files/lib/system/WCF.class.php

index 54236a59b5d6761dd14b1865c6f2f038b371a8b1..7907b38c070a8c7e9f61d7f2f4edd59e8aa18b6d 100644 (file)
@@ -5,8 +5,8 @@
                <packagedescription>Free CMS and web-framework, designed for awesome websites and communities.</packagedescription>
                <packagedescription language="de">Freies CMS und Web-Framework, das eindrucksvolle Websites und Communities ermöglicht.</packagedescription>
                <isapplication>1</isapplication>
-               <version>5.3.26</version>
-               <date>2023-01-19</date>
+               <version>5.3.27</version>
+               <date>2023-03-16</date>
        </packageinformation>
        
        <authorinformation>
                <instruction type="script">acp/post_install.php</instruction>
        </instructions>
        
-       <instructions type="update" fromversion="5.2.*">
-               <!-- We need to deploy `lib/core.functions.php` and `lib/system/api/*` first, otherwise
-                    Guzzle can not be found during the development of the regular file PIP. -->
-               <instruction type="file" run="standalone">files_pre.tar</instruction>
-               
-               <!-- Verify that there are no duplicate usernames and warn about them if any are found. -->
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_preUpdate.php</instruction>
-               
-               <!-- Deploy the database changes as early as possible to avoid any conflicts by calls to
-                    tables that do not exist in 5.2, in particular `wcfN_devtools_missing_language_item`.-->
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3.php</instruction>
-               
-               <instruction type="file" />
-               <instruction type="acpTemplate" />
-               <instruction type="template" />
-               
-               <instruction type="option" run="standalone" />
-               
-               <instruction type="acpMenu" />
-               <instruction type="clipboardAction" />
-               <instruction type="mediaProvider" />
-               <instruction type="userGroupOption" />
-               <instruction type="userMenu" />
-               <instruction type="page" />
-               
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_emailConfirmation.php</instruction>
-               
-               <!-- The internal data structure of sitemaps have been modified, this script must be run before
-                    the `objectType` pip to prevent any data corruption. -->
-               <instruction type="script">acp/update_com.woltlab.wcf_5.3_sitemaps.php</instruction>
-               
-               <instruction type="objectTypeDefinition" />
-               <instruction type="objectType" />
-               
-               <instruction type="userNotificationEvent" />
-               <instruction type="userOption" />
-               
-               <instruction type="language" />
-               
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_invalidateMailForm.php</instruction>
-               
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_fixActivationMethod.php</instruction>
-               
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_orphanedComments.php</instruction>
-               
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.3_style.php</instruction>
-               
-               <instruction type="style" run="standalone">defaultStyle.tar</instruction>
-               
-               <!-- This SQL step purges the legacy package servers, this must come last to make sure that an early
-                    abort of the core upgrade does not brick the installation. -->
-               <instruction type="sql">update_5.3.sql</instruction>
-               
-               <instruction type="script">acp/update_com.woltlab.wcf_5.3_packageServer.php</instruction>
-       </instructions>
-
-       <instructions type="update" fromversion="5.3.25">
-               <instruction type="acpTemplate">acptemplates_update.tar</instruction>
+       <instructions type="update" fromversion="5.3.26">
                <instruction type="file">files_update.tar</instruction>
-               <instruction type="template">templates_update.tar</instruction>
-               
-               <instruction type="language"/>
        </instructions>
 </package>
index 7f1db7bea8797c603a70941c464e55df96b3fb15..441bdf530405ee78adc9c3f0da06875eb0b837d9 100644 (file)
@@ -51,7 +51,7 @@ if (!@ini_get('date.timezone')) {
 }
 
 // define current woltlab suite version
-define('WCF_VERSION', '5.3.26');
+define('WCF_VERSION', '5.3.27');
 
 // define current API version
 // @deprecated 5.2
@@ -69,7 +69,7 @@ if (!defined('NO_IMPORTS')) {
 /**
  * WCF is the central class for the WoltLab Suite Core.
  * It holds the database connection, access to template and language engine.
- * 
+ *
  * @author     Marcel Werk
  * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
@@ -88,89 +88,89 @@ class WCF {
         * @deprecated 5.2
         */
        private static $supportedLegacyApiVersions = [2017, 2018];
-       
+
        /**
         * list of currently loaded applications
         * @var Application[]
         */
        protected static $applications = [];
-       
+
        /**
         * list of currently loaded application objects
         * @var IApplication[]
         */
        protected static $applicationObjects = [];
-       
+
        /**
         * list of autoload directories
         * @var array
         */
        protected static $autoloadDirectories = [];
-       
+
        /**
         * list of unique instances of each core object
         * @var SingletonFactory[]
         */
        protected static $coreObject = [];
-       
+
        /**
         * list of cached core objects
         * @var string[]
         */
        protected static $coreObjectCache = [];
-       
+
        /**
         * database object
         * @var MySQLDatabase
         */
        protected static $dbObj;
-       
+
        /**
         * language object
         * @var \wcf\data\language\Language
         */
        protected static $languageObj;
-       
+
        /**
         * overrides disabled debug mode
         * @var boolean
         */
        protected static $overrideDebugMode = false;
-       
+
        /**
         * session object
         * @var SessionHandler
         */
        protected static $sessionObj;
-       
+
        /**
         * template object
         * @var TemplateEngine
         */
        protected static $tplObj;
-       
+
        /**
         * true if Zend Opcache is loaded and enabled
         * @var boolean
         */
        protected static $zendOpcacheEnabled;
-       
+
        /**
         * force logout during destructor call
         * @var boolean
         */
        protected static $forceLogout = false;
-       
+
        /**
         * Calls all init functions of the WCF class.
         */
        public function __construct() {
                // add autoload directory
                self::$autoloadDirectories['wcf'] = WCF_DIR . 'lib/';
-               
+
                // define tmp directory
                if (!defined('TMP_DIR')) define('TMP_DIR', FileUtil::getTempFolder());
-               
+
                // start initialization
                $this->initDB();
                $this->loadOptions();
@@ -181,13 +181,13 @@ class WCF {
                $this->initCoreObjects();
                $this->initApplications();
                $this->initBlacklist();
-               
+
                EventHandler::getInstance()->fireAction($this, 'initialized');
        }
-       
+
        /**
         * Flushes the output, closes the session, performs background tasks and more.
-        * 
+        *
         * You *must* not create output in here under normal circumstances, as it might get eaten
         * when gzip is enabled.
         */
@@ -195,17 +195,17 @@ class WCF {
                try {
                        // database has to be initialized
                        if (!is_object(self::$dbObj)) return;
-                       
+
                        $debug = self::debugModeIsEnabled(true);
                        if (!$debug) {
                                // flush output
                                if (ob_get_level()) ob_end_flush();
                                flush();
-                               
+
                                // close connection if using FPM
                                if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
                        }
-                       
+
                        // update session
                        if (is_object(self::getSession())) {
                                if (self::$forceLogout) {
@@ -216,7 +216,7 @@ class WCF {
                                        self::getSession()->update();
                                }
                        }
-                       
+
                        // execute shutdown actions of storage handlers
                        RegistryHandler::getInstance()->shutdown();
                        UserStorageHandler::getInstance()->shutdown();
@@ -225,55 +225,55 @@ class WCF {
                        die("<pre>WCF::destruct() Unhandled exception: ".$exception->getMessage()."\n\n".$exception->getTraceAsString());
                }
        }
-       
+
        /**
         * Returns the database object.
-        * 
+        *
         * @return      \wcf\system\database\Database
         */
        public static final function getDB() {
                return self::$dbObj;
        }
-       
+
        /**
         * Returns the session object.
-        * 
+        *
         * @return      SessionHandler
         */
        public static final function getSession() {
                return self::$sessionObj;
        }
-       
+
        /**
         * Returns the user object.
-        * 
+        *
         * @return      \wcf\data\user\User
         */
        public static final function getUser() {
                return self::getSession()->getUser();
        }
-       
+
        /**
         * Returns the language object.
-        * 
+        *
         * @return      \wcf\data\language\Language
         */
        public static final function getLanguage() {
                return self::$languageObj;
        }
-       
+
        /**
         * Returns the template object.
-        * 
+        *
         * @return      TemplateEngine
         */
        public static final function getTPL() {
                return self::$tplObj;
        }
-       
+
        /**
         * Calls the show method on the given exception.
-        * 
+        *
         * @param       \Throwable      $e
         */
        public static final function handleException($e) {
@@ -282,14 +282,14 @@ class WCF {
                        $e->show();
                        exit;
                }
-               
+
                if (ob_get_level()) {
                        // discard any output generated before the exception occurred, prevents exception
                        // being hidden inside HTML elements and therefore not visible in browser output
-                       // 
+                       //
                        // ob_get_level() can return values > 1, if the PHP setting `output_buffering` is on
                        while (ob_get_level()) ob_end_clean();
-                       
+
                        // Some webservers are broken and will apply gzip encoding at all cost, but they fail
                        // to set a proper `Content-Encoding` HTTP header and mess things up even more.
                        // Especially the `identity` value appears to be unrecognized by some of them, hence
@@ -303,22 +303,22 @@ class WCF {
                                        else {
                                                @header('Content-Encoding: gzip');
                                        }
-                                       
+
                                        ob_start(function($output) {
                                                $size = strlen($output);
                                                $crc = crc32($output);
-                                               
+
                                                $newOutput = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff";
                                                $newOutput .= substr(gzcompress($output, 1), 2, -4);
                                                $newOutput .= pack('V', $crc);
                                                $newOutput .= pack('V', $size);
-                                               
+
                                                return $newOutput;
                                        });
                                }
                        }
                }
-               
+
                @header('HTTP/1.1 503 Service Unavailable');
                try {
                        \wcf\functions\exception\printThrowable($e);
@@ -332,10 +332,10 @@ class WCF {
                        exit;
                }
        }
-       
+
        /**
         * Turns PHP errors into an ErrorException.
-        * 
+        *
         * @param       integer         $severity
         * @param       string          $message
         * @param       string          $file
@@ -345,10 +345,10 @@ class WCF {
        public static final function handleError($severity, $message, $file, $line) {
                // this is necessary for the shut-up operator
                if (!(error_reporting() & $severity)) return;
-               
+
                throw new ErrorException($message, 0, $severity, $file, $line);
        }
-       
+
        /**
         * Loads the database configuration and creates a new connection to the database.
         */
@@ -358,11 +358,11 @@ class WCF {
                $dbPort = 0;
                $defaultDriverOptions = [];
                require(WCF_DIR.'config.inc.php');
-               
+
                // create database connection
                self::$dbObj = new MySQLDatabase($dbHost, $dbUser, $dbPassword, $dbName, $dbPort, false, false, $defaultDriverOptions);
        }
-       
+
        /**
         * Loads the options file, automatically created if not exists.
         */
@@ -370,20 +370,20 @@ class WCF {
                // The attachment module is always enabled since 5.2.
                // https://github.com/WoltLab/WCF/issues/2531
                define('MODULE_ATTACHMENT', 1);
-               
+
                // Users cannot react to their own content since 5.2.
                // https://github.com/WoltLab/WCF/issues/2975
                define('LIKE_ALLOW_FOR_OWN_CONTENT', 0);
                define('LIKE_ENABLE_DISLIKE', 0);
-               
+
                // Thumbnails for attachments are already enabled since 5.3.
                // https://github.com/WoltLab/WCF/pull/3444
                define('ATTACHMENT_ENABLE_THUMBNAILS', 1);
-               
+
                // User markings are always applied in sidebars since 5.3.
                // https://github.com/WoltLab/WCF/issues/3330
                define('MESSAGE_SIDEBAR_ENABLE_USER_ONLINE_MARKING', 1);
-               
+
                // Password strength configuration is deprecated since 5.3.
                define('REGISTER_ENABLE_PASSWORD_SECURITY_CHECK', 0);
                define('REGISTER_PASSWORD_MIN_LENGTH', 0);
@@ -395,49 +395,49 @@ class WCF {
                // rel=nofollow is always applied to external link since 5.3
                // https://github.com/WoltLab/WCF/issues/3339
                define('EXTERNAL_LINK_REL_NOFOLLOW', 1);
-               
+
                $filename = WCF_DIR.'options.inc.php';
-               
+
                // create options file if doesn't exist
                if (!file_exists($filename) || filemtime($filename) <= 1) {
                        OptionEditor::rebuild();
                }
                require($filename);
-               
+
                // check if option file is complete and writable
                if (PACKAGE_ID) {
                        if (!is_writable($filename)) {
                                FileUtil::makeWritable($filename);
-                               
+
                                if (!is_writable($filename)) {
                                        throw new SystemException("The option file '" . $filename . "' is not writable.");
                                }
                        }
-                       
+
                        // check if a previous write operation was incomplete and force rebuilding
                        if (!defined('WCF_OPTION_INC_PHP_SUCCESS')) {
                                OptionEditor::rebuild();
-                               
+
                                require($filename);
                        }
-                       
+
                        if (ENABLE_DEBUG_MODE) {
                                self::$dbObj->enableDebugMode();
                        }
                }
        }
-       
+
        /**
         * Starts the session system.
         */
        protected function initSession() {
                $factory = new SessionFactory();
                $factory->load();
-               
+
                self::$sessionObj = SessionHandler::getInstance();
                self::$sessionObj->setHasValidCookie($factory->hasValidCookie());
        }
-       
+
        /**
         * Initialises the language engine.
         */
@@ -445,16 +445,16 @@ class WCF {
                if (isset($_GET['l']) && !self::getUser()->userID) {
                        self::getSession()->setLanguageID(intval($_GET['l']));
                }
-               
+
                // set mb settings
                mb_internal_encoding('UTF-8');
                if (function_exists('mb_regex_encoding')) mb_regex_encoding('UTF-8');
                mb_language('uni');
-               
+
                // get language
                self::$languageObj = LanguageFactory::getInstance()->getUserLanguage(self::getSession()->getLanguageID());
        }
-       
+
        /**
         * Initialises the template engine.
         */
@@ -462,10 +462,10 @@ class WCF {
                self::$tplObj = TemplateEngine::getInstance();
                self::getTPL()->setLanguageID(self::getLanguage()->languageID);
                $this->assignDefaultTemplateVariables();
-               
+
                $this->initStyle();
        }
-       
+
        /**
         * Initializes the user's style.
         */
@@ -473,17 +473,17 @@ class WCF {
                if (isset($_REQUEST['styleID'])) {
                        self::getSession()->setStyleID(intval($_REQUEST['styleID']));
                }
-               
+
                $styleHandler = StyleHandler::getInstance();
                $styleHandler->changeStyle(self::getSession()->getStyleID());
        }
-       
+
        /**
         * Executes the blacklist.
         */
        protected function initBlacklist() {
                $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
-               
+
                if (defined('BLACKLIST_IP_ADDRESSES') && BLACKLIST_IP_ADDRESSES != '') {
                        if (!StringUtil::executeWordFilter(UserUtil::convertIPv6To4(self::getSession()->ipAddress), BLACKLIST_IP_ADDRESSES)) {
                                if ($isAjax) {
@@ -522,7 +522,7 @@ class WCF {
                                }
                        }
                }
-               
+
                // handle banned users
                if (self::getUser()->userID && self::getUser()->banned && !self::getUser()->hasOwnerAccess()) {
                        if ($isAjax) {
@@ -530,7 +530,7 @@ class WCF {
                        }
                        else {
                                self::$forceLogout = true;
-                               
+
                                // remove cookies
                                if (isset($_COOKIE[COOKIE_PREFIX.'userID'])) {
                                        HeaderUtil::setCookie('userID', 0);
@@ -538,36 +538,36 @@ class WCF {
                                if (isset($_COOKIE[COOKIE_PREFIX.'password'])) {
                                        HeaderUtil::setCookie('password', '');
                                }
-                               
+
                                throw new NamedUserException(self::getLanguage()->getDynamicVariable('wcf.user.error.isBanned'));
                        }
                }
        }
-       
+
        /**
         * Initializes applications.
         */
        protected function initApplications() {
                // step 1) load all applications
                $loadedApplications = [];
-               
+
                // register WCF as application
                self::$applications['wcf'] = ApplicationHandler::getInstance()->getApplicationByID(1);
-               
+
                if (!class_exists(WCFACP::class, false)) {
                        static::getTPL()->assign('baseHref', self::$applications['wcf']->getPageURL());
                }
-               
+
                // start main application
                $application = ApplicationHandler::getInstance()->getActiveApplication();
                if ($application->packageID != 1) {
                        $loadedApplications[] = $this->loadApplication($application);
-                       
+
                        // register primary application
                        $abbreviation = ApplicationHandler::getInstance()->getAbbreviation($application->packageID);
                        self::$applications[$abbreviation] = $application;
                }
-               
+
                // start dependent applications
                $applications = ApplicationHandler::getInstance()->getDependentApplications();
                foreach ($applications as $application) {
@@ -579,25 +579,25 @@ class WCF {
                                // ignore apps flagged for uninstallation
                                continue;
                        }
-                       
+
                        $loadedApplications[] = $this->loadApplication($application, true);
                }
-               
+
                // step 2) run each application
                if (!class_exists('wcf\system\WCFACP', false)) {
                        /** @var IApplication $application */
                        foreach ($loadedApplications as $application) {
                                $application->__run();
                        }
-                       
+
                        // refresh the session 1 minute before it expires
                        self::getTPL()->assign('__sessionKeepAlive', SESSION_TIMEOUT - 60);
                }
        }
-       
+
        /**
         * Loads an application.
-        * 
+        *
         * @param       Application             $application
         * @param       boolean                 $isDependentApplication
         * @return      IApplication
@@ -608,7 +608,7 @@ class WCF {
                // package cache might be outdated
                if ($package === null) {
                        $package = new Package($application->packageID);
-                       
+
                        // package cache is outdated, discard cache
                        if ($package->packageID) {
                                PackageEditor::resetCache();
@@ -618,13 +618,13 @@ class WCF {
                                throw new SystemException("application identified by package id '".$application->packageID."' is unknown");
                        }
                }
-               
+
                $abbreviation = ApplicationHandler::getInstance()->getAbbreviation($application->packageID);
                $packageDir = FileUtil::getRealPath(WCF_DIR.$package->packageDir);
                self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/';
-               
+
                $className = $abbreviation.'\system\\'.strtoupper($abbreviation).'Core';
-               
+
                // class was not found, possibly the app was moved, but `packageDir` has not been adjusted
                if (!class_exists($className)) {
                        // check if both the Core and the app are on the same domain
@@ -635,7 +635,7 @@ class WCF {
                                if ($relativePath !== './') {
                                        $packageDir = FileUtil::getRealPath(WCF_DIR.$relativePath);
                                        self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/';
-                                       
+
                                        if (class_exists($className)) {
                                                // the class can now be found, update the `packageDir` value
                                                (new PackageEditor($package))->update(['packageDir' => $relativePath]);
@@ -643,28 +643,28 @@ class WCF {
                                }
                        }
                }
-               
+
                if (class_exists($className) && is_subclass_of($className, IApplication::class)) {
                        // include config file
                        $configPath = $packageDir . PackageInstallationDispatcher::CONFIG_FILE;
                        if (!file_exists($configPath)) {
                                Package::writeConfigFile($package->packageID);
                        }
-                       
+
                        if (file_exists($configPath)) {
                                require_once($configPath);
                        }
                        else {
                                throw new SystemException('Unable to load configuration for '.$package->package);
                        }
-                       
+
                        // register template path if not within ACP
                        if (!class_exists('wcf\system\WCFACP', false)) {
                                // add template path and abbreviation
                                static::getTPL()->addApplication($abbreviation, $packageDir . 'templates/');
                        }
                        EmailTemplateEngine::getInstance()->addApplication($abbreviation, $packageDir . 'templates/');
-                       
+
                        // init application and assign it as template variable
                        self::$applicationObjects[$application->packageID] = call_user_func([$className, 'getInstance']);
                        static::getTPL()->assign('__'.$abbreviation, self::$applicationObjects[$application->packageID]);
@@ -674,7 +674,7 @@ class WCF {
                        unset(self::$autoloadDirectories[$abbreviation]);
                        throw new SystemException("Unable to run '".$package->package."', '".$className."' is missing or does not implement '".IApplication::class."'.");
                }
-               
+
                // register template path in ACP
                if (class_exists('wcf\system\WCFACP', false)) {
                        static::getTPL()->addApplication($abbreviation, $packageDir . 'acp/templates/');
@@ -683,16 +683,16 @@ class WCF {
                        // assign base tag
                        static::getTPL()->assign('baseHref', $application->getPageURL());
                }
-               
+
                // register application
                self::$applications[$abbreviation] = $application;
-               
+
                return self::$applicationObjects[$application->packageID];
        }
-       
+
        /**
         * Returns the corresponding application object. Does not support the 'wcf' pseudo application.
-        * 
+        *
         * @param       Application     $application
         * @return      IApplication
         */
@@ -700,36 +700,36 @@ class WCF {
                if (isset(self::$applicationObjects[$application->packageID])) {
                        return self::$applicationObjects[$application->packageID];
                }
-               
+
                return null;
        }
-       
+
        /**
         * Returns the invoked application.
-        * 
+        *
         * @return      Application
         * @since       3.1
         */
        public static function getActiveApplication() {
                return ApplicationHandler::getInstance()->getActiveApplication();
        }
-       
+
        /**
         * Loads an application on runtime, do not use this outside the package installation.
-        * 
+        *
         * @param       integer         $packageID
         */
        public static function loadRuntimeApplication($packageID) {
                $package = new Package($packageID);
                $application = new Application($packageID);
-               
+
                $abbreviation = Package::getAbbreviation($package->package);
                $packageDir = FileUtil::getRealPath(WCF_DIR.$package->packageDir);
                self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/';
                self::$applications[$abbreviation] = $application;
                self::getTPL()->addApplication($abbreviation, $packageDir . 'acp/templates/');
        }
-       
+
        /**
         * Initializes core object cache.
         */
@@ -738,26 +738,26 @@ class WCF {
                if (PACKAGE_ID == 0) {
                        return;
                }
-               
+
                self::$coreObjectCache = CoreObjectCacheBuilder::getInstance()->getData();
        }
-       
+
        /**
         * Assigns some default variables to the template engine.
         */
        protected function assignDefaultTemplateVariables() {
                $wcf = $this;
-               
+
                if (ENABLE_ENTERPRISE_MODE) {
                        $wcf = new TemplateScriptingCore($wcf);
                }
-               
+
                self::getTPL()->registerPrefilter(['event', 'hascontent', 'lang', 'jslang']);
                self::getTPL()->assign([
                        '__wcf' => $wcf,
                        '__wcfVersion' => LAST_UPDATE_TIME // @deprecated 2.1, use LAST_UPDATE_TIME directly
                ]);
-               
+
                $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
                // Execute background queue in this request, if it was requested and AJAX isn't used.
                if (!$isAjax) {
@@ -765,20 +765,20 @@ class WCF {
                                self::getTPL()->assign([
                                        'forceBackgroundQueuePerform' => true
                                ]);
-                               
+
                                self::getSession()->unregister('forceBackgroundQueuePerform');
                        }
                }
-               
+
                EmailTemplateEngine::getInstance()->registerPrefilter(['event', 'hascontent', 'lang', 'jslang']);
                EmailTemplateEngine::getInstance()->assign([
                        '__wcf' => $wcf
                ]);
        }
-       
+
        /**
         * Wrapper for the getter methods of this class.
-        * 
+        *
         * @param       string          $name
         * @return      mixed           value
         * @throws      SystemException
@@ -788,10 +788,10 @@ class WCF {
                if (method_exists($this, $method)) {
                        return $this->$method();
                }
-               
+
                throw new SystemException("method '".$method."' does not exist in class WCF");
        }
-       
+
        /**
         * Returns true if current application (WCF) is treated as active and was invoked directly.
         *
@@ -800,19 +800,19 @@ class WCF {
        public function isActiveApplication() {
                return (ApplicationHandler::getInstance()->getActiveApplication()->packageID == 1);
        }
-       
+
        /**
         * Changes the active language.
-        * 
+        *
         * @param       integer         $languageID
         */
        public static final function setLanguage($languageID) {
                if (!$languageID || LanguageFactory::getInstance()->getLanguage($languageID) === null) {
                        $languageID = LanguageFactory::getInstance()->getDefaultLanguageID();
                }
-               
+
                self::$languageObj = LanguageFactory::getInstance()->getLanguage($languageID);
-               
+
                // the template engine may not be available yet, usually happens when
                // changing the user (and thus the language id) during session init
                if (self::$tplObj !== null) {
@@ -820,10 +820,10 @@ class WCF {
                        EmailTemplateEngine::getInstance()->setLanguageID(self::getLanguage()->languageID);
                }
        }
-       
+
        /**
         * Includes the required util or exception classes automatically.
-        * 
+        *
         * @param       string          $className
         * @see         spl_autoload_register()
         */
@@ -836,14 +836,14 @@ class WCF {
                        }
                        if (isset(self::$autoloadDirectories[$applicationPrefix])) {
                                $classPath = self::$autoloadDirectories[$applicationPrefix] . implode('/', $namespaces) . '.class.php';
-                               
+
                                // PHP will implicitly check if the file exists when including it, which means that we can save a
                                // redundant syscall/fs access by not checking for existence ourselves. Do not use require_once()!
                                @include_once($classPath);
                        }
                }
        }
-       
+
        /**
         * @inheritDoc
         */
@@ -852,13 +852,13 @@ class WCF {
                if (!method_exists($this, $name)) {
                        return self::__callStatic($name, $arguments);
                }
-               
+
                throw new \BadMethodCallException("Call to undefined method WCF::{$name}().");
        }
-       
+
        /**
         * Returns dynamically loaded core objects.
-        * 
+        *
         * @param       string          $name
         * @param       array           $arguments
         * @return      object
@@ -866,29 +866,29 @@ class WCF {
         */
        public static final function __callStatic($name, array $arguments) {
                $className = preg_replace('~^get~', '', $name);
-               
+
                if (isset(self::$coreObject[$className])) {
                        return self::$coreObject[$className];
                }
-               
+
                $objectName = self::getCoreObject($className);
                if ($objectName === null) {
                        throw new SystemException("Core object '".$className."' is unknown.");
                }
-               
+
                if (class_exists($objectName)) {
                        if (!is_subclass_of($objectName, SingletonFactory::class)) {
                                throw new ParentClassException($objectName, SingletonFactory::class);
                        }
-                       
+
                        self::$coreObject[$className] = call_user_func([$objectName, 'getInstance']);
                        return self::$coreObject[$className];
                }
        }
-       
+
        /**
         * Searches for cached core object definition.
-        * 
+        *
         * @param       string          $className
         * @return      string
         */
@@ -896,13 +896,13 @@ class WCF {
                if (isset(self::$coreObjectCache[$className])) {
                        return self::$coreObjectCache[$className];
                }
-               
+
                return null;
        }
-       
+
        /**
         * Returns true if the debug mode is enabled, otherwise false.
-        * 
+        *
         * @param       boolean         $ignoreACP
         * @return      boolean
         */
@@ -914,13 +914,13 @@ class WCF {
                else if (defined('ENABLE_DEBUG_MODE') && ENABLE_DEBUG_MODE) {
                        return true;
                }
-               
+
                return false;
        }
-       
+
        /**
         * Returns true if benchmarking is enabled, otherwise false.
-        * 
+        *
         * @return      boolean
         */
        public static function benchmarkIsEnabled() {
@@ -928,10 +928,10 @@ class WCF {
                if (!defined('ENABLE_BENCHMARK') || ENABLE_BENCHMARK) return true;
                return false;
        }
-       
+
        /**
         * Returns domain path for given application.
-        * 
+        *
         * @param       string          $abbreviation
         * @return      string
         */
@@ -940,97 +940,97 @@ class WCF {
                if (!PACKAGE_ID) {
                        return '../';
                }
-               
+
                if (!isset(self::$applications[$abbreviation])) {
                        $abbreviation = 'wcf';
                }
-               
+
                return self::$applications[$abbreviation]->getPageURL();
        }
-       
+
        /**
         * Returns the domain path for the currently active application,
         * used to avoid CORS requests.
-        * 
+        *
         * @return      string
         */
        public static function getActivePath() {
                if (!PACKAGE_ID) {
                        return self::getPath();
                }
-               
+
                // We cannot rely on the ApplicationHandler's `getActiveApplication()` because
                // it uses the requested controller to determine the namespace. However, starting
                // with WoltLab Suite 5.2, system pages can be virtually assigned to a different
                // app, resolving against the target app without changing the namespace.
                return self::getPath(ApplicationHandler::getInstance()->getAbbreviation(PACKAGE_ID));
        }
-       
+
        /**
         * Returns a fully qualified anchor for current page.
-        * 
+        *
         * @param       string          $fragment
         * @return      string
         */
        public function getAnchor($fragment) {
                return StringUtil::encodeHTML(self::getRequestURI() . '#' . $fragment);
        }
-       
+
        /**
         * Returns the currently active page or null if unknown.
-        * 
+        *
         * @return      Page|null
         */
        public static function getActivePage() {
                if (self::getActiveRequest() === null) {
                        return null;
                }
-               
+
                if (self::getActiveRequest()->getClassName() === CmsPage::class) {
                        $metaData = self::getActiveRequest()->getMetaData();
                        if (isset($metaData['cms'])) {
                                return PageCache::getInstance()->getPage($metaData['cms']['pageID']);
                        }
-                       
+
                        return null;
                }
-               
+
                return PageCache::getInstance()->getPageByController(self::getActiveRequest()->getClassName());
        }
-       
+
        /**
         * Returns the currently active request.
-        * 
+        *
         * @return Request
         */
        public static function getActiveRequest() {
                return RequestHandler::getInstance()->getActiveRequest();
        }
-       
+
        /**
         * Returns the URI of the current page.
-        * 
+        *
         * @return      string
         */
        public static function getRequestURI() {
                return preg_replace('~^(https?://[^/]+)(?:/.*)?$~', '$1', self::getTPL()->get('baseHref')) . $_SERVER['REQUEST_URI'];
        }
-       
+
        /**
         * Resets Zend Opcache cache if installed and enabled.
-        * 
+        *
         * @param       string          $script
         */
        public static function resetZendOpcache($script = '') {
                if (self::$zendOpcacheEnabled === null) {
                        self::$zendOpcacheEnabled = false;
-                       
+
                        if (extension_loaded('Zend Opcache') && @ini_get('opcache.enable')) {
                                self::$zendOpcacheEnabled = true;
                        }
-                       
+
                }
-               
+
                if (self::$zendOpcacheEnabled) {
                        if (empty($script)) {
                                \opcache_reset();
@@ -1040,16 +1040,16 @@ class WCF {
                        }
                }
        }
-       
+
        /**
         * Returns style handler.
-        * 
+        *
         * @return      StyleHandler
         */
        public function getStyleHandler() {
                return StyleHandler::getInstance();
        }
-       
+
        /**
         * Returns box handler.
         *
@@ -1059,50 +1059,50 @@ class WCF {
        public function getBoxHandler() {
                return BoxHandler::getInstance();
        }
-       
+
        /**
         * Returns number of available updates.
-        * 
+        *
         * @return      integer
         */
        public function getAvailableUpdates() {
                $data = PackageUpdateCacheBuilder::getInstance()->getData();
                return $data['updates'];
        }
-       
+
        /**
         * Returns a 8 character prefix for editor autosave.
-        * 
+        *
         * @return      string
         */
        public function getAutosavePrefix() {
                return substr(sha1(preg_replace('~^https~', 'http', self::getPath())), 0, 8);
        }
-       
+
        /**
         * Returns the favicon URL or a base64 encoded image.
-        * 
+        *
         * @return      string
         */
        public function getFavicon() {
                $activeApplication = ApplicationHandler::getInstance()->getActiveApplication();
                $wcf = ApplicationHandler::getInstance()->getWCF();
                $favicon = StyleHandler::getInstance()->getStyle()->getRelativeFavicon();
-               
+
                if ($activeApplication->domainName !== $wcf->domainName) {
                        if (file_exists(WCF_DIR.$favicon)) {
                                $favicon = file_get_contents(WCF_DIR.$favicon);
-                               
+
                                return 'data:image/x-icon;base64,' . base64_encode($favicon);
                        }
                }
-               
+
                return self::getPath() . $favicon;
        }
-       
+
        /**
         * Returns true if the desktop notifications should be enabled.
-        * 
+        *
         * @return      boolean
         */
        public function useDesktopNotifications() {
@@ -1113,33 +1113,33 @@ class WCF {
                        $application = ApplicationHandler::getInstance()->getApplicationByID(DESKTOP_NOTIFICATION_PACKAGE_ID);
                        // mismatch, default to Core
                        if ($application === null) $application = ApplicationHandler::getInstance()->getApplicationByID(1);
-                       
+
                        $currentApplication = ApplicationHandler::getInstance()->getActiveApplication();
                        if ($currentApplication->domainName != $application->domainName) {
                                // different domain
                                return false;
                        }
                }
-               
+
                return true;
        }
-       
+
        /**
         * Returns true if currently active request represents the landing page.
-        * 
+        *
         * @return      boolean
         */
        public static function isLandingPage() {
                if (self::getActiveRequest() === null) {
                        return false;
                }
-               
+
                return self::getActiveRequest()->isLandingPage();
        }
-       
+
        /**
         * Returns true if the given API version is currently supported.
-        * 
+        *
         * @param       integer         $apiVersion
         * @return      boolean
         * @deprecated 5.2
@@ -1147,17 +1147,17 @@ class WCF {
        public static function isSupportedApiVersion($apiVersion) {
                return ($apiVersion == WSC_API_VERSION) || in_array($apiVersion, self::$supportedLegacyApiVersions);
        }
-       
+
        /**
         * Returns the list of supported legacy API versions.
-        * 
+        *
         * @return      integer[]
         * @deprecated 5.2
         */
        public static function getSupportedLegacyApiVersions() {
                return self::$supportedLegacyApiVersions;
        }
-       
+
        /**
         * Initialises the cronjobs.
         */
@@ -1166,15 +1166,15 @@ class WCF {
                        self::getTPL()->assign('executeCronjobs', CronjobScheduler::getInstance()->getNextExec() < TIME_NOW && defined('OFFLINE') && !OFFLINE);
                }
        }
-       
+
        /**
         * Checks recursively that the most important system files of `com.woltlab.wcf` are writable.
-        * 
+        *
         * @throws      \RuntimeException       if any relevant file or directory is not writable
         */
        public static function checkWritability() {
                $nonWritablePaths = [];
-               
+
                $nonRecursiveDirectories = [
                        '',
                        'acp/',
@@ -1185,12 +1185,12 @@ class WCF {
                        if ($path === 'tmp/' && !is_dir($path)) {
                                continue;
                        }
-                       
+
                        if (!is_writable($path)) {
                                $nonWritablePaths[] = FileUtil::getRelativePath($_SERVER['DOCUMENT_ROOT'], $path);
                                continue;
                        }
-                       
+
                        DirectoryUtil::getInstance($path, false)->executeCallback(function($file, \SplFileInfo $fileInfo) use ($path, &$nonWritablePaths) {
                                if ($fileInfo instanceof \DirectoryIterator) {
                                        if (!is_writable($fileInfo->getPath())) {
@@ -1202,7 +1202,7 @@ class WCF {
                                }
                        });
                }
-               
+
                $recursiveDirectories = [
                        'acp/js/',
                        'acp/style/',
@@ -1216,12 +1216,12 @@ class WCF {
                ];
                foreach ($recursiveDirectories as $directory) {
                        $path = WCF_DIR . $directory;
-                       
+
                        if (!is_writable($path)) {
                                $nonWritablePaths[] = FileUtil::getRelativePath($_SERVER['DOCUMENT_ROOT'], $path);
                                continue;
                        }
-                       
+
                        DirectoryUtil::getInstance($path)->executeCallback(function($file, \SplFileInfo $fileInfo) use ($path, &$nonWritablePaths) {
                                if ($fileInfo instanceof \DirectoryIterator) {
                                        if (!is_writable($fileInfo->getPath())) {
@@ -1233,7 +1233,7 @@ class WCF {
                                }
                        });
                }
-               
+
                if (!empty($nonWritablePaths)) {
                        $maxPaths = 10;
                        throw new \RuntimeException('The following paths are not writable: ' . implode(',', array_slice($nonWritablePaths, 0, $maxPaths)) . (count($nonWritablePaths) > $maxPaths ? ',' . StringUtil::HELLIP : ''));