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