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