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