[FEATURE] Make the image quality definable per sourceCollection
[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 5.6 or newer
477 *
478 * @return Status\StatusInterface
479 */
480 protected function checkAlwaysPopulateRawPostDataSetting() {
481 $minimumPhpVersion = '5.6.0';
482 $currentPhpVersion = phpversion();
483 $currentAlwaysPopulaterRawPostDataSetting = ini_get('always_populate_raw_post_data');
484 if (version_compare($currentPhpVersion, $minimumPhpVersion) >= 0 && $currentAlwaysPopulaterRawPostDataSetting !== '-1') {
485 $status = new Status\ErrorStatus();
486 $status->setTitle('PHP always_populate_raw_post_data is deprecated');
487 $status->setMessage(
488 'always_populate_raw_post_data=' . $currentAlwaysPopulaterRawPostDataSetting . LF .
489 'PHP is configured to automatically populate $HTTP_RAW_POST_DATA.' . LF .
490 ' Warning: Expect fatal errors in central parts of the CMS' .
491 ' if the value is not changed to:' . LF .
492 'always_populate_raw_post_data=-1'
493 );
494 } else {
495 $status = new Status\OkStatus();
496 $status->setTitle('PHP always_populate_raw_post_data is fine');
497 }
498 return $status;
499 }
500
501 /**
502 * Check for doc_root ini setting
503 *
504 * @return Status\StatusInterface
505 */
506 protected function checkDocRoot() {
507 $docRootSetting = trim(ini_get('doc_root'));
508 if ($docRootSetting !== '') {
509 $status = new Status\NoticeStatus();
510 $status->setTitle('doc_root is set');
511 $status->setMessage(
512 'doc_root=' . $docRootSetting . LF .
513 'PHP cannot execute scripts' .
514 ' outside this directory. This setting is seldom used and must correlate' .
515 ' with your actual document root. You might be in trouble if your' .
516 ' TYPO3 CMS core code is linked to some different location.' .
517 ' If that is a problem, the setting must be changed.'
518 );
519 } else {
520 $status = new Status\OkStatus();
521 $status->setTitle('PHP doc_root is not set');
522 }
523 return $status;
524 }
525
526 /**
527 * Check open_basedir
528 *
529 * @return Status\StatusInterface
530 */
531 protected function checkOpenBaseDir() {
532 $openBaseDirSetting = trim(ini_get('open_basedir'));
533 if ($openBaseDirSetting !== '') {
534 $status = new Status\NoticeStatus();
535 $status->setTitle('PHP open_basedir is set');
536 $status->setMessage(
537 'open_basedir = ' . ini_get('open_basedir') . LF .
538 'This restricts TYPO3 to open and include files only in this' .
539 ' path. Please make sure that this does not prevent TYPO3 from running,' .
540 ' if for example your TYPO3 CMS core is linked to a different directory' .
541 ' not included in this path.'
542 );
543 } else {
544 $status = new Status\OkStatus();
545 $status->setTitle('PHP open_basedir is off');
546 }
547 return $status;
548 }
549
550 /**
551 * If xdebug is loaded, the default max_nesting_level of 100 must be raised
552 *
553 * @return Status\StatusInterface
554 */
555 protected function checkXdebugMaxNestingLevel() {
556 if (extension_loaded('xdebug')) {
557 $recommendedMaxNestingLevel = 400;
558 $errorThreshold = 250;
559 $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level');
560 if ($currentMaxNestingLevel < $errorThreshold) {
561 $status = new Status\ErrorStatus();
562 $status->setTitle('PHP xdebug.max_nesting_level is critically low');
563 $status->setMessage(
564 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF .
565 'This setting controls the maximum number of nested function calls to protect against' .
566 ' infinite recursion. The current value is too low for TYPO3 CMS and must' .
567 ' be either raised or xdebug has to be unloaded. A value of ' . $recommendedMaxNestingLevel .
568 ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS' .
569 ' if the value is not raised significantly to:' . LF .
570 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel
571 );
572 } elseif ($currentMaxNestingLevel < $recommendedMaxNestingLevel) {
573 $status = new Status\WarningStatus();
574 $status->setTitle('PHP xdebug.max_nesting_level is low');
575 $status->setMessage(
576 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF .
577 'This setting controls the maximum number of nested function calls to protect against' .
578 ' infinite recursion. The current value is high enough for the TYPO3 CMS core to work' .
579 ' fine, but still some extensions could raise fatal PHP errors if the setting is not' .
580 ' raised further. A value of ' . $recommendedMaxNestingLevel . ' is recommended.' . LF .
581 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel
582 );
583 } else {
584 $status = new Status\OkStatus();
585 $status->setTitle('PHP xdebug.max_nesting_level ok');
586 }
587 } else {
588 $status = new Status\OkStatus();
589 $status->setTitle('PHP xdebug extension not loaded');
590 }
591 return $status;
592 }
593
594 /**
595 * Check accessibility and functionality of OpenSSL
596 *
597 * @return Status\StatusInterface
598 */
599 protected function checkOpenSslInstalled() {
600 if (extension_loaded('openssl')) {
601 $testKey = @openssl_pkey_new();
602 if (is_resource($testKey)) {
603 openssl_free_key($testKey);
604 $status = new Status\OkStatus();
605 $status->setTitle('PHP OpenSSL extension installed properly');
606 } else {
607 $status = new Status\ErrorStatus();
608 $status->setTitle('PHP OpenSSL extension not working');
609 $status->setMessage(
610 'Something went wrong while trying to create a new private key for testing.' .
611 ' Please check the integration of the PHP OpenSSL extension and if it is installed correctly.'
612 );
613 }
614 } else {
615 $status = new Status\ErrorStatus();
616 $status->setTitle('PHP OpenSSL extension not loaded');
617 $status->setMessage(
618 'OpenSSL is a PHP extension to encrypt/decrypt data between requests.' .
619 ' TYPO3 CMS requires it to be able to encrypt stored passwords to improve the security in the' .
620 ' database layer.'
621 );
622 }
623
624 return $status;
625 }
626
627 /**
628 * Get max_input_vars status
629 *
630 * @return Status\StatusInterface
631 */
632 protected function checkMaxInputVars() {
633 $recommendedMaxInputVars = 1500;
634 $minimumMaxInputVars = 1000;
635 $currentMaxInputVars = ini_get('max_input_vars');
636
637 if ($currentMaxInputVars < $minimumMaxInputVars) {
638 $status = new Status\ErrorStatus();
639 $status->setTitle('PHP max_input_vars too low');
640 $status->setMessage(
641 'max_input_vars=' . $currentMaxInputVars . LF .
642 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
643 ' (as the install tool does). It is highly recommended to raise this' .
644 ' to at least ' . $recommendedMaxInputVars . ':' . LF .
645 'max_input_vars=' . $recommendedMaxInputVars
646 );
647 } elseif ($currentMaxInputVars < $recommendedMaxInputVars) {
648 $status = new Status\WarningStatus();
649 $status->setTitle('PHP max_input_vars very low');
650 $status->setMessage(
651 'max_input_vars=' . $currentMaxInputVars . LF .
652 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
653 ' (as the install tool does). It is highly recommended to raise this' .
654 ' to at least ' . $recommendedMaxInputVars . ':' . LF .
655 'max_input_vars=' . $recommendedMaxInputVars
656 );
657 } else {
658 $status = new Status\OkStatus();
659 $status->setTitle('PHP max_input_vars ok');
660 }
661 return $status;
662 }
663
664 /**
665 * Get suhosin loaded status
666 * Should be called only if suhosin extension is loaded
667 *
668 * @return Status\StatusInterface
669 * @throws \BadMethodCallException
670 */
671 protected function getSuhosinLoadedStatus() {
672 if ($this->isSuhosinLoadedAndActive()) {
673 $status = new Status\OkStatus();
674 $status->setTitle('PHP suhosin extension loaded and active');
675 return $status;
676 } else {
677 throw new \BadMethodCallException('Should be called only if suhosin extension is loaded', 1422634778);
678 }
679 }
680
681 /**
682 * Check suhosin.request.max_vars
683 *
684 * @return Status\StatusInterface
685 */
686 protected function checkSuhosinRequestMaxVars() {
687 $recommendedRequestMaxVars = 400;
688 if ($this->isSuhosinLoadedAndActive()) {
689 $currentRequestMaxVars = ini_get('suhosin.request.max_vars');
690 if ($currentRequestMaxVars < $recommendedRequestMaxVars) {
691 $status = new Status\ErrorStatus();
692 $status->setTitle('PHP suhosin.request.max_vars too low');
693 $status->setMessage(
694 'suhosin.request.max_vars=' . $currentRequestMaxVars . LF .
695 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
696 ' (as the install tool does). It is highly recommended to raise this' .
697 ' to at least ' . $recommendedRequestMaxVars . ':' . LF .
698 'suhosin.request.max_vars=' . $recommendedRequestMaxVars
699 );
700 } else {
701 $status = new Status\OkStatus();
702 $status->setTitle('PHP suhosin.request.max_vars ok');
703 }
704 } else {
705 $status = new Status\InfoStatus();
706 $status->setTitle('Suhosin not loaded');
707 $status->setMessage(
708 'If enabling suhosin, suhosin.request.max_vars' .
709 ' should be set to at least ' . $recommendedRequestMaxVars . ':' . LF .
710 'suhosin.request.max_vars=' . $recommendedRequestMaxVars
711 );
712 }
713 return $status;
714 }
715
716 /**
717 * Check suhosin.request.max_varname_length
718 *
719 * @return Status\StatusInterface
720 */
721 protected function checkSuhosinRequestMaxVarnameLength() {
722 $recommendedRequestMaxVarnameLength = 200;
723 if ($this->isSuhosinLoadedAndActive()) {
724 $currentRequestMaxVarnameLength = ini_get('suhosin.request.max_varname_length');
725 if ($currentRequestMaxVarnameLength < $recommendedRequestMaxVarnameLength) {
726 $status = new Status\ErrorStatus();
727 $status->setTitle('PHP suhosin.request.max_varname_length too low');
728 $status->setMessage(
729 'suhosin.request.max_varname_length=' . $currentRequestMaxVarnameLength . LF .
730 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
731 ' (as the install tool does). It is highly recommended to raise this' .
732 ' to at least ' . $recommendedRequestMaxVarnameLength . ':' . LF .
733 'suhosin.request.max_varname_length=' . $recommendedRequestMaxVarnameLength
734 );
735 } else {
736 $status = new Status\OkStatus();
737 $status->setTitle('PHP suhosin.request.max_varname_length ok');
738 }
739 } else {
740 $status = new Status\InfoStatus();
741 $status->setTitle('Suhosin not loaded');
742 $status->setMessage(
743 'If enabling suhosin, suhosin.request.max_varname_length' .
744 ' should be set to at least ' . $recommendedRequestMaxVarnameLength . ':' . LF .
745 'suhosin.request.max_varname_length=' . $recommendedRequestMaxVarnameLength
746 );
747 }
748 return $status;
749 }
750
751 /**
752 * Check suhosin.post.max_name_length
753 *
754 * @return Status\StatusInterface
755 */
756 protected function checkSuhosinPostMaxNameLength() {
757 $recommendedPostMaxNameLength = 200;
758 if ($this->isSuhosinLoadedAndActive()) {
759 $currentPostMaxNameLength = ini_get('suhosin.post.max_name_length');
760 if ($currentPostMaxNameLength < $recommendedPostMaxNameLength) {
761 $status = new Status\ErrorStatus();
762 $status->setTitle('PHP suhosin.post.max_name_length too low');
763 $status->setMessage(
764 'suhosin.post.max_name_length=' . $currentPostMaxNameLength . LF .
765 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
766 ' (as the install tool does). It is highly recommended to raise this' .
767 ' to at least ' . $recommendedPostMaxNameLength . ':' . LF .
768 'suhosin.post.max_name_length=' . $recommendedPostMaxNameLength
769 );
770 } else {
771 $status = new Status\OkStatus();
772 $status->setTitle('PHP suhosin.post.max_name_length ok');
773 }
774 } else {
775 $status = new Status\InfoStatus();
776 $status->setTitle('Suhosin not loaded');
777 $status->setMessage(
778 'If enabling suhosin, suhosin.post.max_name_length' .
779 ' should be set to at least ' . $recommendedPostMaxNameLength . ':' . LF .
780 'suhosin.post.max_name_length=' . $recommendedPostMaxNameLength
781 );
782 }
783 return $status;
784 }
785
786 /**
787 * Check suhosin.post.max_vars
788 *
789 * @return Status\StatusInterface
790 */
791 protected function checkSuhosinPostMaxVars() {
792 $recommendedPostMaxVars = 400;
793 if ($this->isSuhosinLoadedAndActive()) {
794 $currentPostMaxVars = ini_get('suhosin.post.max_vars');
795 if ($currentPostMaxVars < $recommendedPostMaxVars) {
796 $status = new Status\ErrorStatus();
797 $status->setTitle('PHP suhosin.post.max_vars too low');
798 $status->setMessage(
799 'suhosin.post.max_vars=' . $currentPostMaxVars . LF .
800 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
801 ' (as the install tool does). It is highly recommended to raise this' .
802 ' to at least ' . $recommendedPostMaxVars . ':' . LF .
803 'suhosin.post.max_vars=' . $recommendedPostMaxVars
804 );
805 } else {
806 $status = new Status\OkStatus();
807 $status->setTitle('PHP suhosin.post.max_vars ok');
808 }
809 } else {
810 $status = new Status\InfoStatus();
811 $status->setTitle('Suhosin not loaded');
812 $status->setMessage(
813 'If enabling suhosin, suhosin.post.max_vars' .
814 ' should be set to at least ' . $recommendedPostMaxVars . ':' . LF .
815 'suhosin.post.max_vars=' . $recommendedPostMaxVars
816 );
817 }
818 return $status;
819 }
820
821 /**
822 * Check suhosin.get.max_value_length
823 *
824 * @return Status\StatusInterface
825 */
826 protected function checkSuhosinGetMaxValueLength() {
827 $recommendedGetMaxValueLength = 2000;
828 if ($this->isSuhosinLoadedAndActive()) {
829 $currentGetMaxValueLength = ini_get('suhosin.get.max_value_length');
830 if ($currentGetMaxValueLength < $recommendedGetMaxValueLength) {
831 $status = new Status\ErrorStatus();
832 $status->setTitle('PHP suhosin.get.max_value_length too low');
833 $status->setMessage(
834 'suhosin.get.max_value_length=' . $currentGetMaxValueLength . LF .
835 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
836 ' (as the install tool does). It is highly recommended to raise this' .
837 ' to at least ' . $recommendedGetMaxValueLength . ':' . LF .
838 'suhosin.get.max_value_length=' . $recommendedGetMaxValueLength
839 );
840 } else {
841 $status = new Status\OkStatus();
842 $status->setTitle('PHP suhosin.get.max_value_length ok');
843 }
844 } else {
845 $status = new Status\InfoStatus();
846 $status->setTitle('Suhosin not loaded');
847 $status->setMessage(
848 'If enabling suhosin, suhosin.get.max_value_length' .
849 ' should be set to at least ' . $recommendedGetMaxValueLength . ':' . LF .
850 'suhosin.get.max_value_length=' . $recommendedGetMaxValueLength
851 );
852 }
853 return $status;
854 }
855
856 /**
857 * Check suhosin.get.max_name_length
858 *
859 * @return Status\StatusInterface
860 */
861 protected function checkSuhosinGetMaxNameLength() {
862 $recommendedGetMaxNameLength = 200;
863 if ($this->isSuhosinLoadedAndActive()) {
864 $currentGetMaxNameLength = ini_get('suhosin.get.max_name_length');
865 if ($currentGetMaxNameLength < $recommendedGetMaxNameLength) {
866 $status = new Status\ErrorStatus();
867 $status->setTitle('PHP suhosin.get.max_name_length too low');
868 $status->setMessage(
869 'suhosin.get.max_name_length=' . $currentGetMaxNameLength . LF .
870 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS' .
871 ' (as the install tool does). It is highly recommended to raise this' .
872 ' to at least ' . $recommendedGetMaxNameLength . ':' . LF .
873 'suhosin.get.max_name_length=' . $recommendedGetMaxNameLength
874 );
875 } else {
876 $status = new Status\OkStatus();
877 $status->setTitle('PHP suhosin.get.max_name_length ok');
878 }
879 } else {
880 $status = new Status\InfoStatus();
881 $status->setTitle('Suhosin not loaded');
882 $status->setMessage(
883 'If enabling suhosin, suhosin.get.max_name_length' .
884 ' should be set to at least ' . $recommendedGetMaxNameLength . ':' . LF .
885 'suhosin.get.max_name_length=' . $recommendedGetMaxNameLength
886 );
887 }
888 return $status;
889 }
890
891 /**
892 * Check suhosin.executor.include.whitelist contains phar
893 *
894 * @return Status\StatusInterface
895 */
896 protected function checkSuhosinExecutorIncludeWhiteListContainsPhar() {
897 if ($this->isSuhosinLoadedAndActive()) {
898 $whitelist = (string)ini_get('suhosin.executor.include.whitelist');
899 if (strpos($whitelist, 'phar') === FALSE) {
900 $status = new Status\NoticeStatus();
901 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain phar');
902 $status->setMessage(
903 'suhosin.executor.include.whitelist= ' . $whitelist . LF .
904 '"phar" is currently not a hard requirement of TYPO3 CMS but is nice to have and a possible' .
905 ' requirement in future versions. A useful setting is:' . LF .
906 'suhosin.executor.include.whitelist=phar,vfs'
907 );
908 } else {
909 $status = new Status\OkStatus();
910 $status->setTitle('PHP suhosin.executor.include.whitelist contains phar');
911 }
912 } else {
913 $status = new Status\InfoStatus();
914 $status->setTitle('Suhosin not loaded');
915 $status->setMessage(
916 'If enabling suhosin, a useful setting is:' . LF .
917 'suhosin.executor.include.whitelist=phar,vfs'
918 );
919 }
920 return $status;
921 }
922
923 /**
924 * Check suhosin.executor.include.whitelist contains vfs
925 *
926 * @return Status\StatusInterface
927 */
928 protected function checkSuhosinExecutorIncludeWhiteListContainsVfs() {
929 if ($this->isSuhosinLoadedAndActive()) {
930 $whitelist = (string)ini_get('suhosin.executor.include.whitelist');
931 if (strpos($whitelist, 'vfs') === FALSE) {
932 $status = new Status\WarningStatus();
933 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain vfs');
934 $status->setMessage(
935 'suhosin.executor.include.whitelist= ' . $whitelist . LF .
936 '"vfs" is currently not a hard requirement of TYPO3 CMS but tons of unit tests rely on it.' .
937 ' Furthermore, vfs will likely be a base for an additional compatibility layer in the future.' .
938 ' A useful setting is:' . LF .
939 'suhosin.executor.include.whitelist=phar,vfs'
940 );
941 } else {
942 $status = new Status\OkStatus();
943 $status->setTitle('PHP suhosin.executor.include.whitelist contains vfs');
944 }
945 } else {
946 $status = new Status\InfoStatus();
947 $status->setTitle('Suhosin not loaded');
948 $status->setMessage(
949 'If enabling suhosin, a useful setting is:' . LF .
950 'suhosin.executor.include.whitelist=phar,vfs'
951 );
952 }
953 return $status;
954 }
955
956 /**
957 * Check if some opcode cache is loaded
958 *
959 * @return Status\StatusInterface
960 */
961 protected function checkSomePhpOpcodeCacheIsLoaded() {
962 // Link to our wiki page, so we can update opcode cache issue information independent of TYPO3 CMS releases.
963 $wikiLink = 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.';
964 $opcodeCaches = GeneralUtility::makeInstance(OpcodeCacheService::class)->getAllActive();
965 if (empty($opcodeCaches)) {
966 // Set status to notice. It needs to be notice so email won't be triggered.
967 $status = new Status\NoticeStatus();
968 $status->setTitle('No PHP opcode cache loaded');
969 $status->setMessage(
970 'PHP opcode caches hold a compiled version of executed PHP scripts in' .
971 ' memory and do not require to recompile a script each time it is accessed.' .
972 ' This can be a massive performance improvement and can reduce the load on a' .
973 ' server in general. A parse time reduction by factor three for fully cached' .
974 ' pages can be achieved easily if using an opcode cache.' .
975 LF . $wikiLink
976 );
977 } else {
978 $status = new Status\OkStatus();
979 $message = '';
980
981 foreach ($opcodeCaches as $opcodeCache => $properties) {
982 $message .= 'Name: ' . $opcodeCache . ' Version: ' . $properties['version'];
983 $message .= LF;
984
985 if ($properties['error']) {
986 // Set status to error if not already set
987 if ($status->getSeverity() !== 'error') {
988 $status = new Status\ErrorStatus();
989 }
990 $message .= ' This opcode cache is marked as malfunctioning by the TYPO3 CMS Team.';
991 } elseif ($properties['canInvalidate']) {
992 $message .= ' This opcode cache should work correctly and has good performance.';
993 } else {
994 // Set status to notice if not already error set. It needs to be notice so email won't be triggered.
995 if ($status->getSeverity() !== 'error' || $status->getSeverity() !== 'warning') {
996 $status = new Status\NoticeStatus();
997 }
998 $message .= ' This opcode cache may work correctly but has medium performance.';
999 }
1000 $message .= LF;
1001 }
1002
1003 $message .= $wikiLink;
1004
1005 // Set title of status depending on serverity
1006 switch ($status->getSeverity()) {
1007 case 'error':
1008 $status->setTitle('A possibly malfunctioning PHP opcode cache is loaded');
1009 break;
1010 case 'warning':
1011 $status->setTitle('A PHP opcode cache is loaded which may cause problems');
1012 break;
1013 case 'ok':
1014 default:
1015 $status->setTitle('A PHP opcode cache is loaded');
1016 break;
1017 }
1018 $status->setMessage($message);
1019 }
1020 return $status;
1021 }
1022
1023 /**
1024 * Check doc comments can be fetched by reflection
1025 *
1026 * @return Status\StatusInterface
1027 */
1028 protected function checkReflectionDocComment() {
1029 $testReflection = new \ReflectionMethod(get_class($this), __FUNCTION__);
1030 if ($testReflection->getDocComment() === FALSE) {
1031 $status = new Status\AlertStatus();
1032 $status->setTitle('PHP Doc comment reflection broken');
1033 $status->setMessage(
1034 'TYPO3 CMS core extensions like extbase and fluid heavily rely on method'
1035 . ' comment parsing to fetch annotations and add magic belonging to them.'
1036 . ' This does not work in the current environment and so we cannot install'
1037 . ' TYPO3 CMS.' . LF
1038 . ' Here are some possibilities: ' . LF
1039 . '* In Zend OPcache you can disable saving/loading comments. If you are using'
1040 . ' Zend OPcache (included since PHP 5.5) then check your php.ini settings for'
1041 . ' opcache.save_comments and opcache.load_comments and enable them.' . LF
1042 . '* In Zend Optimizer+ you can disable saving comments. If you are using'
1043 . ' Zend Optimizer+ then check your php.ini settings for'
1044 . ' zend_optimizerplus.save_comments and enable it.' . LF
1045 . '* The PHP extension eaccelerator is known to break this if'
1046 . ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.'
1047 . ' This compile flag must be specified, otherwise TYPO3 CMS will not work.' . LF
1048 . 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.'
1049 );
1050 } else {
1051 $status = new Status\OkStatus();
1052 $status->setTitle('PHP Doc comment reflection works');
1053 }
1054 return $status;
1055 }
1056
1057 /**
1058 * Check if systemLocale setting is correct (locale exists in the OS)
1059 *
1060 * @return Status\StatusInterface
1061 */
1062 protected function checkSystemLocale() {
1063
1064 $currentLocale = setlocale(LC_CTYPE, 0);
1065
1066 // On Windows an empty locale value uses the regional settings from the Control Panel
1067 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
1068 $status = new Status\InfoStatus();
1069 $status->setTitle('Empty systemLocale setting');
1070 $status->setMessage(
1071 '$GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is not set. This is fine as long as no UTF-8' .
1072 ' file system is used.'
1073 );
1074 } elseif (setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']) === FALSE) {
1075 $status = new Status\ErrorStatus();
1076 $status->setTitle('Incorrect systemLocale setting');
1077 $status->setMessage(
1078 'Current value of the $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is incorrect. A locale with' .
1079 ' this name doesn\'t exist in the operating system.'
1080 );
1081 setlocale(LC_CTYPE, $currentLocale);
1082 } else {
1083 $status = new Status\OkStatus();
1084 $status->setTitle('System locale is correct');
1085 }
1086
1087 return $status;
1088 }
1089
1090 /**
1091 * Checks whether we can use file names with UTF-8 characters.
1092 * Configured system locale must support UTF-8 when UTF8filesystem is set
1093 *
1094 * @return Status\StatusInterface
1095 */
1096 protected function checkLocaleWithUTF8filesystem() {
1097
1098 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
1099
1100 // On Windows an empty local value uses the regional settings from the Control Panel
1101 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && TYPO3_OS !== 'WIN') {
1102 $status = new Status\ErrorStatus();
1103 $status->setTitle('System locale not set on UTF-8 file system');
1104 $status->setMessage(
1105 '$GLOBALS[TYPO3_CONF_VARS][SYS][UTF8filesystem] is set, but $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale]' .
1106 ' is empty. Make sure a valid locale which supports UTF-8 is set.'
1107 );
1108 } else {
1109 $testString = 'ÖöĄĆŻĘĆćążąęó.jpg';
1110 $currentLocale = setlocale(LC_CTYPE, 0);
1111 $quote = TYPO3_OS === 'WIN' ? '"' : '\'';
1112
1113 setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
1114
1115 if (escapeshellarg($testString) === $quote . $testString . $quote) {
1116 $status = new Status\OkStatus();
1117 $status->setTitle('File names with UTF-8 characters can be used.');
1118 } else {
1119 $status = new Status\ErrorStatus();
1120 $status->setTitle('System locale setting doesn\'t support UTF-8 file names.');
1121 $status->setMessage(
1122 'Please check your $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] setting.'
1123 );
1124 }
1125
1126 setlocale(LC_CTYPE, $currentLocale);
1127 }
1128
1129
1130 } else {
1131 $status = new Status\OkStatus();
1132 $status->setTitle('Skipping test, as UTF8filesystem is not enabled.');
1133 }
1134
1135 return $status;
1136 }
1137
1138 /**
1139 * Checks thread stack size if on windows with apache
1140 *
1141 * @return Status\StatusInterface
1142 */
1143 protected function checkWindowsApacheThreadStackSize() {
1144 if (
1145 $this->isWindowsOs()
1146 && substr($_SERVER['SERVER_SOFTWARE'], 0, 6) === 'Apache'
1147 ) {
1148 $status = new Status\WarningStatus();
1149 $status->setTitle('Windows apache thread stack size');
1150 $status->setMessage(
1151 'This current value cannot be checked by the system, so please ignore this warning if it' .
1152 ' is already taken care of: Fluid uses complex regular expressions which require a lot' .
1153 ' of stack space during the first processing.' .
1154 ' On Windows the default stack size for Apache is a lot smaller than on UNIX.' .
1155 ' You can increase the size to 8MB (default on UNIX) by adding the following configuration' .
1156 ' to httpd.conf and restarting Apache afterwards:' . LF .
1157 '<IfModule mpm_winnt_module>' . LF .
1158 'ThreadStackSize 8388608' . LF .
1159 '</IfModule>'
1160 );
1161 } else {
1162 $status = new Status\OkStatus();
1163 $status->setTitle('Apache ThreadStackSize is not an issue on UNIX systems');
1164 }
1165 return $status;
1166 }
1167
1168 /**
1169 * Check if a specific required PHP extension is loaded
1170 *
1171 * @param string $extension
1172 * @return Status\StatusInterface
1173 */
1174 protected function checkRequiredPhpExtension($extension) {
1175 if (!extension_loaded($extension)) {
1176 $status = new Status\ErrorStatus();
1177 $status->setTitle('PHP extension ' . $extension . ' not loaded');
1178 $status->setMessage(
1179 'TYPO3 CMS uses PHP extension ' . $extension . ' but it is not loaded' .
1180 ' in your environment. Change your environment to provide this extension.'
1181 );
1182 } else {
1183 $status = new Status\OkStatus();
1184 $status->setTitle('PHP extension ' . $extension . ' loaded');
1185 }
1186 return $status;
1187 }
1188
1189 /**
1190 * Check imagecreatetruecolor to verify gdlib works as expected
1191 *
1192 * @return Status\StatusInterface
1193 */
1194 protected function checkGdLibTrueColorSupport() {
1195 if (function_exists('imagecreatetruecolor')) {
1196 $imageResource = @imagecreatetruecolor(50, 100);
1197 if (is_resource($imageResource)) {
1198 imagedestroy($imageResource);
1199 $status = new Status\OkStatus();
1200 $status->setTitle('PHP GD library true color works');
1201 } else {
1202 $status = new Status\ErrorStatus();
1203 $status->setTitle('PHP GD library true color support broken');
1204 $status->setMessage(
1205 'GD is loaded, but calling imagecreatetruecolor() fails.' .
1206 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
1207 );
1208 }
1209 } else {
1210 $status = new Status\ErrorStatus();
1211 $status->setTitle('PHP GD library true color support missing');
1212 $status->setMessage(
1213 'Gdlib is essential for TYPO3 CMS to work properly.'
1214 );
1215 }
1216 return $status;
1217 }
1218
1219 /**
1220 * Check gif support of GD library
1221 *
1222 * @return Status\StatusInterface
1223 */
1224 protected function checkGdLibGifSupport() {
1225 if (
1226 function_exists('imagecreatefromgif')
1227 && function_exists('imagegif')
1228 && (imagetypes() & IMG_GIF)
1229 ) {
1230 $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif');
1231 if (is_resource($imageResource)) {
1232 imagedestroy($imageResource);
1233 $status = new Status\OkStatus();
1234 $status->setTitle('PHP GD library has gif support');
1235 } else {
1236 $status = new Status\ErrorStatus();
1237 $status->setTitle('PHP GD library gif support broken');
1238 $status->setMessage(
1239 'GD is loaded, but calling imagecreatefromgif() fails.' .
1240 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
1241 );
1242 }
1243 } else {
1244 $status = new Status\ErrorStatus();
1245 $status->setTitle('PHP GD library gif support missing');
1246 $status->setMessage(
1247 'GD must be compiled with gif support. This is essential for' .
1248 ' TYPO3 CMS to work properly.'
1249 );
1250 }
1251 return $status;
1252 }
1253
1254 /**
1255 * Check jgp support of GD library
1256 *
1257 * @return Status\StatusInterface
1258 */
1259 protected function checkGdLibJpgSupport() {
1260 if (
1261 function_exists('imagecreatefromjpeg')
1262 && function_exists('imagejpeg')
1263 && (imagetypes() & IMG_JPG)
1264 ) {
1265 $status = new Status\OkStatus();
1266 $status->setTitle('PHP GD library has jpg support');
1267 } else {
1268 $status = new Status\ErrorStatus();
1269 $status->setTitle('PHP GD library jpg support missing');
1270 $status->setMessage(
1271 'GD must be compiled with jpg support. This is essential for' .
1272 ' TYPO3 CMS to work properly.'
1273 );
1274 }
1275 return $status;
1276 }
1277
1278 /**
1279 * Check png support of GD library
1280 *
1281 * @return Status\StatusInterface
1282 */
1283 protected function checkGdLibPngSupport() {
1284 if (
1285 function_exists('imagecreatefrompng')
1286 && function_exists('imagepng')
1287 && (imagetypes() & IMG_PNG)
1288 ) {
1289 $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png');
1290 if (is_resource($imageResource)) {
1291 imagedestroy($imageResource);
1292 $status = new Status\OkStatus();
1293 $status->setTitle('PHP GD library has png support');
1294 } else {
1295 $status = new Status\ErrorStatus();
1296 $status->setTitle('PHP GD library png support broken');
1297 $status->setMessage(
1298 'GD is compiled with png support, but calling imagecreatefrompng() fails.' .
1299 ' Check your environment and fix it, png in GD lib is important' .
1300 ' for TYPO3 CMS to work properly.'
1301 );
1302 }
1303 } else {
1304 $status = new Status\ErrorStatus();
1305 $status->setTitle('PHP GD library png support missing');
1306 $status->setMessage(
1307 'GD must be compiled with png support. This is essential for' .
1308 ' TYPO3 CMS to work properly'
1309 );
1310 }
1311 return $status;
1312 }
1313
1314 /**
1315 * Check gdlib supports freetype
1316 *
1317 * @return Status\StatusInterface
1318 */
1319 protected function checkGdLibFreeTypeSupport() {
1320 if (function_exists('imagettftext')) {
1321 $status = new Status\OkStatus();
1322 $status->setTitle('PHP GD library has freetype font support');
1323 $status->setMessage(
1324 'There is a difference between the font size setting which the GD' .
1325 ' library should be supplied with. If installation is completed' .
1326 ' a test in the install tool helps to find out the value you need.'
1327 );
1328 } else {
1329 $status = new Status\ErrorStatus();
1330 $status->setTitle('PHP GD library freetype support missing');
1331 $status->setMessage(
1332 'Some core functionality and extension rely on the GD' .
1333 ' to render fonts on images. This support is missing' .
1334 ' in your environment. Install it.'
1335 );
1336 }
1337 return $status;
1338 }
1339
1340 /**
1341 * Create true type font test image
1342 *
1343 * @return Status\StatusInterface
1344 */
1345 protected function isTrueTypeFontWorking() {
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 );
1363 } else {
1364 $status = new Status\NoticeStatus();
1365 $status->setTitle('FreeType True Type Font DPI');
1366 $status->setMessage('Fonts are rendered by FreeType library. ' .
1367 'This server does not render fonts as expected. ' .
1368 'Please check your FreeType 2 module.'
1369 );
1370 }
1371 } else {
1372 $status = new Status\ErrorStatus();
1373 $status->setTitle('PHP GD library freetype2 support missing');
1374 $status->setMessage(
1375 'The core relies on GD library compiled into PHP with freetype2' .
1376 ' support. This is missing on your system. Please install it.'
1377 );
1378 }
1379
1380 return $status;
1381 }
1382
1383 /**
1384 * Check register globals
1385 *
1386 * @return Status\StatusInterface
1387 */
1388 protected function checkRegisterGlobals() {
1389 $registerGlobalsEnabled = filter_var(
1390 ini_get('register_globals'),
1391 FILTER_VALIDATE_BOOLEAN,
1392 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
1393 );
1394 if ($registerGlobalsEnabled === TRUE) {
1395 $status = new Status\ErrorStatus();
1396 $status->setTitle('PHP register globals on');
1397 $status->setMessage(
1398 'register_globals=' . ini_get('register_globals') . LF .
1399 'TYPO3 requires PHP setting "register_globals" set to off.' .
1400 ' This ancient PHP setting is a big security problem and should' .
1401 ' never be enabled:' . LF .
1402 'register_globals=Off'
1403 );
1404 } else {
1405 $status = new Status\OkStatus();
1406 $status->setTitle('PHP register globals off');
1407 }
1408 return $status;
1409 }
1410
1411 /**
1412 * Check for bug in libxml
1413 *
1414 * @return Status\StatusInterface
1415 */
1416 protected function checkLibXmlBug() {
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 return filter_var($ip, FILTER_VALIDATE_IP) !== FALSE;
1450 }
1451
1452 /**
1453 * Test if this instance runs on windows OS
1454 *
1455 * @return bool TRUE if operating system is windows
1456 */
1457 protected function isWindowsOs() {
1458 $windowsOs = FALSE;
1459 if (!stristr(PHP_OS, 'darwin') && stristr(PHP_OS, 'win')) {
1460 $windowsOs = TRUE;
1461 }
1462 return $windowsOs;
1463 }
1464
1465 /**
1466 * Helper method to find out if suhosin extension is loaded
1467 *
1468 * @return bool TRUE if suhosin PHP extension is loaded
1469 */
1470 protected function isSuhosinLoadedAndActive() {
1471 $suhosinLoaded = FALSE;
1472 if (extension_loaded('suhosin')) {
1473 $suhosinInSimulationMode = filter_var(
1474 ini_get('suhosin.simulation'),
1475 FILTER_VALIDATE_BOOLEAN,
1476 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
1477 );
1478 if (!$suhosinInSimulationMode) {
1479 $suhosinLoaded = TRUE;
1480 }
1481 }
1482 return $suhosinLoaded;
1483 }
1484
1485 /**
1486 * Helper method to explode a string by delimiter and throw away empty values.
1487 * Removes empty values from result array.
1488 *
1489 * @param string $delimiter Delimiter string to explode with
1490 * @param string $string The string to explode
1491 * @return array Exploded values
1492 */
1493 protected function trimExplode($delimiter, $string) {
1494 $explodedValues = explode($delimiter, $string);
1495 $resultWithPossibleEmptyValues = array_map('trim', $explodedValues);
1496 $result = array();
1497 foreach ($resultWithPossibleEmptyValues as $value) {
1498 if ($value !== '') {
1499 $result[] = $value;
1500 }
1501 }
1502 return $result;
1503 }
1504
1505 /**
1506 * Helper method to get the bytes value from a measurement string like "100k".
1507 *
1508 * @param string $measurement The measurement (e.g. "100k")
1509 * @return int The bytes value (e.g. 102400)
1510 */
1511 protected function getBytesFromSizeMeasurement($measurement) {
1512 $bytes = doubleval($measurement);
1513 if (stripos($measurement, 'G')) {
1514 $bytes *= 1024 * 1024 * 1024;
1515 } elseif (stripos($measurement, 'M')) {
1516 $bytes *= 1024 * 1024;
1517 } elseif (stripos($measurement, 'K')) {
1518 $bytes *= 1024;
1519 }
1520 return (int)$bytes;
1521 }
1522
1523 }