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