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