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