[BUGFIX] Make environment check standalone 61/42861/11
authorMathias Brodala <mbrodala@pagemachine.de>
Tue, 25 Aug 2015 07:45:15 +0000 (09:45 +0200)
committerAndreas Wolf <andreas.wolf@typo3.org>
Sun, 6 Mar 2016 01:02:37 +0000 (02:02 +0100)
The system environment check is supposed to be useable standalone
without any TYPO3 internal requirements.

Move all checks which require a fully set up TYPO3 installation
into a separate class and use it where necessary.

Resolves: #69495
Releases: master
Change-Id: I9f78f8c03a28d18a6daa326b321db721800e7599
Reviewed-on: https://review.typo3.org/42861
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Andreas Wolf <andreas.wolf@typo3.org>
Tested-by: Andreas Wolf <andreas.wolf@typo3.org>
typo3/sysext/install/Classes/Controller/Action/Ajax/EnvironmentStatus.php
typo3/sysext/install/Classes/Controller/Action/Common/InstallToolDisabledAction.php
typo3/sysext/install/Classes/Controller/Action/Step/EnvironmentAndFolders.php
typo3/sysext/install/Classes/Controller/Action/Tool/SystemEnvironment.php
typo3/sysext/install/Classes/Report/EnvironmentStatusReport.php
typo3/sysext/install/Classes/SystemEnvironment/Check.php
typo3/sysext/install/Classes/SystemEnvironment/SetupCheck.php [new file with mode: 0644]

index 9848458..cac98ef 100644 (file)
@@ -15,6 +15,10 @@ namespace TYPO3\CMS\Install\Controller\Action\Ajax;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status\StatusUtility;
+use TYPO3\CMS\Install\SystemEnvironment\Check;
+use TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck;
+use TYPO3\CMS\Install\SystemEnvironment\SetupCheck;
 
 /**
  * Environment status check for errors
@@ -28,17 +32,16 @@ class EnvironmentStatus extends AbstractAjaxAction
      */
     protected function executeAction()
     {
+        // Count of failed checks to be displayed in the left navigation menu
+        $statusObjects = array_merge(
+            GeneralUtility::makeInstance(Check::class)->getStatus(),
+            GeneralUtility::makeInstance(SetupCheck::class)->getStatus(),
+            GeneralUtility::makeInstance(DatabaseCheck::class)->getStatus()
+        );
         /** @var \TYPO3\CMS\Install\Status\StatusUtility $statusUtility */
-        $statusUtility = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\StatusUtility::class);
+        $statusUtility = GeneralUtility::makeInstance(StatusUtility::class);
+        $errors = $statusUtility->filterBySeverity($statusObjects, 'error');
 
-        // Count of failed environment checks to be displayed in the left navigation menu
-        $environmentStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class)->getStatus();
-        $environmentErrors = $statusUtility->filterBySeverity($environmentStatus, 'error');
-
-        // Count of failed database checks to be displayed in the left navigation menu
-        $databaseStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class)->getStatus();
-        $databaseErrors = $statusUtility->filterBySeverity($databaseStatus, 'error');
-
-        return count($environmentErrors) + count($databaseErrors);
+        return count($errors);
     }
 }
index 6590b15..3752f68 100644 (file)
@@ -16,6 +16,9 @@ namespace TYPO3\CMS\Install\Controller\Action\Common;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Controller\Action;
+use TYPO3\CMS\Install\Status\StatusUtility;
+use TYPO3\CMS\Install\SystemEnvironment\Check;
+use TYPO3\CMS\Install\SystemEnvironment\SetupCheck;
 
 /**
  * Welcome page
@@ -29,13 +32,15 @@ class InstallToolDisabledAction extends Action\AbstractAction
      */
     protected function executeAction()
     {
-        /** @var \TYPO3\CMS\Install\SystemEnvironment\Check $statusCheck */
-        $statusCheck = GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class);
-        $statusObjects = $statusCheck->getStatus();
+        $statusObjects = array_merge(
+            GeneralUtility::makeInstance(Check::class)->getStatus(),
+            GeneralUtility::makeInstance(SetupCheck::class)->getStatus()
+        );
         /** @var \TYPO3\CMS\Install\Status\StatusUtility $statusUtility */
-        $statusUtility = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\StatusUtility::class);
+        $statusUtility = GeneralUtility::makeInstance(StatusUtility::class);
         $alerts = $statusUtility->filterBySeverity($statusObjects, 'alert');
         $this->view->assign('alerts', $alerts);
+
         return $this->view->render();
     }
 }
index 4c7daec..46df25c 100644 (file)
@@ -15,6 +15,9 @@ namespace TYPO3\CMS\Install\Controller\Action\Step;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status\StatusUtility;
+use TYPO3\CMS\Install\SystemEnvironment\Check;
+use TYPO3\CMS\Install\SystemEnvironment\SetupCheck;
 
 /**
  * Very first install step:
@@ -40,7 +43,7 @@ class EnvironmentAndFolders extends AbstractStepAction
         $structureFacade = $folderStructureFactory->getStructure();
         $structureFixMessages = $structureFacade->fix();
         /** @var \TYPO3\CMS\Install\Status\StatusUtility $statusUtility */
-        $statusUtility = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\StatusUtility::class);
+        $statusUtility = GeneralUtility::makeInstance(StatusUtility::class);
         $errorsFromStructure = $statusUtility->filterBySeverity($structureFixMessages, 'error');
 
         if (@is_dir(PATH_typo3conf)) {
@@ -95,11 +98,12 @@ class EnvironmentAndFolders extends AbstractStepAction
      */
     protected function executeAction()
     {
-        /** @var \TYPO3\CMS\Install\SystemEnvironment\Check $statusCheck */
-        $statusCheck = GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class);
-        $statusObjects = $statusCheck->getStatus();
+        $statusObjects = array_merge(
+            GeneralUtility::makeInstance(Check::class)->getStatus(),
+            GeneralUtility::makeInstance(SetupCheck::class)->getStatus()
+        );
         /** @var \TYPO3\CMS\Install\Status\StatusUtility $statusUtility */
-        $statusUtility = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\StatusUtility::class);
+        $statusUtility = GeneralUtility::makeInstance(StatusUtility::class);
         $environmentStatus = $statusUtility->sortBySeverity($statusObjects);
         $alerts = $statusUtility->filterBySeverity($statusObjects, 'alert');
         $this->view->assign('alerts', $alerts);
index 528af16..8d55ac3 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Install\Controller\Action;
 use TYPO3\CMS\Install\Status\StatusUtility;
 use TYPO3\CMS\Install\SystemEnvironment\Check;
 use TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck;
+use TYPO3\CMS\Install\SystemEnvironment\SetupCheck;
 
 /**
  * Show system environment check results
@@ -32,13 +33,11 @@ class SystemEnvironment extends Action\AbstractAction
      */
     protected function executeAction()
     {
-        /** @var $statusCheck Check */
-        $statusCheck = GeneralUtility::makeInstance(Check::class);
-        $statusObjects = $statusCheck->getStatus();
-
-        /** @var $statusCheck DatabaseCheck */
-        $databaseStatusCheck = GeneralUtility::makeInstance(DatabaseCheck::class);
-        $statusObjects = array_merge($statusObjects, $databaseStatusCheck->getStatus());
+        $statusObjects = array_merge(
+            GeneralUtility::makeInstance(Check::class)->getStatus(),
+            GeneralUtility::makeInstance(SetupCheck::class)->getStatus(),
+            GeneralUtility::makeInstance(DatabaseCheck::class)->getStatus()
+        );
 
         /** @var $statusUtility StatusUtility */
         $statusUtility = GeneralUtility::makeInstance(StatusUtility::class);
index 04c72d4..5296e53 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Install\Report;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Reports\ExtendedStatusProviderInterface;
 use TYPO3\CMS\Reports\StatusProviderInterface;
 
@@ -49,14 +50,11 @@ class EnvironmentStatusReport implements StatusProviderInterface, ExtendedStatus
      */
     protected function getStatusInternal($verbose)
     {
-        /** @var $statusCheck \TYPO3\CMS\Install\SystemEnvironment\Check */
-        $statusCheck = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class);
-        $statusObjects = $statusCheck->getStatus();
-
-        /** @var $statusCheck \TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck */
-        $databaseStatusCheck = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class);
-        $statusObjects = array_merge($statusObjects, $databaseStatusCheck->getStatus());
-
+        $statusObjects = array_merge(
+            GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class)->getStatus(),
+            GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\SetupCheck::class)->getStatus(),
+            GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class)->getStatus()
+        );
         $reportStatusTypes = array(
             'error' => array(),
             'warning' => array(),
@@ -94,7 +92,7 @@ class EnvironmentStatusReport implements StatusProviderInterface, ExtendedStatus
                     $message = $GLOBALS['LANG']->sL($pathToXliff . ':environment.status.message.' . $type);
                 }
                 $severity = constant('\TYPO3\CMS\Reports\Status::' . strtoupper($type));
-                $statusArray[] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
+                $statusArray[] = GeneralUtility::makeInstance(
                     \TYPO3\CMS\Reports\Status::class,
                     $GLOBALS['LANG']->sL($pathToXliff . ':environment.status.title'),
                     sprintf($GLOBALS['LANG']->sL($pathToXliff . ':environment.status.value'), $value),
index a7876b0..84599e7 100644 (file)
@@ -14,8 +14,6 @@ namespace TYPO3\CMS\Install\SystemEnvironment;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Service\OpcodeCacheService;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Status;
 
 /**
@@ -74,51 +72,49 @@ class Check
      */
     public function getStatus()
     {
-        $statusArray = array();
-        $statusArray[] = $this->checkCurrentDirectoryIsInIncludePath();
-        $statusArray[] = $this->checkTrustedHostPattern();
-        $statusArray[] = $this->checkFileUploadEnabled();
-        $statusArray[] = $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
-        $statusArray[] = $this->checkMemorySettings();
-        $statusArray[] = $this->checkPhpVersion();
-        $statusArray[] = $this->checkMaxExecutionTime();
-        $statusArray[] = $this->checkDisableFunctions();
-        $statusArray[] = $this->checkDownloadsPossible();
-        $statusArray[] = $this->checkMysqliReconnectSetting();
-        $statusArray[] = $this->checkDocRoot();
-        $statusArray[] = $this->checkOpenBaseDir();
-        $statusArray[] = $this->checkXdebugMaxNestingLevel();
-        $statusArray[] = $this->checkOpenSslInstalled();
+        $status = array();
+        $status[] = $this->checkCurrentDirectoryIsInIncludePath();
+        $status[] = $this->checkFileUploadEnabled();
+        $status[] = $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
+        $status[] = $this->checkMemorySettings();
+        $status[] = $this->checkPhpVersion();
+        $status[] = $this->checkMaxExecutionTime();
+        $status[] = $this->checkDisableFunctions();
+        $status[] = $this->checkMysqliReconnectSetting();
+        $status[] = $this->checkDocRoot();
+        $status[] = $this->checkOpenBaseDir();
+        $status[] = $this->checkXdebugMaxNestingLevel();
+        $status[] = $this->checkOpenSslInstalled();
+
         if ($this->isSuhosinLoadedAndActive()) {
-            $statusArray[] = $this->getSuhosinLoadedStatus();
-            $statusArray[] = $this->checkSuhosinRequestMaxVars();
-            $statusArray[] = $this->checkSuhosinRequestMaxVarnameLength();
-            $statusArray[] = $this->checkSuhosinPostMaxNameLength();
-            $statusArray[] = $this->checkSuhosinPostMaxVars();
-            $statusArray[] = $this->checkSuhosinGetMaxNameLength();
-            $statusArray[] = $this->checkSuhosinGetMaxValueLength();
-            $statusArray[] = $this->checkSuhosinExecutorIncludeWhiteListContainsPhar();
-            $statusArray[] = $this->checkSuhosinExecutorIncludeWhiteListContainsVfs();
+            $status[] = $this->getSuhosinLoadedStatus();
+            $status[] = $this->checkSuhosinRequestMaxVars();
+            $status[] = $this->checkSuhosinRequestMaxVarnameLength();
+            $status[] = $this->checkSuhosinPostMaxNameLength();
+            $status[] = $this->checkSuhosinPostMaxVars();
+            $status[] = $this->checkSuhosinGetMaxNameLength();
+            $status[] = $this->checkSuhosinGetMaxValueLength();
+            $status[] = $this->checkSuhosinExecutorIncludeWhiteListContainsPhar();
+            $status[] = $this->checkSuhosinExecutorIncludeWhiteListContainsVfs();
         }
-        $statusArray[] = $this->checkMaxInputVars();
-        $statusArray[] = $this->checkSomePhpOpcodeCacheIsLoaded();
-        $statusArray[] = $this->checkReflectionDocComment();
-        $statusArray[] = $this->checkSystemLocale();
-        $statusArray[] = $this->checkLocaleWithUTF8filesystem();
-        $statusArray[] = $this->checkWindowsApacheThreadStackSize();
+
+        $status[] = $this->checkMaxInputVars();
+        $status[] = $this->checkReflectionDocComment();
+        $status[] = $this->checkWindowsApacheThreadStackSize();
+
         foreach ($this->requiredPhpExtensions as $extension) {
-            $statusArray[] = $this->checkRequiredPhpExtension($extension);
+            $status[] = $this->checkRequiredPhpExtension($extension);
         }
-        $statusArray[] = $this->checkPcreVersion();
-        $statusArray[] = $this->checkGdLibTrueColorSupport();
-        $statusArray[] = $this->checkGdLibGifSupport();
-        $statusArray[] = $this->checkGdLibJpgSupport();
-        $statusArray[] = $this->checkGdLibPngSupport();
-        $statusArray[] = $this->checkGdLibFreeTypeSupport();
-        $statusArray[] = $this->checkRegisterGlobals();
-        $statusArray[] = $this->checkLibXmlBug();
-        $statusArray[] = $this->isTrueTypeFontWorking();
-        return $statusArray;
+
+        $status[] = $this->checkPcreVersion();
+        $status[] = $this->checkGdLibTrueColorSupport();
+        $status[] = $this->checkGdLibGifSupport();
+        $status[] = $this->checkGdLibJpgSupport();
+        $status[] = $this->checkGdLibPngSupport();
+        $status[] = $this->checkGdLibFreeTypeSupport();
+        $status[] = $this->checkRegisterGlobals();
+
+        return $status;
     }
 
     /**
@@ -149,31 +145,6 @@ class Check
     }
 
     /**
-     * Checks the status of the trusted hosts pattern check
-     *
-     * @return Status\StatusInterface
-     */
-    protected function checkTrustedHostPattern()
-    {
-        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
-            $status = new Status\WarningStatus();
-            $status->setTitle('Trusted hosts pattern is insecure');
-            $status->setMessage('Trusted hosts pattern is configured to allow all header values. Check the pattern defined in Install Tool -> All configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).');
-        } else {
-            if (GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST'])) {
-                $status = new Status\OkStatus();
-                $status->setTitle('Trusted hosts pattern is configured to allow current host value.');
-            } else {
-                $status = new Status\ErrorStatus();
-                $status->setTitle('Trusted hosts pattern mismatch');
-                $status->setMessage('The trusted hosts pattern will be configured to allow all header values. This is because your $SERVER_NAME is "' . htmlspecialchars($_SERVER['SERVER_NAME']) . '" while your HTTP_HOST is "' . htmlspecialchars($_SERVER['HTTP_HOST']) . '". Check the pattern defined in Install Tool -> All configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).');
-            }
-        }
-
-        return $status;
-    }
-
-    /**
      * Check if file uploads are enabled in PHP
      *
      * @return Status\StatusInterface
@@ -435,29 +406,6 @@ class Check
     }
 
     /**
-     * Check if it is possible to download external data (e.g. TER)
-     * Either allow_url_fopen must be enabled or curl must be used
-     *
-     * @return Status\OkStatus|Status\WarningStatus
-     */
-    protected function checkDownloadsPossible()
-    {
-        $allowUrlFopen = (bool)ini_get('allow_url_fopen');
-        $curlEnabled = !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse']);
-        if ($allowUrlFopen || $curlEnabled) {
-            $status = new Status\OkStatus();
-            $status->setTitle('Fetching external URLs is allowed');
-        } else {
-            $status = new Status\WarningStatus();
-            $status->setTitle('Fetching external URLs is not allowed');
-            $status->setMessage(
-                'Either enable PHP runtime setting "allow_url_fopen"' . LF . 'or enable curl by setting [SYS][curlUse] accordingly.'
-            );
-        }
-        return $status;
-    }
-
-    /**
      * Verify that mysqli.reconnect is set to 0 in order to avoid improper reconnects
      *
      * @return Status\StatusInterface
@@ -951,74 +899,6 @@ class Check
     }
 
     /**
-     * Check if some opcode cache is loaded
-     *
-     * @return Status\StatusInterface
-     */
-    protected function checkSomePhpOpcodeCacheIsLoaded()
-    {
-        // Link to our wiki page, so we can update opcode cache issue information independent of TYPO3 CMS releases.
-        $wikiLink = 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.';
-        $opcodeCaches = GeneralUtility::makeInstance(OpcodeCacheService::class)->getAllActive();
-        if (empty($opcodeCaches)) {
-            // Set status to notice. It needs to be notice so email won't be triggered.
-            $status = new Status\NoticeStatus();
-            $status->setTitle('No PHP opcode cache loaded');
-            $status->setMessage(
-                'PHP opcode caches hold a compiled version of executed PHP scripts in' .
-                ' memory and do not require to recompile a script each time it is accessed.' .
-                ' This can be a massive performance improvement and can reduce the load on a' .
-                ' server in general. A parse time reduction by factor three for fully cached' .
-                ' pages can be achieved easily if using an opcode cache.' .
-                LF . $wikiLink
-            );
-        } else {
-            $status = new Status\OkStatus();
-            $message = '';
-
-            foreach ($opcodeCaches as $opcodeCache => $properties) {
-                $message .= 'Name: ' . $opcodeCache . ' Version: ' . $properties['version'];
-                $message .= LF;
-
-                if ($properties['error']) {
-                    // Set status to error if not already set
-                    if ($status->getSeverity() !== 'error') {
-                        $status = new Status\ErrorStatus();
-                    }
-                    $message .= ' This opcode cache is marked as malfunctioning by the TYPO3 CMS Team.';
-                } elseif ($properties['canInvalidate']) {
-                    $message .= ' This opcode cache should work correctly and has good performance.';
-                } else {
-                    // Set status to notice if not already error set. It needs to be notice so email won't be triggered.
-                    if ($status->getSeverity() !== 'error' || $status->getSeverity() !== 'warning') {
-                        $status = new Status\NoticeStatus();
-                    }
-                    $message .= ' This opcode cache may work correctly but has medium performance.';
-                }
-                $message .= LF;
-            }
-
-            $message .= $wikiLink;
-
-            // Set title of status depending on serverity
-            switch ($status->getSeverity()) {
-                case 'error':
-                    $status->setTitle('A possibly malfunctioning PHP opcode cache is loaded');
-                    break;
-                case 'warning':
-                    $status->setTitle('A PHP opcode cache is loaded which may cause problems');
-                    break;
-                case 'ok':
-                default:
-                    $status->setTitle('A PHP opcode cache is loaded');
-                    break;
-            }
-            $status->setMessage($message);
-        }
-        return $status;
-    }
-
-    /**
      * Check doc comments can be fetched by reflection
      *
      * @return Status\StatusInterface
@@ -1054,84 +934,6 @@ class Check
     }
 
     /**
-     * Check if systemLocale setting is correct (locale exists in the OS)
-     *
-     * @return Status\StatusInterface
-     */
-    protected function checkSystemLocale()
-    {
-        $currentLocale = setlocale(LC_CTYPE, 0);
-
-        // On Windows an empty locale value uses the regional settings from the Control Panel
-        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
-            $status = new Status\InfoStatus();
-            $status->setTitle('Empty systemLocale setting');
-            $status->setMessage(
-                '$GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is not set. This is fine as long as no UTF-8' .
-                ' file system is used.'
-            );
-        } elseif (setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']) === false) {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('Incorrect systemLocale setting');
-            $status->setMessage(
-                'Current value of the $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is incorrect. A locale with' .
-                ' this name doesn\'t exist in the operating system.'
-            );
-            setlocale(LC_CTYPE, $currentLocale);
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('System locale is correct');
-        }
-
-        return $status;
-    }
-
-    /**
-     * Checks whether we can use file names with UTF-8 characters.
-     * Configured system locale must support UTF-8 when UTF8filesystem is set
-     *
-     * @return Status\StatusInterface
-     */
-    protected function checkLocaleWithUTF8filesystem()
-    {
-        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
-            // On Windows an empty local value uses the regional settings from the Control Panel
-            if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
-                $status = new Status\ErrorStatus();
-                $status->setTitle('System locale not set on UTF-8 file system');
-                $status->setMessage(
-                    '$GLOBALS[TYPO3_CONF_VARS][SYS][UTF8filesystem] is set, but $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale]' .
-                    ' is empty. Make sure a valid locale which supports UTF-8 is set.'
-                );
-            } else {
-                $testString = 'ÖöĄĆŻĘĆćążąęó.jpg';
-                $currentLocale = setlocale(LC_CTYPE, 0);
-                $quote = TYPO3_OS === 'WIN' ? '"' : '\'';
-
-                setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
-
-                if (escapeshellarg($testString) === $quote . $testString . $quote) {
-                    $status = new Status\OkStatus();
-                    $status->setTitle('File names with UTF-8 characters can be used.');
-                } else {
-                    $status = new Status\ErrorStatus();
-                    $status->setTitle('System locale setting doesn\'t support UTF-8 file names.');
-                    $status->setMessage(
-                        'Please check your $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] setting.'
-                    );
-                }
-
-                setlocale(LC_CTYPE, $currentLocale);
-            }
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('Skipping test, as UTF8filesystem is not enabled.');
-        }
-
-        return $status;
-    }
-
-    /**
      * Checks thread stack size if on windows with apache
      *
      * @return Status\StatusInterface
@@ -1225,7 +1027,8 @@ class Check
             && function_exists('imagegif')
             && (imagetypes() & IMG_GIF)
         ) {
-            $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif');
+            // See http://stackoverflow.com/a/13139830
+            $imageResource = @imagecreatefromgif('data://image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
             if (is_resource($imageResource)) {
                 imagedestroy($imageResource);
                 $status = new Status\OkStatus();
@@ -1284,7 +1087,7 @@ class Check
             && function_exists('imagepng')
             && (imagetypes() & IMG_PNG)
         ) {
-            $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png');
+            $imageResource = @imagecreatefrompng('data://image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII');
             if (is_resource($imageResource)) {
                 imagedestroy($imageResource);
                 $status = new Status\OkStatus();
@@ -1337,48 +1140,6 @@ class Check
     }
 
     /**
-     * Create true type font test image
-     *
-     * @return Status\StatusInterface
-     */
-    protected function isTrueTypeFontWorking()
-    {
-        if (function_exists('imageftbbox')) {
-            // 20 Pixels at 96 DPI
-            $fontSize = (20 / 96 * 72);
-            $textDimensions = @imageftbbox(
-                $fontSize,
-                0,
-                __DIR__ . '/../../Resources/Private/Font/vera.ttf',
-                'Testing true type support'
-            );
-            $fontBoxWidth = $textDimensions[2] - $textDimensions[0];
-            if ($fontBoxWidth < 300 && $fontBoxWidth > 200) {
-                $status = new Status\OkStatus();
-                $status->setTitle('FreeType True Type Font DPI');
-                $status->setMessage('Fonts are rendered by FreeType library. ' .
-                    'We need to ensure that the final dimensions are as expected. ' .
-                    'This server renderes fonts based on 96 DPI correctly');
-            } else {
-                $status = new Status\NoticeStatus();
-                $status->setTitle('FreeType True Type Font DPI');
-                $status->setMessage('Fonts are rendered by FreeType library. ' .
-                    'This server does not render fonts as expected. ' .
-                    'Please check your FreeType 2 module.');
-            }
-        } else {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('PHP GD library freetype2 support missing');
-            $status->setMessage(
-                'The core relies on GD library compiled into PHP with freetype2' .
-                ' support. This is missing on your system. Please install it.'
-            );
-        }
-
-        return $status;
-    }
-
-    /**
      * Check register globals
      *
      * @return Status\StatusInterface
@@ -1408,34 +1169,6 @@ class Check
     }
 
     /**
-     * Check for bug in libxml
-     *
-     * @return Status\StatusInterface
-     */
-    protected function checkLibXmlBug()
-    {
-        $sampleArray = array('Test>><<Data');
-
-        $xmlContent = '<numIndex index="0">Test&gt;&gt;&lt;&lt;Data</numIndex>' . LF;
-
-        $xml = \TYPO3\CMS\Core\Utility\GeneralUtility::array2xml($sampleArray, '', -1);
-
-        if ($xmlContent !== $xml) {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('PHP libxml bug present');
-            $status->setMessage(
-                'Some hosts have problems saving ">><<" in a flexform.' .
-                ' To fix this, enable [BE][flexformForceCDATA] in' .
-                ' All Configuration.'
-            );
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('PHP libxml bug not present');
-        }
-        return $status;
-    }
-
-    /**
      * Helper methods
      */
 
diff --git a/typo3/sysext/install/Classes/SystemEnvironment/SetupCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/SetupCheck.php
new file mode 100644 (file)
index 0000000..5f1daf4
--- /dev/null
@@ -0,0 +1,309 @@
+<?php
+namespace TYPO3\CMS\Install\SystemEnvironment;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Service\OpcodeCacheService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status;
+
+/**
+ * Check TYPO3 setup status
+ *
+ * This class is a hardcoded requirement check for the TYPO3 setup.
+ *
+ * The status messages and title *must not* include HTML, use plain
+ * text only. The return values of this class are not bound to HTML
+ * and can be used in different scopes (eg. as json array).
+ */
+class SetupCheck
+{
+    /**
+     * Get all status information as array with status objects
+     *
+     * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
+     */
+    public function getStatus()
+    {
+        $status = [];
+
+        $status[] = $this->checkTrustedHostPattern();
+        $status[] = $this->checkDownloadsPossible();
+        $status[] = $this->checkSystemLocale();
+        $status[] = $this->checkLocaleWithUTF8filesystem();
+        $status[] = $this->checkSomePhpOpcodeCacheIsLoaded();
+        $status[] = $this->isTrueTypeFontWorking();
+        $status[] = $this->checkLibXmlBug();
+
+        return $status;
+    }
+
+    /**
+     * Checks the status of the trusted hosts pattern check
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkTrustedHostPattern()
+    {
+        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
+            $status = new Status\WarningStatus();
+            $status->setTitle('Trusted hosts pattern is insecure');
+            $status->setMessage('Trusted hosts pattern is configured to allow all header values. Check the pattern defined in Install Tool -> All configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).');
+        } else {
+            if (GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST'])) {
+                $status = new Status\OkStatus();
+                $status->setTitle('Trusted hosts pattern is configured to allow current host value.');
+            } else {
+                $status = new Status\ErrorStatus();
+                $status->setTitle('Trusted hosts pattern mismatch');
+                $status->setMessage('The trusted hosts pattern will be configured to allow all header values. This is because your $SERVER_NAME is "' . htmlspecialchars($_SERVER['SERVER_NAME']) . '" while your HTTP_HOST is "' . htmlspecialchars($_SERVER['HTTP_HOST']) . '". Check the pattern defined in Install Tool -> All configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).');
+            }
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check if it is possible to download external data (e.g. TER)
+     * Either allow_url_fopen must be enabled or curl must be used
+     *
+     * @return Status\OkStatus|Status\WarningStatus
+     */
+    protected function checkDownloadsPossible()
+    {
+        $allowUrlFopen = (bool)ini_get('allow_url_fopen');
+        $curlEnabled = !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse']);
+        if ($allowUrlFopen || $curlEnabled) {
+            $status = new Status\OkStatus();
+            $status->setTitle('Fetching external URLs is allowed');
+        } else {
+            $status = new Status\WarningStatus();
+            $status->setTitle('Fetching external URLs is not allowed');
+            $status->setMessage(
+                'Either enable PHP runtime setting "allow_url_fopen"' . LF . 'or enable curl by setting [SYS][curlUse] accordingly.'
+            );
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check if systemLocale setting is correct (locale exists in the OS)
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkSystemLocale()
+    {
+        $currentLocale = setlocale(LC_CTYPE, 0);
+
+        // On Windows an empty locale value uses the regional settings from the Control Panel
+        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
+            $status = new Status\InfoStatus();
+            $status->setTitle('Empty systemLocale setting');
+            $status->setMessage(
+                '$GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is not set. This is fine as long as no UTF-8' .
+                ' file system is used.'
+            );
+        } elseif (setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']) === false) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('Incorrect systemLocale setting');
+            $status->setMessage(
+                'Current value of the $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is incorrect. A locale with' .
+                ' this name doesn\'t exist in the operating system.'
+            );
+            setlocale(LC_CTYPE, $currentLocale);
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('System locale is correct');
+        }
+
+        return $status;
+    }
+
+    /**
+     * Checks whether we can use file names with UTF-8 characters.
+     * Configured system locale must support UTF-8 when UTF8filesystem is set
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkLocaleWithUTF8filesystem()
+    {
+        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
+            // On Windows an empty local value uses the regional settings from the Control Panel
+            if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
+                $status = new Status\ErrorStatus();
+                $status->setTitle('System locale not set on UTF-8 file system');
+                $status->setMessage(
+                    '$GLOBALS[TYPO3_CONF_VARS][SYS][UTF8filesystem] is set, but $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale]' .
+                    ' is empty. Make sure a valid locale which supports UTF-8 is set.'
+                );
+            } else {
+                $testString = 'ÖöĄĆŻĘĆćążąęó.jpg';
+                $currentLocale = setlocale(LC_CTYPE, 0);
+                $quote = TYPO3_OS === 'WIN' ? '"' : '\'';
+                setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
+                if (escapeshellarg($testString) === $quote . $testString . $quote) {
+                    $status = new Status\OkStatus();
+                    $status->setTitle('File names with UTF-8 characters can be used.');
+                } else {
+                    $status = new Status\ErrorStatus();
+                    $status->setTitle('System locale setting doesn\'t support UTF-8 file names.');
+                    $status->setMessage(
+                        'Please check your $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] setting.'
+                    );
+                }
+                setlocale(LC_CTYPE, $currentLocale);
+            }
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('Skipping test, as UTF8filesystem is not enabled.');
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check if some opcode cache is loaded
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkSomePhpOpcodeCacheIsLoaded()
+    {
+        // Link to our wiki page, so we can update opcode cache issue information independent of TYPO3 CMS releases.
+        $wikiLink = 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.';
+        $opcodeCaches = GeneralUtility::makeInstance(OpcodeCacheService::class)->getAllActive();
+        if (empty($opcodeCaches)) {
+            // Set status to notice. It needs to be notice so email won't be triggered.
+            $status = new Status\NoticeStatus();
+            $status->setTitle('No PHP opcode cache loaded');
+            $status->setMessage(
+                'PHP opcode caches hold a compiled version of executed PHP scripts in' .
+                ' memory and do not require to recompile a script each time it is accessed.' .
+                ' This can be a massive performance improvement and can reduce the load on a' .
+                ' server in general. A parse time reduction by factor three for fully cached' .
+                ' pages can be achieved easily if using an opcode cache.' .
+                LF . $wikiLink
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $message = '';
+            foreach ($opcodeCaches as $opcodeCache => $properties) {
+                $message .= 'Name: ' . $opcodeCache . ' Version: ' . $properties['version'];
+                $message .= LF;
+                if ($properties['error']) {
+                    // Set status to error if not already set
+                    if ($status->getSeverity() !== 'error') {
+                        $status = new Status\ErrorStatus();
+                    }
+                    $message .= ' This opcode cache is marked as malfunctioning by the TYPO3 CMS Team.';
+                } elseif ($properties['canInvalidate']) {
+                    $message .= ' This opcode cache should work correctly and has good performance.';
+                } else {
+                    // Set status to notice if not already error set. It needs to be notice so email won't be triggered.
+                    if ($status->getSeverity() !== 'error' || $status->getSeverity() !== 'warning') {
+                        $status = new Status\NoticeStatus();
+                    }
+                    $message .= ' This opcode cache may work correctly but has medium performance.';
+                }
+                $message .= LF;
+            }
+            $message .= $wikiLink;
+            // Set title of status depending on serverity
+            switch ($status->getSeverity()) {
+                case 'error':
+                    $status->setTitle('A possibly malfunctioning PHP opcode cache is loaded');
+                    break;
+                case 'warning':
+                    $status->setTitle('A PHP opcode cache is loaded which may cause problems');
+                    break;
+                case 'ok':
+                default:
+                    $status->setTitle('A PHP opcode cache is loaded');
+                    break;
+            }
+            $status->setMessage($message);
+        }
+
+        return $status;
+    }
+
+    /**
+     * Create true type font test image
+     *
+     * @return Status\StatusInterface
+     */
+    protected function isTrueTypeFontWorking()
+    {
+        if (function_exists('imageftbbox')) {
+            // 20 Pixels at 96 DPI
+            $fontSize = (20 / 96 * 72);
+            $textDimensions = @imageftbbox(
+                $fontSize,
+                0,
+                __DIR__ . '/../../Resources/Private/Font/vera.ttf',
+                'Testing true type support'
+            );
+            $fontBoxWidth = $textDimensions[2] - $textDimensions[0];
+            if ($fontBoxWidth < 300 && $fontBoxWidth > 200) {
+                $status = new Status\OkStatus();
+                $status->setTitle('FreeType True Type Font DPI');
+                $status->setMessage('Fonts are rendered by FreeType library. ' .
+                    'We need to ensure that the final dimensions are as expected. ' .
+                    'This server renderes fonts based on 96 DPI correctly');
+            } else {
+                $status = new Status\NoticeStatus();
+                $status->setTitle('FreeType True Type Font DPI');
+                $status->setMessage('Fonts are rendered by FreeType library. ' .
+                    'This server does not render fonts as expected. ' .
+                    'Please check your FreeType 2 module.');
+            }
+        } else {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('PHP GD library freetype2 support missing');
+            $status->setMessage(
+                'The core relies on GD library compiled into PHP with freetype2' .
+                ' support. This is missing on your system. Please install it.'
+            );
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check for bug in libxml
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkLibXmlBug()
+    {
+        $sampleArray = array('Test>><<Data');
+        $xmlContent = '<numIndex index="0">Test&gt;&gt;&lt;&lt;Data</numIndex>' . LF;
+        $xml = GeneralUtility::array2xml($sampleArray, '', -1);
+
+        if ($xmlContent !== $xml) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('PHP libxml bug present');
+            $status->setMessage(
+                'Some hosts have problems saving ">><<" in a flexform.' .
+                ' To fix this, enable [BE][flexformForceCDATA] in' .
+                ' All Configuration.'
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('PHP libxml bug not present');
+        }
+
+        return $status;
+    }
+}