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