Merge branch 'master' into next
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / WCF.class.php
index bc02426bac2962e01516b9d6e61fe9e9c5636433..3ab7dc1ac55791383949331b1eece7c1f01bcd72 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 namespace wcf\system;
 use wcf\data\application\Application;
 use wcf\data\option\OptionEditor;
@@ -25,6 +26,7 @@ use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\SystemException;
 use wcf\system\language\LanguageFactory;
 use wcf\system\package\PackageInstallationDispatcher;
+use wcf\system\registry\RegistryHandler;
 use wcf\system\request\Request;
 use wcf\system\request\RequestHandler;
 use wcf\system\session\SessionFactory;
@@ -47,7 +49,10 @@ if (!@ini_get('date.timezone')) {
 }
 
 // define current woltlab suite version
-define('WCF_VERSION', '3.0.13');
+define('WCF_VERSION', '3.1.2 pl 2');
+
+// define current API version
+define('WSC_API_VERSION', 2018);
 
 // define current unix timestamp
 define('TIME_NOW', time());
@@ -63,11 +68,17 @@ if (!defined('NO_IMPORTS')) {
  * It holds the database connection, access to template and language engine.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2017 WoltLab GmbH
+ * @copyright  2001-2018 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System
  */
 class WCF {
+       /**
+        * list of supported legacy API versions
+        * @var integer[]
+        */
+       private static $supportedLegacyApiVersions = [2017];
+       
        /**
         * list of currently loaded applications
         * @var Application[]
@@ -196,7 +207,8 @@ class WCF {
                                }
                        }
                        
-                       // execute shutdown actions of user storage handler
+                       // execute shutdown actions of storage handlers
+                       RegistryHandler::getInstance()->shutdown();
                        UserStorageHandler::getInstance()->shutdown();
                }
                catch (\Exception $exception) {
@@ -262,7 +274,7 @@ class WCF {
                }
                
                if (ob_get_level()) {
-                       // discard any output generated before the exception occured, prevents exception
+                       // 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
@@ -273,9 +285,9 @@ class WCF {
                        // Especially the `identity` value appears to be unrecognized by some of them, hence
                        // we'll just gzip the output of the exception to prevent them from tampering.
                        // This part is copied from `HeaderUtil` in order to isolate the exception handler!
-                       if (HTTP_ENABLE_GZIP && !defined('HTTP_DISABLE_GZIP')) {
-                               if (function_exists('gzcompress') && !@ini_get('zlib.output_compression') && !@ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
-                                       if (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip')) {
+                       if (defined('HTTP_ENABLE_GZIP') && HTTP_ENABLE_GZIP && !defined('HTTP_DISABLE_GZIP')) {
+                               if (function_exists('gzcompress') && !@ini_get('zlib.output_compression') && !@ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {
+                                       if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false) {
                                                @header('Content-Encoding: x-gzip');
                                        }
                                        else {
@@ -309,14 +321,6 @@ class WCF {
                        echo "\n\nwas handled.</pre>";
                        exit;
                }
-               catch (\Exception $e2) {
-                       echo "<pre>An Exception was thrown while handling an Exception:\n\n";
-                       echo preg_replace('/Database->__construct\(.*\)/', 'Database->__construct(...)', $e2);
-                       echo "\n\nwas thrown while:\n\n";
-                       echo preg_replace('/Database->__construct\(.*\)/', 'Database->__construct(...)', $e);
-                       echo "\n\nwas handled.</pre>";
-                       exit;
-               }
        }
        
        /**
@@ -576,6 +580,26 @@ class WCF {
                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
+                       $coreApp = ApplicationHandler::getInstance()->getApplicationByID(1);
+                       if ($coreApp->domainName === $application->domainName) {
+                               // resolve the relative path and use it to construct the autoload directory
+                               $relativePath = FileUtil::getRelativePath($coreApp->domainPath, $application->domainPath);
+                               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]);
+                                       }
+                               }
+                       }
+               }
+               
                if (class_exists($className) && is_subclass_of($className, IApplication::class)) {
                        // include config file
                        $configPath = $packageDir . PackageInstallationDispatcher::CONFIG_FILE;
@@ -636,6 +660,16 @@ class WCF {
                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.
         * 
@@ -998,16 +1032,41 @@ class WCF {
        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.'images/favicon.ico')) {
-                               $favicon = file_get_contents(WCF_DIR.'images/favicon.ico');
+                       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() . 'images/favicon.ico';
+               return self::getPath() . $favicon;
+       }
+       
+       /**
+        * Returns true if the desktop notifications should be enabled.
+        * 
+        * @return      boolean
+        */
+       public function useDesktopNotifications() {
+               if (!ENABLE_DESKTOP_NOTIFICATIONS) {
+                       return false;
+               }
+               else if (ApplicationHandler::getInstance()->isMultiDomainSetup()) {
+                       $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;
        }
        
        /**
@@ -1023,6 +1082,25 @@ class WCF {
                return self::getActiveRequest()->isLandingPage();
        }
        
+       /**
+        * Returns true if the given API version is currently supported.
+        * 
+        * @param       integer         $apiVersion
+        * @return      boolean
+        */
+       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[]
+        */
+       public static function getSupportedLegacyApiVersions() {
+               return self::$supportedLegacyApiVersions;
+       }
+       
        /**
         * Initialises the cronjobs.
         */