[FEATURE] Adjust trustedHostsPattern during installation
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / SystemEnvironment / Check.php
1 <?php
2 namespace TYPO3\CMS\Install\SystemEnvironment;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Service\OpcodeCacheService;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Install\Status;
20
21 /**
22 * Check system environment status
23 *
24 * This class is a hardcoded requirement check of the underlying
25 * server and PHP system.
26 *
27 * The class *must not* check for any TYPO3 specific things like
28 * specific configuration values or directories. It should not fail
29 * if there is no TYPO3 at all.
30 *
31 * The only core code used is the class loader
32 *
33 * This class is instantiated as the *very first* class during
34 * installation. It is meant to be *standalone* und must not have
35 * any requirements, except the status classes. It must be possible
36 * to run this script separated from the rest of the core, without
37 * dependencies.
38 *
39 * This means especially:
40 * * No hooks or anything like that
41 * * No usage of *any* TYPO3 code like GeneralUtility
42 * * No require of anything but the status classes
43 * * No localization
44 *
45 * The status messages and title *must not* include HTML, use plain
46 * text only. The return values of this class are not bound to HTML
47 * and can be used in different scopes (eg. as json array).
48 */
49 class Check {
50
51 /**
52 * @var array List of required PHP extensions
53 */
54 protected $requiredPhpExtensions = array(
55 'fileinfo',
56 'filter',
57 'gd',
58 'hash',
59 'json',
60 'mysqli',
61 'openssl',
62 'session',
63 'soap',
64 'SPL',
65 'standard',
66 'xml',
67 'zip',
68 'zlib',
69 );
70
71 /**
72 * Get all status information as array with status objects
73 *
74 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
75 */
76 public function getStatus() {
77 $statusArray = array();
78 $statusArray[] = $this->checkCurrentDirectoryIsInIncludePath();
79 $statusArray[] = $this->checkTrustedHostPattern();
80 $statusArray[] = $this->checkFileUploadEnabled();
81 $statusArray[] = $this->checkMaximumFileUploadSize();
82 $statusArray[] = $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
83 $statusArray[] = $this->checkMemorySettings();
84 $statusArray[] = $this->checkPhpVersion();
85 $statusArray[] = $this->checkMaxExecutionTime();
86 $statusArray[] = $this->checkDisableFunctions();
87 $statusArray[] = $this->checkDownloadsPossible();
88 $statusArray[] = $this->checkDocRoot();
89 $statusArray[] = $this->checkOpenBaseDir();
90 $statusArray[] = $this->checkXdebugMaxNestingLevel();
91 $statusArray[] = $this->checkOpenSslInstalled();
92 if ($this->isSuhosinLoadedAndActive()) {
93 $statusArray[] = $this->getSuhosinLoadedStatus();
94 $statusArray[] = $this->checkSuhosinRequestMaxVars();
95 $statusArray[] = $this->checkSuhosinRequestMaxVarnameLength();
96 $statusArray[] = $this->checkSuhosinPostMaxNameLength();
97 $statusArray[] = $this->checkSuhosinPostMaxVars();
98 $statusArray[] = $this->checkSuhosinGetMaxNameLength();
99 $statusArray[] = $this->checkSuhosinGetMaxValueLength();
100 $statusArray[] = $this->checkSuhosinExecutorIncludeWhitelistContainsPhar();
101 $statusArray[] = $this->checkSuhosinExecutorIncludeWhitelistContainsVfs();
102 }
103 $statusArray[] = $this->checkMaxInputVars();
104 $statusArray[] = $this->checkSomePhpOpcodeCacheIsLoaded();
105 $statusArray[] = $this->checkReflectionDocComment();
106 $statusArray[] = $this->checkSystemLocale();
107 $statusArray[] = $this->checkLocaleWithUTF8filesystem();
108 $statusArray[] = $this->checkWindowsApacheThreadStackSize();
109 foreach ($this->requiredPhpExtensions as $extension) {
110 $statusArray[] = $this->checkRequiredPhpExtension($extension);
111 }
112 $statusArray[] = $this->checkPcreVersion();
113 $statusArray[] = $this->checkGdLibTrueColorSupport();
114 $statusArray[] = $this->checkGdLibGifSupport();
115 $statusArray[] = $this->checkGdLibJpgSupport();
116 $statusArray[] = $this->checkGdLibPngSupport();
117 $statusArray[] = $this->checkGdLibFreeTypeSupport();
118 $statusArray[] = $this->checkRegisterGlobals();
119 $statusArray[] = $this->checkLibXmlBug();
120 $statusArray[] = $this->isTrueTypeFontWorking();
121 return $statusArray;
122 }
123
124 /**
125 * Checks if current directory (.) is in PHP include path
126 *
127 * @return Status\StatusInterface
128 */
129 protected function checkCurrentDirectoryIsInIncludePath() {
130 $includePath = ini_get('include_path');
131 $delimiter = $this->isWindowsOs() ? ';' : ':';
132 $pathArray = $this->trimExplode($delimiter, $includePath);
133 if (!in_array('.', $pathArray)) {
134 $status = new Status\WarningStatus();
135 $status->setTitle('Current directory (./) is not within PHP include path');
136 $status->setMessage(
137 'include_path = ' . implode(' ', $pathArray) . LF .
138 'Normally the current path \'.\' is included in the' .
139 ' include_path of PHP. Although TYPO3 does not rely on this,' .
140 ' it is an unusual setting that may introduce problems for' .
141 ' some extensions.'
142 );
143 } else {
144 $status = new Status\OkStatus();
145 $status->setTitle('Current directory (./) is within PHP include path.');
146 }
147 return $status;
148 }
149
150 /**
151 * Checks the status of the trusted hosts pattern check
152 *
153 * @return Status\StatusInterface
154 */
155 protected function checkTrustedHostPattern() {
156 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
157 $status = new Status\WarningStatus();
158 $status->setTitle('Trusted hosts pattern is insecure');
159 $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).');
160 } else {
161 if (GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST'])) {
162 $status = new Status\OkStatus();
163 $status->setTitle('Trusted hosts pattern is configured to allow current host value.');
164 } else {
165 $status = new Status\ErrorStatus();
166 $status->setTitle('Trusted hosts pattern mismatch');
167 $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).');
168 }
169 }
170
171 return $status;
172 }
173
174 /**
175 * Check if file uploads are enabled in PHP
176 *
177 * @return Status\StatusInterface
178 */
179 protected function checkFileUploadEnabled() {
180 if (!ini_get('file_uploads')) {
181 $status = new Status\ErrorStatus();
182 $status->setTitle('File uploads not allowed in PHP');
183 $status->setMessage(
184 'file_uploads=' . ini_get('file_uploads') . LF .
185 'TYPO3 uses the ability to upload files from the browser in various cases.' .
186 ' If this flag is disabled in PHP, you won\'t be able to upload files.' .
187 ' But it doesn\'t end here, because not only are files not accepted by' .
188 ' the server - ALL content in the forms are discarded and therefore' .
189 ' nothing at all will be editable if you don\'t set this flag!'
190 );
191 } else {
192 $status = new Status\OkStatus();
193 $status->setTitle('File uploads allowed in PHP');
194 }
195 return $status;
196 }
197
198 /**
199 * Check maximum file upload size against default value of 10MB
200 *
201 * @return Status\StatusInterface
202 */
203 protected function checkMaximumFileUploadSize() {
204 $maximumUploadFilesize = $this->getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
205 $configuredMaximumUploadFilesize = 1024 * (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize'];
206 if ($maximumUploadFilesize < $configuredMaximumUploadFilesize) {
207 $status = new Status\ErrorStatus();
208 $status->setTitle('PHP Maximum upload filesize too small');
209 $status->setMessage(
210 'PHP upload_max_filesize = ' . (int)($maximumUploadFilesize / 1024) . ' KB' . LF .
211 'TYPO3_CONF_VARS[BE][maxFileSize] = ' . (int)($configuredMaximumUploadFilesize / 1024) . ' KB' . LF . LF .
212 'Currently PHP determines the limits for uploaded file\'s sizes and not TYPO3.' .
213 ' It is recommended that the value of upload_max_filesize is at least equal to the value' .
214 ' of TYPO3_CONF_VARS[BE][maxFileSize].'
215 );
216 } else {
217 $status = new Status\OkStatus();
218 $status->setTitle('PHP Maximum file upload size is higher than or equal to [BE][maxFileSize]');
219 }
220 return $status;
221 }
222
223 /**
224 * Check maximum post upload size correlates with maximum file upload
225 *
226 * @return Status\StatusInterface
227 */
228 protected function checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize() {
229 $maximumUploadFilesize = $this->getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
230 $maximumPostSize = $this->getBytesFromSizeMeasurement(ini_get('post_max_size'));
231 if ($maximumPostSize > 0 && $maximumPostSize < $maximumUploadFilesize) {
232 $status = new Status\ErrorStatus();
233 $status->setTitle('Maximum size for POST requests is smaller than maximum upload filesize in PHP');
234 $status->setMessage(
235 'upload_max_filesize=' . ini_get('upload_max_filesize') . LF .
236 'post_max_size=' . ini_get('post_max_size') . LF .
237 'You have defined a maximum size for file uploads in PHP which' .
238 ' exceeds the allowed size for POST requests. Therefore the' .
239 ' file uploads can also not be larger than ' . ini_get('post_max_size') . '.'
240 );
241 } else {
242 $status = new Status\OkStatus();
243 $status->setTitle('Maximum post upload size correlates with maximum upload file size in PHP');
244 }
245 return $status;
246 }
247
248 /**
249 * Check memory settings
250 *
251 * @return Status\StatusInterface
252 */
253 protected function checkMemorySettings() {
254 $minimumMemoryLimit = 32;
255 $recommendedMemoryLimit = 64;
256 $memoryLimit = $this->getBytesFromSizeMeasurement(ini_get('memory_limit'));
257 if ($memoryLimit <= 0) {
258 $status = new Status\WarningStatus();
259 $status->setTitle('Unlimited memory limit for PHP');
260 $status->setMessage(
261 'PHP is configured not to limit memory usage at all. This is a risk' .
262 ' and should be avoided in production setup. In general it\'s best practice to limit this.' .
263 ' To be safe, set a limit in PHP, but with a minimum of ' . $recommendedMemoryLimit . 'MB:' . LF .
264 'memory_limit=' . $recommendedMemoryLimit . 'M'
265 );
266 } elseif ($memoryLimit < 1024 * 1024 * $minimumMemoryLimit) {
267 $status = new Status\ErrorStatus();
268 $status->setTitle('PHP Memory limit below ' . $minimumMemoryLimit . 'MB');
269 $status->setMessage(
270 'memory_limit=' . ini_get('memory_limit') . LF .
271 'Your system is configured to enforce a memory limit for PHP scripts lower than ' .
272 $minimumMemoryLimit . 'MB. It is required to raise the limit.' .
273 ' We recommend a minimum PHP memory limit of ' . $recommendedMemoryLimit . 'MB:' . LF .
274 'memory_limit=' . $recommendedMemoryLimit . 'M'
275 );
276 } elseif ($memoryLimit < 1024 * 1024 * $recommendedMemoryLimit) {
277 $status = new Status\WarningStatus();
278 $status->setTitle('PHP Memory limit below ' . $recommendedMemoryLimit . 'MB');
279 $status->setMessage(
280 'memory_limit=' . ini_get('memory_limit') . LF .
281 'Your system is configured to enforce a memory limit for PHP scripts lower than ' .
282 $recommendedMemoryLimit . 'MB.' .
283 ' A slim TYPO3 instance without many extensions will probably work, but you should monitor your' .
284 ' system for "allowed memory size of X bytes exhausted" messages, especially if using the backend.' .
285 ' To be on the safe side,' . ' we recommend a minimum PHP memory limit of ' .
286 $recommendedMemoryLimit . 'MB:' . LF .
287 'memory_limit=' . $recommendedMemoryLimit . 'M'
288 );
289 } else {
290 $status = new Status\OkStatus();
291 $status->setTitle('PHP Memory limit is equal to or more than ' . $recommendedMemoryLimit . 'MB');
292 }
293 return $status;
294 }
295
296 /**
297 * Check minimum PHP version
298 *
299 * @return Status\StatusInterface
300 */
301 protected function checkPhpVersion() {
302 $minimumPhpVersion = '5.5.0';
303 $currentPhpVersion = phpversion();
304 if (version_compare($currentPhpVersion, $minimumPhpVersion) < 0) {
305 $status = new Status\ErrorStatus();
306 $status->setTitle('PHP version too low');
307 $status->setMessage(
308 'Your PHP version ' . $currentPhpVersion . ' is too old. TYPO3 CMS does not run' .
309 ' with this version. Update to at least PHP ' . $minimumPhpVersion
310 );
311 } else {
312 $status = new Status\OkStatus();
313 $status->setTitle('PHP version is fine');
314 }
315 return $status;
316 }
317
318 /**
319 * Check PRCE module is loaded and minimum version
320 *
321 * @return Status\StatusInterface
322 */
323 protected function checkPcreVersion() {
324 $minimumPcreVersion = '8.30';
325 if (!extension_loaded('pcre')) {
326 $status = new Status\ErrorStatus();
327 $status->setTitle('PHP extension pcre not loaded');
328 $status->setMessage(
329 'TYPO3 CMS uses PHP extension pcre but it is not loaded' .
330 ' in your environment. Change your environment to provide this extension' .
331 ' in with minimum version ' . $minimumPcreVersion . '.'
332 );
333 } else {
334 $installedPcreVersionString = trim(PCRE_VERSION); // '8.31 2012-07-06'
335 $mainPcreVersionString = explode(' ', $installedPcreVersionString);
336 $mainPcreVersionString = $mainPcreVersionString[0]; // '8.31'
337 if (version_compare($mainPcreVersionString, $minimumPcreVersion) < 0) {
338 $status = new Status\ErrorStatus();
339 $status->setTitle('PCRE version too low');
340 $status->setMessage(
341 'Your PCRE version ' . PCRE_VERSION . ' is too old. TYPO3 CMS may trigger PHP segmentantion' .
342 ' faults with this version. Update to at least PCRE ' . $minimumPcreVersion
343 );
344 } else {
345 $status = new Status\OkStatus();
346 $status->setTitle('PHP extension PCRE is loaded and version is fine');
347 }
348 }
349 return $status;
350 }
351
352 /**
353 * Check maximum execution time
354 *
355 * @return Status\StatusInterface
356 */
357 protected function checkMaxExecutionTime() {
358 $minimumMaximumExecutionTime = 30;
359 $recommendedMaximumExecutionTime = 240;
360 $currentMaximumExecutionTime = ini_get('max_execution_time');
361 if ($currentMaximumExecutionTime == 0) {
362 $status = new Status\WarningStatus();
363 $status->setTitle('Infinite PHP script execution time');
364 $status->setMessage(
365 'max_execution_time=0' . LF .
366 'While TYPO3 is fine with this, you risk a denial-of-service for your system if for whatever' .
367 ' reason some script hangs in an infinite loop. You are usually on the safe side ' .
368 ' if it is reduced to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF .
369 'max_execution_time=' . $recommendedMaximumExecutionTime
370 );
371 } elseif ($currentMaximumExecutionTime < $minimumMaximumExecutionTime) {
372 $status = new Status\ErrorStatus();
373 $status->setTitle('Low PHP script execution time');
374 $status->setMessage(
375 'max_execution_time=' . $currentMaximumExecutionTime . LF .
376 'Your max_execution_time is too low. Some expensive operations in TYPO3 can take longer than that.' .
377 ' It is recommended to raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF .
378 'max_execution_time=' . $recommendedMaximumExecutionTime
379 );
380 } elseif ($currentMaximumExecutionTime < $recommendedMaximumExecutionTime) {
381 $status = new Status\WarningStatus();
382 $status->setTitle('Low PHP script execution time');
383 $status->setMessage(
384 'max_execution_time=' . $currentMaximumExecutionTime . LF .
385 'Your max_execution_time is low. While TYPO3 often runs without problems' .
386 ' with ' . $minimumMaximumExecutionTime . ' seconds,' .
387 ' it may still happen that script execution is stopped before finishing' .
388 ' calculations. You should monitor the system for messages in this area' .
389 ' and maybe raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF .
390 'max_execution_time=' . $recommendedMaximumExecutionTime
391 );
392 } else {
393 $status = new Status\OkStatus();
394 $status->setTitle('Maximum PHP script execution time is equal to or more than '
395 . $recommendedMaximumExecutionTime);
396 }
397 return $status;
398 }
399
400 /**
401 * Check for disabled functions
402 *
403 * @return Status\StatusInterface
404 */
405 protected function checkDisableFunctions() {
406 $disabledFunctions = trim(ini_get('disable_functions'));
407
408 // Filter "disable_functions"
409 $disabledFunctionsArray = $this->trimExplode(',', $disabledFunctions);
410
411 // Array with strings to find
412 $findStrings = array(
413 // Disabled by default on Ubuntu OS but this is okay since the Core does not use them
414 'pcntl_',
415 );
416 foreach ($disabledFunctionsArray as $key => $disabledFunction) {
417 foreach ($findStrings as $findString) {
418 if (strpos($disabledFunction, $findString) !== FALSE) {
419 unset($disabledFunctionsArray[$key]);
420 }
421 }
422 }
423
424 if ($disabledFunctions !== '') {
425 if (!empty($disabledFunctionsArray)) {
426 $status = new Status\ErrorStatus();
427 $status->setTitle('Some PHP functions disabled');
428 $status->setMessage(
429 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF .
430 'These function(s) are disabled. TYPO3 uses some of those, so there might be trouble.' .
431 ' TYPO3 is designed to use the default set of PHP functions plus some common extensions.' .
432 ' Possibly these functions are disabled' .
433 ' due to security considerations and most likely the list would include a function like' .
434 ' exec() which is used by TYPO3 at various places. Depending on which exact functions' .
435 ' are disabled, some parts of the system may just break without further notice.'
436 );
437 } else {
438 $status = new Status\NoticeStatus();
439 $status->setTitle('Some PHP functions currently disabled but OK');
440 $status->setMessage(
441 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF .
442 'These function(s) are disabled. TYPO3 uses currently none of those, so you are good to go.'
443 );
444 }
445 } else {
446 $status = new Status\OkStatus();
447 $status->setTitle('No disabled PHP functions');
448 }
449 return $status;
450 }
451
452 /**
453 * Check if it is possible to download external data (e.g. TER)
454 * Either allow_url_fopen must be enabled or curl must be used
455 *
456 * @return Status\OkStatus|Status\WarningStatus
457 */
458 protected function checkDownloadsPossible() {
459 $allowUrlFopen = (bool)ini_get('allow_url_fopen');
460 $curlEnabled = !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse']);
461 if ($allowUrlFopen || $curlEnabled) {
462 $status = new Status\OkStatus();
463 $status->setTitle('Fetching external URLs is allowed');
464 } else {
465 $status = new Status\WarningStatus();
466 $status->setTitle('Fetching external URLs is not allowed');
467 $status->setMessage(
468 'Either enable PHP runtime setting "allow_url_fopen"' . LF . 'or enable curl by setting [SYS][curlUse] accordingly.'
469 );
470 }
471 return $status;
472 }
473
474 /**
475 * Check for doc_root ini setting
476 *
477 * @return Status\StatusInterface
478 */
479 protected function checkDocRoot() {
480 $docRootSetting = trim(ini_get('doc_root'));
481 if ($docRootSetting !== '') {
482 $status = new Status\NoticeStatus();
483 $status->setTitle('doc_root is set');
484 $status->setMessage(
485 'doc_root=' . $docRootSetting . LF .
486 'PHP cannot execute scripts' .
487 ' outside this directory. This setting is seldom used and must correlate' .
488 ' with your actual document root. You might be in trouble if your' .
489 ' TYPO3 CMS core code is linked to some different location.' .
490 ' If that is a problem, the setting must be changed.'
491 );
492 } else {
493 $status = new Status\OkStatus();
494 $status->setTitle('PHP doc_root is not set');
495 }
496 return $status;
497 }
498
499 /**
500 * Check open_basedir
501 *
502 * @return Status\StatusInterface
503 */
504 protected function checkOpenBaseDir() {
505 $openBaseDirSetting = trim(ini_get('open_basedir'));
506 if ($openBaseDirSetting !== '') {
507 $status = new Status\NoticeStatus();
508 $status->setTitle('PHP open_basedir is set');
509 $status->setMessage(
510 'open_basedir = ' . ini_get('open_basedir') . LF .
511 'This restricts TYPO3 to open and include files only in this' .
512 ' path. Please make sure that this does not prevent TYPO3 from running,' .
513 ' if for example your TYPO3 CMS core is linked to a different directory' .
514 ' not included in this path.'
515 );
516 } else {
517 $status = new Status\OkStatus();
518 $status->setTitle('PHP open_basedir is off');
519 }
520 return $status;
521 }
522
523 /**
524 * If xdebug is loaded, the default max_nesting_level of 100 must be raised
525 *
526 * @return Status\StatusInterface
527 */
528 protected function checkXdebugMaxNestingLevel() {
529 if (extension_loaded('xdebug')) {
530 $recommendedMaxNestingLevel = 400;
531 $errorThreshold = 250;
532 $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level');
533 if ($currentMaxNestingLevel < $errorThreshold) {
534 $status = new Status\ErrorStatus();
535 $status->setTitle('PHP xdebug.max_nesting_level is critically low');
536 $status->setMessage(
537 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF .
538 'This setting controls the maximum number of nested function calls to protect against' .
539 ' infinite recursion. The current value is too low for TYPO3 CMS and must' .
540 ' be either raised or xdebug has to be unloaded. A value of ' . $recommendedMaxNestingLevel .
541 ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS' .
542 ' if the value is not raised significantly to:' . LF .
543 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel
544 );
545 } elseif ($currentMaxNestingLevel < $recommendedMaxNestingLevel) {
546 $status = new Status\WarningStatus();
547 $status->setTitle('PHP xdebug.max_nesting_level is low');
548 $status->setMessage(
549 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF .
550 'This setting controls the maximum number of nested function calls to protect against' .
551 ' infinite recursion. The current value is high enough for the TYPO3 CMS core to work' .
552 ' fine, but still some extensions could raise fatal PHP errors if the setting is not' .
553 ' raised further. A value of ' . $recommendedMaxNestingLevel . ' is recommended.' . LF .
554 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel
555 );
556 } else {
557 $status = new Status\OkStatus();
558 $status->setTitle('PHP xdebug.max_nesting_level ok');
559 }
560 } else {
561 $status = new Status\OkStatus();
562 $status->setTitle('PHP xdebug extension not loaded');
563 }
564 return $status;
565 }
566
567 /**
568 * Check accessibility and functionality of OpenSSL
569 *
570 * @return Status\StatusInterface
571 */
572 protected function checkOpenSslInstalled() {
573 if (extension_loaded('openssl')) {
574 $testKey = @openssl_pkey_new();
575 if (is_resource($testKey)) {
576 openssl_free_key($testKey);
577 $status = new Status\OkStatus();
578 $status->setTitle('PHP OpenSSL extension installed properly');
579 } else {
580 $status = new Status\ErrorStatus();
581 $status->setTitle('PHP OpenSSL extension not working');
582 $status->setMessage(
583 'Something went wrong while trying to create a new private key for testing.' .
584 ' Please check the integration of the PHP OpenSSL extension and if it is installed correctly.'
585 );
586 }
587 } else {
588 $status = new Status\ErrorStatus();
589 $status->setTitle('PHP OpenSSL extension not loaded');
590 $status->setMessage(
591 'OpenSSL is a PHP extension to encrypt/decrypt data between requests.' .
592 ' TYPO3 CMS requires it to be able to encrypt stored passwords to improve the security in the' .
593 ' database layer.'
594 );
595 }
596
597 return $status;
598 }
599
600 /**
601 * Get max_input_vars status
602 *
603 * @return Status\StatusInterface
604 */
605 protected function checkMaxInputVars() {
606 $recommendedMaxInputVars = 1500;
607 $minimumMaxInputVars = 1000;
608 $currentMaxInputVars = ini_get('max_input_vars');
609
610 if ($currentMaxInputVars < $minimumMaxInputVars) {
611 $status = new Status\ErrorStatus();
612 $status->setTitle('PHP max_input_vars too low');
613 $status->setMessage(
614 'max_input_vars=' . $currentMaxInputVars . LF .
615 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
616 ' (as the install tool does). It is highly recommended to raise this' .
617 ' to at least ' . $recommendedMaxInputVars . ':' . LF .
618 'max_input_vars=' . $recommendedMaxInputVars
619 );
620 } elseif ($currentMaxInputVars < $recommendedMaxInputVars) {
621 $status = new Status\WarningStatus();
622 $status->setTitle('PHP max_input_vars very low');
623 $status->setMessage(
624 'max_input_vars=' . $currentMaxInputVars . LF .
625 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
626 ' (as the install tool does). It is highly recommended to raise this' .
627 ' to at least ' . $recommendedMaxInputVars . ':' . LF .
628 'max_input_vars=' . $recommendedMaxInputVars
629 );
630 } else {
631 $status = new Status\OkStatus();
632 $status->setTitle('PHP max_input_vars ok');
633 }
634 return $status;
635 }
636
637 /**
638 * Get suhosin loaded status
639 * Should be called only if suhosin extension is loaded
640 *
641 * @return Status\StatusInterface
642 * @throws \BadMethodCallException
643 */
644 protected function getSuhosinLoadedStatus() {
645 if ($this->isSuhosinLoadedAndActive()) {
646 $status = new Status\OkStatus();
647 $status->setTitle('PHP suhosin extension loaded and active');
648 return $status;
649 } else {
650 throw new \BadMethodCallException('Should be called only if suhosin extension is loaded', 1422634778);
651 }
652 }
653
654 /**
655 * Check suhosin.request.max_vars
656 *
657 * @return Status\StatusInterface
658 */
659 protected function checkSuhosinRequestMaxVars() {
660 $recommendedRequestMaxVars = 400;
661 if ($this->isSuhosinLoadedAndActive()) {
662 $currentRequestMaxVars = ini_get('suhosin.request.max_vars');
663 if ($currentRequestMaxVars < $recommendedRequestMaxVars) {
664 $status = new Status\ErrorStatus();
665 $status->setTitle('PHP suhosin.request.max_vars too low');
666 $status->setMessage(
667 'suhosin.request.max_vars=' . $currentRequestMaxVars . LF .
668 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
669 ' (as the install tool does). It is highly recommended to raise this' .
670 ' to at least ' . $recommendedRequestMaxVars . ':' . LF .
671 'suhosin.request.max_vars=' . $recommendedRequestMaxVars
672 );
673 } else {
674 $status = new Status\OkStatus();
675 $status->setTitle('PHP suhosin.request.max_vars ok');
676 }
677 } else {
678 $status = new Status\InfoStatus();
679 $status->setTitle('Suhosin not loaded');
680 $status->setMessage(
681 'If enabling suhosin, suhosin.request.max_vars' .
682 ' should be set to at least ' . $recommendedRequestMaxVars . ':' . LF .
683 'suhosin.request.max_vars=' . $recommendedRequestMaxVars
684 );
685 }
686 return $status;
687 }
688
689 /**
690 * Check suhosin.request.max_varname_length
691 *
692 * @return Status\StatusInterface
693 */
694 protected function checkSuhosinRequestMaxVarnameLength() {
695 $recommendedRequestMaxVarnameLength = 200;
696 if ($this->isSuhosinLoadedAndActive()) {
697 $currentRequestMaxVarnameLength = ini_get('suhosin.request.max_varname_length');
698 if ($currentRequestMaxVarnameLength < $recommendedRequestMaxVarnameLength) {
699 $status = new Status\ErrorStatus();
700 $status->setTitle('PHP suhosin.request.max_varname_length too low');
701 $status->setMessage(
702 'suhosin.request.max_varname_length=' . $currentRequestMaxVarnameLength . LF .
703 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
704 ' (as the install tool does). It is highly recommended to raise this' .
705 ' to at least ' . $recommendedRequestMaxVarnameLength . ':' . LF .
706 'suhosin.request.max_varname_length=' . $recommendedRequestMaxVarnameLength
707 );
708 } else {
709 $status = new Status\OkStatus();
710 $status->setTitle('PHP suhosin.request.max_varname_length ok');
711 }
712 } else {
713 $status = new Status\InfoStatus();
714 $status->setTitle('Suhosin not loaded');
715 $status->setMessage(
716 'If enabling suhosin, suhosin.request.max_varname_length' .
717 ' should be set to at least ' . $recommendedRequestMaxVarnameLength . ':' . LF .
718 'suhosin.request.max_varname_length=' . $recommendedRequestMaxVarnameLength
719 );
720 }
721 return $status;
722 }
723
724 /**
725 * Check suhosin.post.max_name_length
726 *
727 * @return Status\StatusInterface
728 */
729 protected function checkSuhosinPostMaxNameLength() {
730 $recommendedPostMaxNameLength = 200;
731 if ($this->isSuhosinLoadedAndActive()) {
732 $currentPostMaxNameLength = ini_get('suhosin.post.max_name_length');
733 if ($currentPostMaxNameLength < $recommendedPostMaxNameLength) {
734 $status = new Status\ErrorStatus();
735 $status->setTitle('PHP suhosin.post.max_name_length too low');
736 $status->setMessage(
737 'suhosin.post.max_name_length=' . $currentPostMaxNameLength . LF .
738 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
739 ' (as the install tool does). It is highly recommended to raise this' .
740 ' to at least ' . $recommendedPostMaxNameLength . ':' . LF .
741 'suhosin.post.max_name_length=' . $recommendedPostMaxNameLength
742 );
743 } else {
744 $status = new Status\OkStatus();
745 $status->setTitle('PHP suhosin.post.max_name_length ok');
746 }
747 } else {
748 $status = new Status\InfoStatus();
749 $status->setTitle('Suhosin not loaded');
750 $status->setMessage(
751 'If enabling suhosin, suhosin.post.max_name_length' .
752 ' should be set to at least ' . $recommendedPostMaxNameLength . ':' . LF .
753 'suhosin.post.max_name_length=' . $recommendedPostMaxNameLength
754 );
755 }
756 return $status;
757 }
758
759 /**
760 * Check suhosin.post.max_vars
761 *
762 * @return Status\StatusInterface
763 */
764 protected function checkSuhosinPostMaxVars() {
765 $recommendedPostMaxVars = 400;
766 if ($this->isSuhosinLoadedAndActive()) {
767 $currentPostMaxVars = ini_get('suhosin.post.max_vars');
768 if ($currentPostMaxVars < $recommendedPostMaxVars) {
769 $status = new Status\ErrorStatus();
770 $status->setTitle('PHP suhosin.post.max_vars too low');
771 $status->setMessage(
772 'suhosin.post.max_vars=' . $currentPostMaxVars . LF .
773 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
774 ' (as the install tool does). It is highly recommended to raise this' .
775 ' to at least ' . $recommendedPostMaxVars . ':' . LF .
776 'suhosin.post.max_vars=' . $recommendedPostMaxVars
777 );
778 } else {
779 $status = new Status\OkStatus();
780 $status->setTitle('PHP suhosin.post.max_vars ok');
781 }
782 } else {
783 $status = new Status\InfoStatus();
784 $status->setTitle('Suhosin not loaded');
785 $status->setMessage(
786 'If enabling suhosin, suhosin.post.max_vars' .
787 ' should be set to at least ' . $recommendedPostMaxVars . ':' . LF .
788 'suhosin.post.max_vars=' . $recommendedPostMaxVars
789 );
790 }
791 return $status;
792 }
793
794 /**
795 * Check suhosin.get.max_value_length
796 *
797 * @return Status\StatusInterface
798 */
799 protected function checkSuhosinGetMaxValueLength() {
800 $recommendedGetMaxValueLength = 2000;
801 if ($this->isSuhosinLoadedAndActive()) {
802 $currentGetMaxValueLength = ini_get('suhosin.get.max_value_length');
803 if ($currentGetMaxValueLength < $recommendedGetMaxValueLength) {
804 $status = new Status\ErrorStatus();
805 $status->setTitle('PHP suhosin.get.max_value_length too low');
806 $status->setMessage(
807 'suhosin.get.max_value_length=' . $currentGetMaxValueLength . LF .
808 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
809 ' (as the install tool does). It is highly recommended to raise this' .
810 ' to at least ' . $recommendedGetMaxValueLength . ':' . LF .
811 'suhosin.get.max_value_length=' . $recommendedGetMaxValueLength
812 );
813 } else {
814 $status = new Status\OkStatus();
815 $status->setTitle('PHP suhosin.get.max_value_length ok');
816 }
817 } else {
818 $status = new Status\InfoStatus();
819 $status->setTitle('Suhosin not loaded');
820 $status->setMessage(
821 'If enabling suhosin, suhosin.get.max_value_length' .
822 ' should be set to at least ' . $recommendedGetMaxValueLength . ':' . LF .
823 'suhosin.get.max_value_length=' . $recommendedGetMaxValueLength
824 );
825 }
826 return $status;
827 }
828
829 /**
830 * Check suhosin.get.max_name_length
831 *
832 * @return Status\StatusInterface
833 */
834 protected function checkSuhosinGetMaxNameLength() {
835 $recommendedGetMaxNameLength = 200;
836 if ($this->isSuhosinLoadedAndActive()) {
837 $currentGetMaxNameLength = ini_get('suhosin.get.max_name_length');
838 if ($currentGetMaxNameLength < $recommendedGetMaxNameLength) {
839 $status = new Status\ErrorStatus();
840 $status->setTitle('PHP suhosin.get.max_name_length too low');
841 $status->setMessage(
842 'suhosin.get.max_name_length=' . $currentGetMaxNameLength . LF .
843 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
844 ' (as the install tool does). It is highly recommended to raise this' .
845 ' to at least ' . $recommendedGetMaxNameLength . ':' . LF .
846 'suhosin.get.max_name_length=' . $recommendedGetMaxNameLength
847 );
848 } else {
849 $status = new Status\OkStatus();
850 $status->setTitle('PHP suhosin.get.max_name_length ok');
851 }
852 } else {
853 $status = new Status\InfoStatus();
854 $status->setTitle('Suhosin not loaded');
855 $status->setMessage(
856 'If enabling suhosin, suhosin.get.max_name_length' .
857 ' should be set to at least ' . $recommendedGetMaxNameLength . ':' . LF .
858 'suhosin.get.max_name_length=' . $recommendedGetMaxNameLength
859 );
860 }
861 return $status;
862 }
863
864 /**
865 * Check suhosin.executor.include.whitelist contains phar
866 *
867 * @return Status\StatusInterface
868 */
869 protected function checkSuhosinExecutorIncludeWhiteListContainsPhar() {
870 if ($this->isSuhosinLoadedAndActive()) {
871 $whitelist = (string)ini_get('suhosin.executor.include.whitelist');
872 if (strpos($whitelist, 'phar') === FALSE) {
873 $status = new Status\NoticeStatus();
874 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain phar');
875 $status->setMessage(
876 'suhosin.executor.include.whitelist= ' . $whitelist . LF .
877 '"phar" is currently not a hard requirement of TYPO3 CMS but is nice to have and a possible' .
878 ' requirement in future versions. A useful setting is:' . LF .
879 'suhosin.executor.include.whitelist=phar,vfs'
880 );
881 } else {
882 $status = new Status\OkStatus();
883 $status->setTitle('PHP suhosin.executor.include.whitelist contains phar');
884 }
885 } else {
886 $status = new Status\InfoStatus();
887 $status->setTitle('Suhosin not loaded');
888 $status->setMessage(
889 'If enabling suhosin, a useful setting is:' . LF .
890 'suhosin.executor.include.whitelist=phar,vfs'
891 );
892 }
893 return $status;
894 }
895
896 /**
897 * Check suhosin.executor.include.whitelist contains vfs
898 *
899 * @return Status\StatusInterface
900 */
901 protected function checkSuhosinExecutorIncludeWhiteListContainsVfs() {
902 if ($this->isSuhosinLoadedAndActive()) {
903 $whitelist = (string)ini_get('suhosin.executor.include.whitelist');
904 if (strpos($whitelist, 'vfs') === FALSE) {
905 $status = new Status\WarningStatus();
906 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain vfs');
907 $status->setMessage(
908 'suhosin.executor.include.whitelist= ' . $whitelist . LF .
909 '"vfs" is currently not a hard requirement of TYPO3 CMS but tons of unit tests rely on it.' .
910 ' Furthermore, vfs will likely be a base for an additional compatibility layer in the future.' .
911 ' A useful setting is:' . LF .
912 'suhosin.executor.include.whitelist=phar,vfs'
913 );
914 } else {
915 $status = new Status\OkStatus();
916 $status->setTitle('PHP suhosin.executor.include.whitelist contains vfs');
917 }
918 } else {
919 $status = new Status\InfoStatus();
920 $status->setTitle('Suhosin not loaded');
921 $status->setMessage(
922 'If enabling suhosin, a useful setting is:' . LF .
923 'suhosin.executor.include.whitelist=phar,vfs'
924 );
925 }
926 return $status;
927 }
928
929 /**
930 * Check if some opcode cache is loaded
931 *
932 * @return Status\StatusInterface
933 */
934 protected function checkSomePhpOpcodeCacheIsLoaded() {
935 // Link to our wiki page, so we can update opcode cache issue information independent of TYPO3 CMS releases.
936 $wikiLink = 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.';
937 $opcodeCaches = GeneralUtility::makeInstance(OpcodeCacheService::class)->getAllActive();
938 if (empty($opcodeCaches)) {
939 // Set status to notice. It needs to be notice so email won't be triggered.
940 $status = new Status\NoticeStatus();
941 $status->setTitle('No PHP opcode cache loaded');
942 $status->setMessage(
943 'PHP opcode caches hold a compiled version of executed PHP scripts in' .
944 ' memory and do not require to recompile a script each time it is accessed.' .
945 ' This can be a massive performance improvement and can reduce the load on a' .
946 ' server in general. A parse time reduction by factor three for fully cached' .
947 ' pages can be achieved easily if using an opcode cache.' .
948 LF . $wikiLink
949 );
950 } else {
951 $status = new Status\OkStatus();
952 $message = '';
953
954 foreach ($opcodeCaches as $opcodeCache => $properties) {
955 $message .= 'Name: ' . $opcodeCache . ' Version: ' . $properties['version'];
956 $message .= LF;
957
958 if ($properties['error']) {
959 // Set status to error if not already set
960 if ($status->getSeverity() !== 'error') {
961 $status = new Status\ErrorStatus();
962 }
963 $message .= ' This opcode cache is marked as malfunctioning by the TYPO3 CMS Team.';
964 } elseif ($properties['canInvalidate']) {
965 $message .= ' This opcode cache should work correctly and has good performance.';
966 } else {
967 // Set status to notice if not already error set. It needs to be notice so email won't be triggered.
968 if ($status->getSeverity() !== 'error' || $status->getSeverity() !== 'warning') {
969 $status = new Status\NoticeStatus();
970 }
971 $message .= ' This opcode cache may work correctly but has medium performance.';
972 }
973 $message .= LF;
974 }
975
976 $message .= $wikiLink;
977
978 // Set title of status depending on serverity
979 switch ($status->getSeverity()) {
980 case 'error':
981 $status->setTitle('A possibly malfunctioning PHP opcode cache is loaded');
982 break;
983 case 'warning':
984 $status->setTitle('A PHP opcode cache is loaded which may cause problems');
985 break;
986 case 'ok':
987 default:
988 $status->setTitle('A PHP opcode cache is loaded');
989 break;
990 }
991 $status->setMessage($message);
992 }
993 return $status;
994 }
995
996 /**
997 * Check doc comments can be fetched by reflection
998 *
999 * @return Status\StatusInterface
1000 */
1001 protected function checkReflectionDocComment() {
1002 $testReflection = new \ReflectionMethod(get_class($this), __FUNCTION__);
1003 if ($testReflection->getDocComment() === FALSE) {
1004 $status = new Status\AlertStatus();
1005 $status->setTitle('PHP Doc comment reflection broken');
1006 $status->setMessage(
1007 'TYPO3 CMS core extensions like extbase and fluid heavily rely on method'
1008 . ' comment parsing to fetch annotations and add magic belonging to them.'
1009 . ' This does not work in the current environment and so we cannot install'
1010 . ' TYPO3 CMS.' . LF
1011 . ' Here are some possibilities: ' . LF
1012 . '* In Zend OPcache you can disable saving/loading comments. If you are using'
1013 . ' Zend OPcache (included since PHP 5.5) then check your php.ini settings for'
1014 . ' opcache.save_comments and opcache.load_comments and enable them.' . LF
1015 . '* In Zend Optimizer+ you can disable saving comments. If you are using'
1016 . ' Zend Optimizer+ then check your php.ini settings for'
1017 . ' zend_optimizerplus.save_comments and enable it.' . LF
1018 . '* The PHP extension eaccelerator is known to break this if'
1019 . ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.'
1020 . ' This compile flag must be specified, otherwise TYPO3 CMS will not work.' . LF
1021 . 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.'
1022 );
1023 } else {
1024 $status = new Status\OkStatus();
1025 $status->setTitle('PHP Doc comment reflection works');
1026 }
1027 return $status;
1028 }
1029
1030 /**
1031 * Check if systemLocale setting is correct (locale exists in the OS)
1032 *
1033 * @return Status\StatusInterface
1034 */
1035 protected function checkSystemLocale() {
1036
1037 $currentLocale = setlocale(LC_CTYPE, 0);
1038
1039 // On Windows an empty locale value uses the regional settings from the Control Panel
1040 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
1041 $status = new Status\InfoStatus();
1042 $status->setTitle('Empty systemLocale setting');
1043 $status->setMessage(
1044 '$GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is not set. This is fine as long as no UTF-8' .
1045 ' file system is used.'
1046 );
1047 } elseif (setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']) === FALSE) {
1048 $status = new Status\ErrorStatus();
1049 $status->setTitle('Incorrect systemLocale setting');
1050 $status->setMessage(
1051 'Current value of the $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is incorrect. A locale with' .
1052 ' this name doesn\'t exist in the operating system.'
1053 );
1054 setlocale(LC_CTYPE, $currentLocale);
1055 } else {
1056 $status = new Status\OkStatus();
1057 $status->setTitle('System locale is correct');
1058 }
1059
1060 return $status;
1061 }
1062
1063 /**
1064 * Checks whether we can use file names with UTF-8 characters.
1065 * Configured system locale must support UTF-8 when UTF8filesystem is set
1066 *
1067 * @return Status\StatusInterface
1068 */
1069 protected function checkLocaleWithUTF8filesystem() {
1070
1071 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
1072
1073 // On Windows an empty local value uses the regional settings from the Control Panel
1074 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
1075 $status = new Status\ErrorStatus();
1076 $status->setTitle('System locale not set on UTF-8 file system');
1077 $status->setMessage(
1078 '$GLOBALS[TYPO3_CONF_VARS][SYS][UTF8filesystem] is set, but $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale]' .
1079 ' is empty. Make sure a valid locale which supports UTF-8 is set.'
1080 );
1081 } else {
1082 $testString = 'ÖöĄĆŻĘĆćążąęó.jpg';
1083 $currentLocale = setlocale(LC_CTYPE, 0);
1084 $quote = TYPO3_OS === 'WIN' ? '"' : '\'';
1085
1086 setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
1087
1088 if (escapeshellarg($testString) === $quote . $testString . $quote) {
1089 $status = new Status\OkStatus();
1090 $status->setTitle('File names with UTF-8 characters can be used.');
1091 } else {
1092 $status = new Status\ErrorStatus();
1093 $status->setTitle('System locale setting doesn\'t support UTF-8 file names.');
1094 $status->setMessage(
1095 'Please check your $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] setting.'
1096 );
1097 }
1098
1099 setlocale(LC_CTYPE, $currentLocale);
1100 }
1101
1102
1103 } else {
1104 $status = new Status\OkStatus();
1105 $status->setTitle('Skipping test, as UTF8filesystem is not enabled.');
1106 }
1107
1108 return $status;
1109 }
1110
1111 /**
1112 * Checks thread stack size if on windows with apache
1113 *
1114 * @return Status\StatusInterface
1115 */
1116 protected function checkWindowsApacheThreadStackSize() {
1117 if (
1118 $this->isWindowsOs()
1119 && substr($_SERVER['SERVER_SOFTWARE'], 0, 6) === 'Apache'
1120 ) {
1121 $status = new Status\WarningStatus();
1122 $status->setTitle('Windows apache thread stack size');
1123 $status->setMessage(
1124 'This current value cannot be checked by the system, so please ignore this warning if it' .
1125 ' is already taken care of: Fluid uses complex regular expressions which require a lot' .
1126 ' of stack space during the first processing.' .
1127 ' On Windows the default stack size for Apache is a lot smaller than on UNIX.' .
1128 ' You can increase the size to 8MB (default on UNIX) by adding the following configuration' .
1129 ' to httpd.conf and restarting Apache afterwards:' . LF .
1130 '<IfModule mpm_winnt_module>' . LF .
1131 'ThreadStackSize 8388608' . LF .
1132 '</IfModule>'
1133 );
1134 } else {
1135 $status = new Status\OkStatus();
1136 $status->setTitle('Apache ThreadStackSize is not an issue on UNIX systems');
1137 }
1138 return $status;
1139 }
1140
1141 /**
1142 * Check if a specific required PHP extension is loaded
1143 *
1144 * @param string $extension
1145 * @return Status\StatusInterface
1146 */
1147 protected function checkRequiredPhpExtension($extension) {
1148 if (!extension_loaded($extension)) {
1149 $status = new Status\ErrorStatus();
1150 $status->setTitle('PHP extension ' . $extension . ' not loaded');
1151 $status->setMessage(
1152 'TYPO3 CMS uses PHP extension ' . $extension . ' but it is not loaded' .
1153 ' in your environment. Change your environment to provide this extension.'
1154 );
1155 } else {
1156 $status = new Status\OkStatus();
1157 $status->setTitle('PHP extension ' . $extension . ' loaded');
1158 }
1159 return $status;
1160 }
1161
1162 /**
1163 * Check imagecreatetruecolor to verify gdlib works as expected
1164 *
1165 * @return Status\StatusInterface
1166 */
1167 protected function checkGdLibTrueColorSupport() {
1168 if (function_exists('imagecreatetruecolor')) {
1169 $imageResource = @imagecreatetruecolor(50, 100);
1170 if (is_resource($imageResource)) {
1171 imagedestroy($imageResource);
1172 $status = new Status\OkStatus();
1173 $status->setTitle('PHP GD library true color works');
1174 } else {
1175 $status = new Status\ErrorStatus();
1176 $status->setTitle('PHP GD library true color support broken');
1177 $status->setMessage(
1178 'GD is loaded, but calling imagecreatetruecolor() fails.' .
1179 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
1180 );
1181 }
1182 } else {
1183 $status = new Status\ErrorStatus();
1184 $status->setTitle('PHP GD library true color support missing');
1185 $status->setMessage(
1186 'Gdlib is essential for TYPO3 CMS to work properly.'
1187 );
1188 }
1189 return $status;
1190 }
1191
1192 /**
1193 * Check gif support of GD library
1194 *
1195 * @return Status\StatusInterface
1196 */
1197 protected function checkGdLibGifSupport() {
1198 if (
1199 function_exists('imagecreatefromgif')
1200 && function_exists('imagegif')
1201 && (imagetypes() & IMG_GIF)
1202 ) {
1203 $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif');
1204 if (is_resource($imageResource)) {
1205 imagedestroy($imageResource);
1206 $status = new Status\OkStatus();
1207 $status->setTitle('PHP GD library has gif support');
1208 } else {
1209 $status = new Status\ErrorStatus();
1210 $status->setTitle('PHP GD library gif support broken');
1211 $status->setMessage(
1212 'GD is loaded, but calling imagecreatefromgif() fails.' .
1213 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
1214 );
1215 }
1216 } else {
1217 $status = new Status\ErrorStatus();
1218 $status->setTitle('PHP GD library gif support missing');
1219 $status->setMessage(
1220 'GD must be compiled with gif support. This is essential for' .
1221 ' TYPO3 CMS to work properly.'
1222 );
1223 }
1224 return $status;
1225 }
1226
1227 /**
1228 * Check jgp support of GD library
1229 *
1230 * @return Status\StatusInterface
1231 */
1232 protected function checkGdLibJpgSupport() {
1233 if (
1234 function_exists('imagecreatefromjpeg')
1235 && function_exists('imagejpeg')
1236 && (imagetypes() & IMG_JPG)
1237 ) {
1238 $status = new Status\OkStatus();
1239 $status->setTitle('PHP GD library has jpg support');
1240 } else {
1241 $status = new Status\ErrorStatus();
1242 $status->setTitle('PHP GD library jpg support missing');
1243 $status->setMessage(
1244 'GD must be compiled with jpg support. This is essential for' .
1245 ' TYPO3 CMS to work properly.'
1246 );
1247 }
1248 return $status;
1249 }
1250
1251 /**
1252 * Check png support of GD library
1253 *
1254 * @return Status\StatusInterface
1255 */
1256 protected function checkGdLibPngSupport() {
1257 if (
1258 function_exists('imagecreatefrompng')
1259 && function_exists('imagepng')
1260 && (imagetypes() & IMG_PNG)
1261 ) {
1262 $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png');
1263 if (is_resource($imageResource)) {
1264 imagedestroy($imageResource);
1265 $status = new Status\OkStatus();
1266 $status->setTitle('PHP GD library has png support');
1267 } else {
1268 $status = new Status\ErrorStatus();
1269 $status->setTitle('PHP GD library png support broken');
1270 $status->setMessage(
1271 'GD is compiled with png support, but calling imagecreatefrompng() fails.' .
1272 ' Check your environment and fix it, png in GD lib is important' .
1273 ' for TYPO3 CMS to work properly.'
1274 );
1275 }
1276 } else {
1277 $status = new Status\ErrorStatus();
1278 $status->setTitle('PHP GD library png support missing');
1279 $status->setMessage(
1280 'GD must be compiled with png support. This is essential for' .
1281 ' TYPO3 CMS to work properly'
1282 );
1283 }
1284 return $status;
1285 }
1286
1287 /**
1288 * Check gdlib supports freetype
1289 *
1290 * @return Status\StatusInterface
1291 */
1292 protected function checkGdLibFreeTypeSupport() {
1293 if (function_exists('imagettftext')) {
1294 $status = new Status\OkStatus();
1295 $status->setTitle('PHP GD library has freetype font support');
1296 $status->setMessage(
1297 'There is a difference between the font size setting which the GD' .
1298 ' library should be supplied with. If installation is completed' .
1299 ' a test in the install tool helps to find out the value you need.'
1300 );
1301 } else {
1302 $status = new Status\ErrorStatus();
1303 $status->setTitle('PHP GD library freetype support missing');
1304 $status->setMessage(
1305 'Some core functionality and extension rely on the GD' .
1306 ' to render fonts on images. This support is missing' .
1307 ' in your environment. Install it.'
1308 );
1309 }
1310 return $status;
1311 }
1312
1313 /**
1314 * Create true type font test image
1315 *
1316 * @return Status\StatusInterface
1317 */
1318 protected function isTrueTypeFontWorking() {
1319 if (function_exists('imageftbbox')) {
1320 // 20 Pixels at 96 DPI
1321 $fontSize = (20 / 96 * 72);
1322 $textDimensions = @imageftbbox(
1323 $fontSize,
1324 0,
1325 __DIR__ . '/../../Resources/Private/Font/vera.ttf',
1326 'Testing true type support'
1327 );
1328 $fontBoxWidth = $textDimensions[2] - $textDimensions[0];
1329 if ($fontBoxWidth < 300 && $fontBoxWidth > 200) {
1330 $status = new Status\OkStatus();
1331 $status->setTitle('FreeType True Type Font DPI');
1332 $status->setMessage('Fonts are rendered by FreeType library. ' .
1333 'We need to ensure that the final dimensions are as expected. ' .
1334 'This server renderes fonts based on 96 DPI correctly'
1335 );
1336 } else {
1337 $status = new Status\NoticeStatus();
1338 $status->setTitle('FreeType True Type Font DPI');
1339 $status->setMessage('Fonts are rendered by FreeType library. ' .
1340 'This server does not render fonts as expected. ' .
1341 'Please check your FreeType 2 module.'
1342 );
1343 }
1344 } else {
1345 $status = new Status\ErrorStatus();
1346 $status->setTitle('PHP GD library freetype2 support missing');
1347 $status->setMessage(
1348 'The core relies on GD library compiled into PHP with freetype2' .
1349 ' support. This is missing on your system. Please install it.'
1350 );
1351 }
1352
1353 return $status;
1354 }
1355
1356 /**
1357 * Check register globals
1358 *
1359 * @return Status\StatusInterface
1360 */
1361 protected function checkRegisterGlobals() {
1362 $registerGlobalsEnabled = filter_var(
1363 ini_get('register_globals'),
1364 FILTER_VALIDATE_BOOLEAN,
1365 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
1366 );
1367 if ($registerGlobalsEnabled === TRUE) {
1368 $status = new Status\ErrorStatus();
1369 $status->setTitle('PHP register globals on');
1370 $status->setMessage(
1371 'register_globals=' . ini_get('register_globals') . LF .
1372 'TYPO3 requires PHP setting "register_globals" set to off.' .
1373 ' This ancient PHP setting is a big security problem and should' .
1374 ' never be enabled:' . LF .
1375 'register_globals=Off'
1376 );
1377 } else {
1378 $status = new Status\OkStatus();
1379 $status->setTitle('PHP register globals off');
1380 }
1381 return $status;
1382 }
1383
1384 /**
1385 * Check for bug in libxml
1386 *
1387 * @return Status\StatusInterface
1388 */
1389 protected function checkLibXmlBug() {
1390 $sampleArray = array('Test>><<Data');
1391
1392 $xmlContent = '<numIndex index="0">Test&gt;&gt;&lt;&lt;Data</numIndex>' . LF;
1393
1394 $xml = \TYPO3\CMS\Core\Utility\GeneralUtility::array2xml($sampleArray, '', -1);
1395
1396 if ($xmlContent !== $xml) {
1397 $status = new Status\ErrorStatus();
1398 $status->setTitle('PHP libxml bug present');
1399 $status->setMessage(
1400 'Some hosts have problems saving ">><<" in a flexform.' .
1401 ' To fix this, enable [BE][flexformForceCDATA] in' .
1402 ' All Configuration.'
1403 );
1404 } else {
1405 $status = new Status\OkStatus();
1406 $status->setTitle('PHP libxml bug not present');
1407 }
1408 return $status;
1409 }
1410
1411 /**
1412 * Helper methods
1413 */
1414
1415 /**
1416 * Validate a given IP address.
1417 *
1418 * @param string $ip IP address to be tested
1419 * @return bool
1420 */
1421 protected function isValidIp($ip) {
1422 return filter_var($ip, FILTER_VALIDATE_IP) !== FALSE;
1423 }
1424
1425 /**
1426 * Test if this instance runs on windows OS
1427 *
1428 * @return bool TRUE if operating system is windows
1429 */
1430 protected function isWindowsOs() {
1431 $windowsOs = FALSE;
1432 if (!stristr(PHP_OS, 'darwin') && stristr(PHP_OS, 'win')) {
1433 $windowsOs = TRUE;
1434 }
1435 return $windowsOs;
1436 }
1437
1438 /**
1439 * Helper method to find out if suhosin extension is loaded
1440 *
1441 * @return bool TRUE if suhosin PHP extension is loaded
1442 */
1443 protected function isSuhosinLoadedAndActive() {
1444 $suhosinLoaded = FALSE;
1445 if (extension_loaded('suhosin')) {
1446 $suhosinInSimulationMode = filter_var(
1447 ini_get('suhosin.simulation'),
1448 FILTER_VALIDATE_BOOLEAN,
1449 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
1450 );
1451 if (!$suhosinInSimulationMode) {
1452 $suhosinLoaded = TRUE;
1453 }
1454 }
1455 return $suhosinLoaded;
1456 }
1457
1458 /**
1459 * Helper method to explode a string by delimiter and throw away empty values.
1460 * Removes empty values from result array.
1461 *
1462 * @param string $delimiter Delimiter string to explode with
1463 * @param string $string The string to explode
1464 * @return array Exploded values
1465 */
1466 protected function trimExplode($delimiter, $string) {
1467 $explodedValues = explode($delimiter, $string);
1468 $resultWithPossibleEmptyValues = array_map('trim', $explodedValues);
1469 $result = array();
1470 foreach ($resultWithPossibleEmptyValues as $value) {
1471 if ($value !== '') {
1472 $result[] = $value;
1473 }
1474 }
1475 return $result;
1476 }
1477
1478 /**
1479 * Helper method to get the bytes value from a measurement string like "100k".
1480 *
1481 * @param string $measurement The measurement (e.g. "100k")
1482 * @return int The bytes value (e.g. 102400)
1483 */
1484 protected function getBytesFromSizeMeasurement($measurement) {
1485 $bytes = doubleval($measurement);
1486 if (stripos($measurement, 'G')) {
1487 $bytes *= 1024 * 1024 * 1024;
1488 } elseif (stripos($measurement, 'M')) {
1489 $bytes *= 1024 * 1024;
1490 } elseif (stripos($measurement, 'K')) {
1491 $bytes *= 1024;
1492 }
1493 return (int)$bytes;
1494 }
1495
1496 }