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