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