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