'This extension is used to detect the orientation of uploaded images.', 'fileinfo' => 'This extension is used for proper file type detection in the File Abstraction Layer.', 'openssl' => 'This extension is used for sending SMTP mails over an encrypted channel endpoint.', ]; public function __construct() { $this->messageQueue = new FlashMessageQueue('install'); } public function getMessageQueue(): FlashMessageQueue { return $this->messageQueue; } /** * Get all status information as array with status objects */ public function getStatus(): FlashMessageQueue { $this->checkCurrentDirectoryIsInIncludePath(); $this->checkFileUploadEnabled(); $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize(); $this->checkMemorySettings(); $this->checkPhpVersion(); $this->checkMaxExecutionTime(); $this->checkDisableFunctions(); $this->checkDocRoot(); $this->checkOpenBaseDir(); $this->checkXdebugMaxNestingLevel(); $this->checkMaxInputVars(); $this->checkReflectionDocComment(); $this->checkWindowsApacheThreadStackSize(); foreach ($this->requiredPhpExtensions as $extension) { $this->checkPhpExtension($extension); } foreach ($this->suggestedPhpExtensions as $extension => $purpose) { $this->checkPhpExtension($extension, false, $purpose); } $this->checkPcreVersion(); $this->checkGdLibTrueColorSupport(); $this->checkGdLibGifSupport(); $this->checkGdLibJpgSupport(); $this->checkGdLibPngSupport(); $this->checkGdLibFreeTypeSupport(); return $this->messageQueue; } /** * Checks if current directory (.) is in PHP include path */ protected function checkCurrentDirectoryIsInIncludePath() { $includePath = (string)ini_get('include_path'); $delimiter = $this->isWindowsOs() ? ';' : ':'; $pathArray = GeneralUtility::trimExplode($delimiter, $includePath, true); if (!in_array('.', $pathArray)) { $this->messageQueue->enqueue(new FlashMessage( 'include_path = ' . implode(' ', $pathArray) . LF . 'Normally the current path \'.\' is included in the' . ' include_path of PHP. Although TYPO3 does not rely on this,' . ' it is an unusual setting that may introduce problems for' . ' some extensions.', 'Current directory (./) is not within PHP include path', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'Current directory (./) is within PHP include path.' )); } } /** * Check if file uploads are enabled in PHP */ protected function checkFileUploadEnabled() { if (!ini_get('file_uploads')) { $this->messageQueue->enqueue(new FlashMessage( 'file_uploads=' . ini_get('file_uploads') . LF . 'TYPO3 uses the ability to upload files from the browser in various cases.' . ' If this flag is disabled in PHP, you won\'t be able to upload files.' . ' But it doesn\'t end here, because not only are files not accepted by' . ' the server - ALL content in the forms are discarded and therefore' . ' nothing at all will be editable if you don\'t set this flag!', 'File uploads not allowed in PHP', ContextualFeedbackSeverity::ERROR )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'File uploads allowed in PHP' )); } } /** * Check maximum post upload size correlates with maximum file upload */ protected function checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize() { $maximumUploadFilesize = $this->getBytesFromSizeMeasurement((string)ini_get('upload_max_filesize')); $maximumPostSize = $this->getBytesFromSizeMeasurement((string)ini_get('post_max_size')); if ($maximumPostSize > 0 && $maximumPostSize < $maximumUploadFilesize) { $this->messageQueue->enqueue(new FlashMessage( 'upload_max_filesize=' . ini_get('upload_max_filesize') . LF . 'post_max_size=' . ini_get('post_max_size') . LF . 'You have defined a maximum size for file uploads in PHP which' . ' exceeds the allowed size for POST requests. Therefore the' . ' file uploads can also not be larger than ' . ini_get('post_max_size') . '.', 'Maximum size for POST requests is smaller than maximum upload filesize in PHP', ContextualFeedbackSeverity::ERROR )); } elseif ($maximumPostSize === $maximumUploadFilesize) { $this->messageQueue->enqueue(new FlashMessage( 'The maximum size for file uploads is set to ' . ini_get('upload_max_filesize'), 'Maximum post upload size correlates with maximum upload file size in PHP' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'The maximum size for file uploads is set to ' . ini_get('upload_max_filesize'), 'Maximum post upload size is higher than maximum upload file size in PHP, which is fine.' )); } } /** * Check memory settings */ protected function checkMemorySettings() { $minimumMemoryLimit = 256; $recommendedMemoryLimit = 512; $memoryLimit = $this->getBytesFromSizeMeasurement((string)ini_get('memory_limit')); if ($memoryLimit <= 0) { if (Environment::isCli()) { // "0" memory limit for CLI is usually "just fine". Do not cause a report for this in CLI mode (but in web mode) $this->messageQueue->enqueue(new FlashMessage( 'Maximum PHP memory limit is set to zero; this is commonly set in PHP CLI mode, which is currently active for this check.', 'Unlimited memory limit for PHP (CLI)', )); return; } $this->messageQueue->enqueue(new FlashMessage( 'PHP is configured not to limit memory usage at all. This is a risk' . ' and should be avoided in production setup. In general it\'s best practice to limit this.' . ' To be safe, set a limit in PHP, but with a minimum of ' . $recommendedMemoryLimit . 'MB:' . LF . 'memory_limit=' . $recommendedMemoryLimit . 'M', 'Unlimited memory limit for PHP', ContextualFeedbackSeverity::WARNING )); } elseif ($memoryLimit < 1024 * 1024 * $minimumMemoryLimit) { $this->messageQueue->enqueue(new FlashMessage( 'memory_limit=' . ini_get('memory_limit') . LF . 'Your system is configured to enforce a memory limit for PHP scripts lower than ' . $minimumMemoryLimit . 'MB. It is required to raise the limit.' . ' We recommend a minimum PHP memory limit of ' . $recommendedMemoryLimit . 'MB:' . LF . 'memory_limit=' . $recommendedMemoryLimit . 'M', 'PHP Memory limit below ' . $minimumMemoryLimit . 'MB', ContextualFeedbackSeverity::ERROR )); } elseif ($memoryLimit < 1024 * 1024 * $recommendedMemoryLimit) { $this->messageQueue->enqueue(new FlashMessage( 'memory_limit=' . ini_get('memory_limit') . LF . 'Your system is configured to enforce a memory limit for PHP scripts lower than ' . $recommendedMemoryLimit . 'MB.' . ' A slim TYPO3 instance without many extensions will probably work, but you should monitor your' . ' system for "allowed memory size of X bytes exhausted" messages, especially if using the backend.' . ' To be on the safe side, we recommend a minimum PHP memory limit of ' . $recommendedMemoryLimit . 'MB:' . LF . 'memory_limit=' . $recommendedMemoryLimit . 'M', 'PHP Memory limit below ' . $recommendedMemoryLimit . 'MB', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP Memory limit is equal to or more than ' . $recommendedMemoryLimit . 'MB' )); } } /** * Check minimum PHP version */ protected function checkPhpVersion() { $minimumPhpVersion = '8.5.0'; $currentPhpVersion = PHP_VERSION; if (version_compare($currentPhpVersion, $minimumPhpVersion) < 0) { $this->messageQueue->enqueue(new FlashMessage( 'Your PHP version ' . $currentPhpVersion . ' is too old. TYPO3 CMS does not run' . ' with this version. Update to at least PHP ' . $minimumPhpVersion, 'PHP version too low', ContextualFeedbackSeverity::ERROR )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP version is fine' )); } } /** * Check PRCE module is loaded and minimum version */ protected function checkPcreVersion() { $minimumPcreVersion = '8.38'; if (!extension_loaded('pcre')) { $this->messageQueue->enqueue(new FlashMessage( 'TYPO3 CMS uses PHP extension pcre but it is not loaded' . ' in your environment. Change your environment to provide this extension' . ' in with minimum version ' . $minimumPcreVersion . '.', 'PHP extension pcre not loaded', ContextualFeedbackSeverity::ERROR )); } else { $installedPcreVersionString = trim(PCRE_VERSION); // '8.39 2016-06-14' $mainPcreVersionString = explode(' ', $installedPcreVersionString); $mainPcreVersionString = $mainPcreVersionString[0]; // '8.39' if (version_compare($mainPcreVersionString, $minimumPcreVersion) < 0) { $this->messageQueue->enqueue(new FlashMessage( 'Your PCRE version ' . PCRE_VERSION . ' is too old. TYPO3 CMS may trigger PHP segmentantion' . ' faults with this version. Update to at least PCRE ' . $minimumPcreVersion, 'PCRE version too low', ContextualFeedbackSeverity::ERROR )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP extension PCRE is loaded and version is fine' )); } } } /** * Check maximum execution time */ protected function checkMaxExecutionTime() { $minimumMaximumExecutionTime = 30; $recommendedMaximumExecutionTime = 240; $currentMaximumExecutionTime = ini_get('max_execution_time'); if ($currentMaximumExecutionTime == 0) { if (Environment::isCli()) { // "0" execution time for CLI is usually "just fine". Do not cause a report for this in CLI mode (but in web mode) $this->messageQueue->enqueue(new FlashMessage( 'Maximum PHP script execution time is set to zero; this is commonly set in PHP CLI mode, which is currently active for this check.', 'Infinite PHP script execution time', )); return; } $this->messageQueue->enqueue(new FlashMessage( 'max_execution_time=0' . LF . 'While TYPO3 is fine with this, you risk a denial-of-service for your system if for whatever' . ' reason some script hangs in an infinite loop. You are usually on the safe side ' . ' if it is reduced to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF . 'max_execution_time=' . $recommendedMaximumExecutionTime, 'Infinite PHP script execution time', ContextualFeedbackSeverity::WARNING )); } elseif ($currentMaximumExecutionTime < $minimumMaximumExecutionTime) { $this->messageQueue->enqueue(new FlashMessage( 'max_execution_time=' . $currentMaximumExecutionTime . LF . 'Your max_execution_time is too low. Some expensive operations in TYPO3 can take longer than that.' . ' It is recommended to raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF . 'max_execution_time=' . $recommendedMaximumExecutionTime, 'Low PHP script execution time', ContextualFeedbackSeverity::ERROR )); } elseif ($currentMaximumExecutionTime < $recommendedMaximumExecutionTime) { $this->messageQueue->enqueue(new FlashMessage( 'max_execution_time=' . $currentMaximumExecutionTime . LF . 'Your max_execution_time is low. While TYPO3 often runs without problems' . ' with ' . $minimumMaximumExecutionTime . ' seconds,' . ' it may still happen that script execution is stopped before finishing' . ' calculations. You should monitor the system for messages in this area' . ' and maybe raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF . 'max_execution_time=' . $recommendedMaximumExecutionTime, 'Low PHP script execution time', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'Maximum PHP script execution time is equal to or more than ' . $recommendedMaximumExecutionTime )); } } /** * Check for disabled functions */ protected function checkDisableFunctions() { $disabledFunctions = trim((string)ini_get('disable_functions')); // Filter "disable_functions" $disabledFunctionsArray = GeneralUtility::trimExplode(',', $disabledFunctions, true); // Array with strings to find $findStrings = [ // Disabled by default on Ubuntu OS but this is okay since the Core does not use them 'pcntl_', ]; // List of disable_functions which would not trigger an error, but only a warning $configuredAllowedDisableFunctions = $GLOBALS['TYPO3_CONF_VARS']['SYS']['allowedPhpDisableFunctions'] ?? []; if (!is_array($configuredAllowedDisableFunctions)) { $configuredAllowedDisableFunctions = []; } $foundAllowedDisableFunctions = []; // Iterate all functions that are currently disabled by PHP ($disabledFunctionsArray). // Each disabled function ($disabledFunction) is checked whether it may be acceptable // to be disabled (based on $configuredAllowedDisableFunctions). // If good to be disabled: Remove from $disabledFunctionsArray (which is emitted later on), // and also add to $foundAllowedDisableFunctions for reporting. // Else: Check if the function is maybe whitelisted because unused by core ($findStrings) // and if so, also remove from $disabledFunctionsArray // What remains then in $disabledFunctionsArray is the list of disabled functions that // need to be reported. foreach ($disabledFunctionsArray as $key => $disabledFunction) { if (in_array($disabledFunction, $configuredAllowedDisableFunctions, true)) { unset($disabledFunctionsArray[$key]); $foundAllowedDisableFunctions[] = $disabledFunction; continue; } foreach ($findStrings as $findString) { if (str_contains($disabledFunction, $findString)) { unset($disabledFunctionsArray[$key]); } } } if ($disabledFunctions !== '') { // Error for disable_functions which are not explicitly allowed if ($disabledFunctionsArray !== []) { $this->messageQueue->enqueue(new FlashMessage( 'disable_functions=' . implode(' ', $disabledFunctionsArray) . LF . '- These function(s) are disabled. TYPO3 uses some of those, so there might be trouble.' . ' TYPO3 is designed to use the default set of PHP functions plus some common extensions.' . ' Possibly these functions are disabled' . ' due to security considerations and often the list would include a function like' . ' exec() which is used by TYPO3 at various places. Depending on which exact functions' . ' are disabled, some parts of the system may just break without further notice. Known acceptable' . ' exemptions can be muted by adding those to' . ' $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'allowedPhpDisableFunctions\'] in your system' . ' configuration.', 'Some PHP functions disabled', ContextualFeedbackSeverity::ERROR )); } // Warning for disable_functions which are explicitly allowed if ($foundAllowedDisableFunctions !== []) { $this->messageQueue->enqueue(new FlashMessage( 'disable_functions=' . implode(' ', $foundAllowedDisableFunctions) . LF . '- These function(s) are disabled. TYPO3 or installed extensions may use some of those, but the' . ' error reporting for them is explicitly muted in your installation via configuration variable' . ' $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'allowedPhpDisableFunctions\'].' . ' Please ensure by yourself that these functions are not used by TYPO3 or any other installed package.', 'Some PHP functions disabled, but considered irrelevant', ContextualFeedbackSeverity::WARNING )); } // Notice for known irrelevant functions (e.g. pcntl_*) // Only shown if none of the two FlashMessages above are emitted. if ($disabledFunctionsArray === [] && $foundAllowedDisableFunctions === []) { $this->messageQueue->enqueue(new FlashMessage( 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF . '- These function(s) are disabled. TYPO3 uses currently none of those, so you are good to go.', 'Some PHP functions currently disabled but OK' )); } } else { $this->messageQueue->enqueue(new FlashMessage( '', 'No disabled PHP functions' )); } } /** * Check for doc_root ini setting */ protected function checkDocRoot() { $docRootSetting = trim((string)ini_get('doc_root')); if ($docRootSetting !== '') { $this->messageQueue->enqueue(new FlashMessage( 'doc_root=' . $docRootSetting . LF . 'PHP cannot execute scripts' . ' outside this directory. This setting is seldom used and must correlate' . ' with your actual document root. You might be in trouble if your' . ' TYPO3 CMS core code is linked to some different location.' . ' If that is a problem, the setting must be changed.', 'doc_root is set', ContextualFeedbackSeverity::NOTICE )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP doc_root is not set' )); } } /** * Check open_basedir */ protected function checkOpenBaseDir() { $openBaseDirSetting = trim((string)ini_get('open_basedir')); if ($openBaseDirSetting !== '') { $this->messageQueue->enqueue(new FlashMessage( 'open_basedir = ' . ini_get('open_basedir') . LF . 'This restricts TYPO3 to open and include files only in this' . ' path. Please make sure that this does not prevent TYPO3 from running,' . ' if for example your TYPO3 CMS core is linked to a different directory' . ' not included in this path.', 'PHP open_basedir is set', ContextualFeedbackSeverity::NOTICE )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP open_basedir is off' )); } } /** * If xdebug is loaded, the default max_nesting_level of 100 must be raised */ protected function checkXdebugMaxNestingLevel() { if (extension_loaded('xdebug')) { $recommendedMaxNestingLevel = 400; $errorThreshold = 250; $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level'); if ($currentMaxNestingLevel < $errorThreshold) { $this->messageQueue->enqueue(new FlashMessage( 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF . 'This setting controls the maximum number of nested function calls to protect against' . ' infinite recursion. The current value is too low for TYPO3 CMS and must' . ' be either raised or xdebug has to be unloaded. A value of ' . $recommendedMaxNestingLevel . ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS' . ' if the value is not raised significantly to:' . LF . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel, 'PHP xdebug.max_nesting_level is critically low', ContextualFeedbackSeverity::ERROR )); } elseif ($currentMaxNestingLevel < $recommendedMaxNestingLevel) { $this->messageQueue->enqueue(new FlashMessage( 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF . 'This setting controls the maximum number of nested function calls to protect against' . ' infinite recursion. The current value is high enough for the TYPO3 CMS core to work' . ' fine, but still some extensions could raise fatal PHP errors if the setting is not' . ' raised further. A value of ' . $recommendedMaxNestingLevel . ' is recommended.' . LF . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel, 'PHP xdebug.max_nesting_level is low', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP xdebug.max_nesting_level ok' )); } } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP xdebug extension not loaded' )); } } /** * Get max_input_vars status */ protected function checkMaxInputVars() { $recommendedMaxInputVars = 1500; $minimumMaxInputVars = 1000; $currentMaxInputVars = ini_get('max_input_vars'); if ($currentMaxInputVars < $minimumMaxInputVars) { $this->messageQueue->enqueue(new FlashMessage( 'max_input_vars=' . $currentMaxInputVars . LF . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' . ' (as the install tool does). It is highly recommended to raise this' . ' to at least ' . $recommendedMaxInputVars . ':' . LF . 'max_input_vars=' . $recommendedMaxInputVars, 'PHP max_input_vars too low', ContextualFeedbackSeverity::ERROR )); } elseif ($currentMaxInputVars < $recommendedMaxInputVars) { $this->messageQueue->enqueue(new FlashMessage( 'max_input_vars=' . $currentMaxInputVars . LF . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' . ' (as the install tool does). It is highly recommended to raise this' . ' to at least ' . $recommendedMaxInputVars . ':' . LF . 'max_input_vars=' . $recommendedMaxInputVars, 'PHP max_input_vars very low', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP max_input_vars ok' )); } } /** * Check doc comments can be fetched by reflection */ protected function checkReflectionDocComment() { $testReflection = new \ReflectionMethod(static::class, __FUNCTION__); if ($testReflection->getDocComment() === false) { $this->messageQueue->enqueue(new FlashMessage( 'TYPO3 CMS core extensions like extbase and fluid heavily rely on method' . ' comment parsing to fetch annotations and add magic belonging to them.' . ' This does not work in the current environment and so we cannot install' . ' TYPO3 CMS.' . LF . ' Here are some possibilities: ' . LF . '* In Zend OPcache you can disable saving/loading comments. If you are using' . ' Zend OPcache (included since PHP 5.5) then check your php.ini settings for' . ' opcache.save_comments and opcache.load_comments and enable them.' . LF . '* In Zend Optimizer+ you can disable saving comments. If you are using' . ' Zend Optimizer+ then check your php.ini settings for' . ' zend_optimizerplus.save_comments and enable it.' . LF . '* The PHP extension eaccelerator is known to break this if' . ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.' . ' This compile flag must be specified, otherwise TYPO3 CMS will not work.' . LF . 'For more information take a look in our documentation ' . Typo3Information::getDocsLink('t3coreapi:troubleshooting-php-troubleshooting-opcode') . '.', 'PHP Doc comment reflection broken', ContextualFeedbackSeverity::ERROR )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP Doc comment reflection works' )); } } /** * Checks thread stack size if on windows with apache */ protected function checkWindowsApacheThreadStackSize() { if (Environment::isCli()) { return; } if ($this->isWindowsOs() && str_starts_with($_SERVER['SERVER_SOFTWARE'], 'Apache') ) { $this->messageQueue->enqueue(new FlashMessage( 'This current value cannot be checked by the system, so please ignore this warning if it' . ' is already taken care of: Fluid uses complex regular expressions which require a lot' . ' of stack space during the first processing.' . ' On Windows the default stack size for Apache is a lot smaller than on UNIX.' . ' You can increase the size to 8MB (default on UNIX) by adding the following configuration' . ' to httpd.conf and restarting Apache afterwards:' . LF . 'ThreadStackSize 8388608', 'Windows apache thread stack size', ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'Apache ThreadStackSize is not an issue on UNIX systems' )); } } /** * Checks if a specific PHP extension is loaded. */ public function checkPhpExtension(string $extension, bool $required = true, string $purpose = '') { if (!extension_loaded($extension)) { $this->messageQueue->enqueue(new FlashMessage( 'TYPO3 uses the PHP extension "' . $extension . '" but it is not loaded' . ' in your environment. Change your environment to provide this extension. ' . $purpose, 'PHP extension "' . $extension . '" not loaded', $required ? ContextualFeedbackSeverity::ERROR : ContextualFeedbackSeverity::WARNING )); } else { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP extension "' . $extension . '" loaded' )); } } /** * Check imagecreatetruecolor to verify gdlib works as expected */ protected function checkGdLibTrueColorSupport() { if (function_exists('imagecreatetruecolor')) { $imageResource = @imagecreatetruecolor(50, 100); if ($this->checkImageResource($imageResource)) { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP GD library true color works' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'GD is loaded, but calling imagecreatetruecolor() fails.' . ' This must be fixed, TYPO3 CMS won\'t work well otherwise.', 'PHP GD library true color support broken', ContextualFeedbackSeverity::ERROR )); } } else { $this->messageQueue->enqueue(new FlashMessage( 'Gdlib is essential for TYPO3 CMS to work properly.', 'PHP GD library true color support missing', ContextualFeedbackSeverity::ERROR )); } } /** * Check gif support of GD library */ protected function checkGdLibGifSupport() { if (function_exists('imagecreatefromgif') && function_exists('imagegif') && (imagetypes() & IMG_GIF) ) { // Do not use data:// wrapper to be independent of allow_url_fopen $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif'); if ($this->checkImageResource($imageResource)) { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP GD library has gif support' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'GD is loaded, but calling imagecreatefromgif() fails. This must be fixed, TYPO3 CMS won\'t work well otherwise.', 'PHP GD library gif support broken', ContextualFeedbackSeverity::ERROR )); } } else { $this->messageQueue->enqueue(new FlashMessage( 'GD must be compiled with gif support. This is essential for TYPO3 CMS to work properly.', 'PHP GD library gif support missing', ContextualFeedbackSeverity::ERROR )); } } /** * Check jpg support of GD library */ protected function checkGdLibJpgSupport() { if (function_exists('imagecreatefromjpeg') && function_exists('imagejpeg') && (imagetypes() & IMG_JPG) ) { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP GD library has jpg support' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'GD must be compiled with jpg support. This is essential for TYPO3 CMS to work properly.', 'PHP GD library jpg support missing', ContextualFeedbackSeverity::ERROR )); } } /** * Check png support of GD library */ protected function checkGdLibPngSupport() { if (function_exists('imagecreatefrompng') && function_exists('imagepng') && (imagetypes() & IMG_PNG) ) { // Do not use data:// wrapper to be independent of allow_url_fopen $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png'); if ($this->checkImageResource($imageResource)) { $this->messageQueue->enqueue(new FlashMessage( '', 'PHP GD library has png support' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'GD is compiled with png support, but calling imagecreatefrompng() fails.' . ' Check your environment and fix it, png in GD lib is important' . ' for TYPO3 CMS to work properly.', 'PHP GD library png support broken', ContextualFeedbackSeverity::ERROR )); } } else { $this->messageQueue->enqueue(new FlashMessage( 'GD must be compiled with png support. This is essential for TYPO3 CMS to work properly', 'PHP GD library png support missing', ContextualFeedbackSeverity::ERROR )); } } /** * Check gdlib supports freetype */ protected function checkGdLibFreeTypeSupport() { if (function_exists('imagettftext')) { $this->messageQueue->enqueue(new FlashMessage( 'There is a difference between the font size setting which the GD' . ' library should be supplied with. If installation is completed' . ' a test in the install tool helps to find out the value you need.', 'PHP GD library has freetype font support' )); } else { $this->messageQueue->enqueue(new FlashMessage( 'Some core functionality and extension rely on the GD' . ' to render fonts on images. This support is missing' . ' in your environment. Install it.', 'PHP GD library freetype support missing', ContextualFeedbackSeverity::ERROR )); } } /** * Helper methods */ /** * Validate a given IP address. * * @param string $ip IP address to be tested * @return bool */ protected function isValidIp($ip) { return filter_var($ip, FILTER_VALIDATE_IP) !== false; } /** * Test if this instance runs on windows OS * * @return bool TRUE if operating system is windows */ protected function isWindowsOs() { $windowsOs = false; if (stripos(PHP_OS, 'darwin') === false && stripos(PHP_OS, 'win') !== false) { $windowsOs = true; } return $windowsOs; } /** * Helper method to get the bytes value from a measurement string like "100k". * * @param string $measurement The measurement (e.g. "100k") * @return int The bytes value (e.g. 102400) */ protected function getBytesFromSizeMeasurement($measurement) { $bytes = (float)$measurement; if (stripos($measurement, 'G')) { $bytes *= 1024 * 1024 * 1024; } elseif (stripos($measurement, 'M')) { $bytes *= 1024 * 1024; } elseif (stripos($measurement, 'K')) { $bytes *= 1024; } return (int)$bytes; } private function checkImageResource($imageResource): bool { return $imageResource instanceof \GdImage; } }