9079c0270461517c851648a59b201edbc0fd6ac3
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / SystemEnvironment / Check.php
1 <?php
2 namespace TYPO3\CMS\Install\SystemEnvironment;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Christian Kuhn <lolli@schwarzbu.ch>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Install\Status;
28
29 /**
30 * Check system environment status
31 *
32 * This class is a hardcoded requirement check of the underlying
33 * server and PHP system.
34 *
35 * The class *must not* check for any TYPO3 specific things like
36 * specific configuration values or directories. It should not fail
37 * if there is no TYPO3 at all.
38 *
39 * The only core code used is the class loader
40 *
41 * This class is instantiated as the *very first* class during
42 * installation. It is meant to be *standalone* und must not have
43 * any requirements, except the status classes. It must be possible
44 * to run this script separated from the rest of the core, without
45 * dependencies.
46 *
47 * This means especially:
48 * * No hooks or anything like that
49 * * No usage of *any* TYPO3 code like GeneralUtility
50 * * No require of anything but the status classes
51 * * No localization
52 *
53 * The status messages and title *must not* include HTML, use plain
54 * text only. The return values of this class are not bound to HTML
55 * and can be used in different scopes (eg. as json array).
56 *
57 * @author Christian Kuhn <lolli@schwarzbu.ch>
58 */
59 class Check {
60
61 /**
62 * @var array List of required PHP extensions
63 */
64 protected $requiredPhpExtensions = array(
65 'fileinfo',
66 'filter',
67 'gd',
68 'hash',
69 'json',
70 'mysqli',
71 'openssl',
72 'pcre',
73 'session',
74 'soap',
75 'SPL',
76 'standard',
77 'xml',
78 'zip',
79 'zlib',
80 );
81
82 /**
83 * Get all status information as array with status objects
84 *
85 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
86 */
87 public function getStatus() {
88 $statusArray = array();
89 $statusArray[] = $this->checkCurrentDirectoryIsInIncludePath();
90 $statusArray[] = $this->checkFileUploadEnabled();
91 $statusArray[] = $this->checkMaximumFileUploadSize();
92 $statusArray[] = $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
93 $statusArray[] = $this->checkMemorySettings();
94 $statusArray[] = $this->checkPhpVersion();
95 $statusArray[] = $this->checkMaxExecutionTime();
96 $statusArray[] = $this->checkDisableFunctions();
97 $statusArray[] = $this->checkSafeMode();
98 $statusArray[] = $this->checkDocRoot();
99 $statusArray[] = $this->checkOpenBaseDir();
100 $statusArray[] = $this->checkXdebugMaxNestingLevel();
101 $statusArray[] = $this->checkOpenSslInstalled();
102 $statusArray[] = $this->checkSuhosinLoaded();
103 $statusArray[] = $this->checkSuhosinRequestMaxVars();
104 $statusArray[] = $this->checkSuhosinPostMaxVars();
105 $statusArray[] = $this->checkSuhosinGetMaxValueLength();
106 $statusArray[] = $this->checkSuhosinExecutorIncludeWhitelistContainsPhar();
107 $statusArray[] = $this->checkSuhosinExecutorIncludeWhitelistContainsVfs();
108 $statusArray[] = $this->checkSomePhpOpcodeCacheIsLoaded();
109 $statusArray[] = $this->checkReflectionDocComment();
110 $statusArray[] = $this->checkWindowsApacheThreadStackSize();
111 foreach ($this->requiredPhpExtensions as $extension) {
112 $statusArray[] = $this->checkRequiredPhpExtension($extension);
113 }
114 $statusArray[] = $this->checkGdLibTrueColorSupport();
115 $statusArray[] = $this->checkGdLibGifSupport();
116 $statusArray[] = $this->checkGdLibJpgSupport();
117 $statusArray[] = $this->checkGdLibPngSupport();
118 $statusArray[] = $this->checkGdLibFreeTypeSupport();
119 $statusArray[] = $this->checkPhpMagicQuotes();
120 $statusArray[] = $this->checkRegisterGlobals();
121 $statusArray[] = $this->isTrueTypeFontDpiStandard();
122 return $statusArray;
123 }
124
125 /**
126 * Checks if current directory (.) is in PHP include path
127 *
128 * @return Status\StatusInterface
129 */
130 protected function checkCurrentDirectoryIsInIncludePath() {
131 $includePath = ini_get('include_path');
132 $delimiter = $this->isWindowsOs() ? ';' : ':';
133 $pathArray = $this->trimExplode($delimiter, $includePath);
134 if (!in_array('.', $pathArray)) {
135 $status = new Status\WarningStatus();
136 $status->setTitle('Current directory (./) is not in include path');
137 $status->setMessage(
138 'include_path = ' . implode(' ', $pathArray) .
139 ' Normally the current path, \'.\', is included in the' .
140 ' include_path of PHP. Although TYPO3 does not rely on this,' .
141 ' it is an unusual setting that may introduce problems for' .
142 ' some extensions.'
143 );
144 } else {
145 $status = new Status\OkStatus();
146 $status->setTitle('Current directory (./) is in include path.');
147 }
148 return $status;
149 }
150
151 /**
152 * Check if file uploads are enabled in PHP
153 *
154 * @return Status\StatusInterface
155 */
156 protected function checkFileUploadEnabled() {
157 if (!ini_get('file_uploads')) {
158 $status = new Status\ErrorStatus();
159 $status->setTitle('File uploads not allowed');
160 $status->setMessage(
161 'file_uploads=' . ini_get('file_uploads') .
162 ' TYPO3 uses the ability to upload files from the browser in various cases.' .
163 ' As long as this flag is disabled, you\'ll not be able to upload files.' .
164 ' But it doesn\'t end here, because not only are files not accepted by' .
165 ' the server - ALL content in the forms are discarded and therefore' .
166 ' nothing at all will be editable if you don\'t set this flag!' .
167 ' However if you cannot enable fileupload for some reason alternatively' .
168 ' you change the default form encoding value with \\$TYPO3_CONF_VARS[SYS][form_enctype].'
169 );
170 } else {
171 $status = new Status\OkStatus();
172 $status->setTitle('File uploads allowed');
173 }
174 return $status;
175 }
176
177 /**
178 * Check maximum file upload size against default value of 10MB
179 *
180 * @return Status\StatusInterface
181 */
182 protected function checkMaximumFileUploadSize() {
183 $maximumUploadFilesize = $this->getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
184 if ($maximumUploadFilesize < 1024 * 1024 * 10) {
185 $status = new Status\ErrorStatus();
186 $status->setTitle('Maximum upload filesize too small');
187 $status->setMessage(
188 'upload_max_filesize=' . ini_get('upload_max_filesize') .
189 '. By default TYPO3 supports uploading, copying and moving' .
190 ' files of sizes up to 10MB (you can alter the TYPO3 defaults' .
191 ' by the config option TYPO3_CONF_VARS[BE][maxFileSize]).' .
192 ' Your current value is below this, so at this point, PHP sets' .
193 ' the limits for uploaded filesizes and not TYPO3.'
194 );
195 } else {
196 $status = new Status\OkStatus();
197 $status->setTitle('Maximum file upload size is higher or equal to 10MB');
198 }
199 return $status;
200 }
201
202 /**
203 * Check maximum post upload size correlates with maximum file upload
204 *
205 * @return Status\StatusInterface
206 */
207 protected function checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize() {
208 $maximumUploadFilesize = $this->getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
209 $maximumPostSize = $this->getBytesFromSizeMeasurement(ini_get('post_max_size'));
210 if ($maximumPostSize < $maximumUploadFilesize) {
211 $status = new Status\ErrorStatus();
212 $status->setTitle('Maximum size for POST requests is smaller than max. upload filesize');
213 $status->setMessage(
214 'upload_max_filesize=' . ini_get('upload_max_filesize') .
215 ', post_max_size=' . ini_get('post_max_size') .
216 ' You have defined a maximum size for file uploads which' .
217 ' exceeds the allowed size for POST requests. Therefore the' .
218 ' file uploads can not be larger than ' . ini_get('post_max_size') . '.'
219 );
220 } else {
221 $status = new Status\OkStatus();
222 $status->setTitle('Maximum post upload size correlates with maximum upload file size');
223 }
224 return $status;
225 }
226
227 /**
228 * Check memory settings
229 *
230 * @return Status\StatusInterface
231 */
232 protected function checkMemorySettings() {
233 $memoryLimit = $this->getBytesFromSizeMeasurement(ini_get('memory_limit'));
234 if ($memoryLimit <= 0) {
235 $status = new Status\WarningStatus();
236 $status->setTitle('Unlimited memory limit!');
237 $status->setMessage(
238 'Your webserver is configured to not limit PHP memory usage at all. This is a risk' .
239 ' and should be avoided in production setup. In general it\'s best practice to limit this' .
240 ' in the configuration of your webserver. To be safe, ask the system administrator of the' .
241 ' webserver to raise the limit to something over 64MB'
242 );
243 } elseif ($memoryLimit < 1024 * 1024 * 32) {
244 $status = new Status\ErrorStatus();
245 $status->setTitle('Memory limit below 32MB');
246 $status->setMessage(
247 'memory_limit=' . ini_get('memory_limit') .
248 ' Your system is configured to enforce a memory limit of PHP scripts lower than 32MB.' .
249 ' There is nothing else to do than raise the limit. To be safe, ask the system' .
250 ' administrator of the webserver to raise the limit to 64MB.'
251 );
252 } elseif ($memoryLimit < 1024 * 1024 * 64) {
253 $status = new Status\WarningStatus();
254 $status->setTitle('Memory limit below 64MB');
255 $status->setMessage(
256 'memory_limit=' . ini_get('memory_limit') .
257 ' Your system is configured to enforce a memory limit of PHP scripts lower than 64MB.' .
258 ' A slim TYPO3 instance without many extensions will probably work, but you should ' .
259 ' monitor your system for exhausted messages, especially if using the backend. ' .
260 ' To be on the safe side, it would be better to raise the PHP memory limit to 64MB or more.'
261 );
262 } else {
263 $status = new Status\OkStatus();
264 $status->setTitle('Memory limit equal 64MB or more');
265 }
266 return $status;
267 }
268
269 /**
270 * Check minimum PHP version
271 *
272 * @return Status\StatusInterface
273 */
274 protected function checkPhpVersion() {
275 $minimumPhpVersion = '5.3.7';
276 $currentPhpVersion = phpversion();
277 if (version_compare($currentPhpVersion, $minimumPhpVersion) < 0) {
278 $status = new Status\ErrorStatus();
279 $status->setTitle('PHP version too low');
280 $status->setMessage(
281 'Your PHP version ' . $currentPhpVersion . ' is too old. TYPO3 CMS does not run' .
282 ' with this version. Update to at least PHP ' . $minimumPhpVersion
283 );
284 } else {
285 $status = new Status\OkStatus();
286 $status->setTitle('PHP version is fine');
287 }
288 return $status;
289 }
290
291 /**
292 * Check maximum execution time
293 *
294 * @return Status\StatusInterface
295 */
296 protected function checkMaxExecutionTime() {
297 $minimumMaximumExecutionTime = 30;
298 $recommendedMaximumExecutionTime = 240;
299 $currentMaximumExecutionTime = ini_get('max_execution_time');
300 if ($currentMaximumExecutionTime == 0) {
301 if (PHP_SAPI === 'cli') {
302 $status = new Status\OkStatus();
303 $status->setTitle('Infinite PHP script execution time');
304 $status->setMessage(
305 'Maximum PHP script execution time is always set to infinite (0) in cli mode.' .
306 ' The setting used for web requests can not be checked from command line.'
307 );
308 } else {
309 $status = new Status\WarningStatus();
310 $status->setTitle('Infinite PHP script execution time');
311 $status->setMessage(
312 'Your max_execution_time is set to 0 (infinite). While TYPO3 is fine' .
313 ' with this, you risk a denial-of-service of your system if for whatever' .
314 ' reason some script hangs in an infinite loop. You are usually on safe side ' .
315 ' if max_execution_time is reduced to ' . $recommendedMaximumExecutionTime
316 );
317 }
318 } elseif ($currentMaximumExecutionTime < $minimumMaximumExecutionTime) {
319 $status = new Status\ErrorStatus();
320 $status->setTitle('Low PHP script execution time');
321 $status->setMessage(
322 'Your max_execution_time is set to ' . $currentMaximumExecutionTime .
323 '. Some expensive operation in TYPO3 can take longer than that. It is advised' .
324 ' to raise max_execution_time to ' . $recommendedMaximumExecutionTime
325 );
326 } elseif ($currentMaximumExecutionTime < $recommendedMaximumExecutionTime) {
327 $status = new Status\WarningStatus();
328 $status->setTitle('Low PHP script execution time');
329 $status->setMessage(
330 'Your max_execution_time is set to ' . $currentMaximumExecutionTime .
331 '. While TYPO3 often runs without problems with ' . $minimumMaximumExecutionTime .
332 ' it still may happen that script execution is stopped before finishing' .
333 ' calculations. You should monitor the system for messages in this area' .
334 ' and maybe raise the limit to ' . $recommendedMaximumExecutionTime . '.'
335 );
336 } else {
337 $status = new Status\OkStatus();
338 $status->setTitle('Maximum PHP script execution time equals ' . $recommendedMaximumExecutionTime . ' or more');
339 }
340 return $status;
341 }
342
343 /**
344 * Check for disabled functions
345 *
346 * @return Status\StatusInterface
347 */
348 protected function checkDisableFunctions() {
349 $disabledFunctions = trim(ini_get('disable_functions'));
350
351 // Filter "disable_functions"
352 $disabledFunctionsArray = $this->trimExplode(',', $disabledFunctions);
353
354 // Array with strings to find
355 $findStrings = array(
356 // Disabled by default on Ubuntu OS but this is okay since the Core does not use them
357 'pcntl_',
358 );
359 foreach ($disabledFunctionsArray as $key => $disabledFunction) {
360 foreach ($findStrings as $findString) {
361 if (strpos($disabledFunction, $findString) !== FALSE) {
362 unset($disabledFunctionsArray[$key]);
363 }
364 }
365 }
366
367 if (strlen($disabledFunctions) > 0 && count($disabledFunctionsArray) > 0) {
368 $status = new Status\ErrorStatus();
369 $status->setTitle('Some PHP functions disabled');
370 $status->setMessage(
371 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . '. These function(s)' .
372 ' are disabled. TYPO3 uses some of those, so there might be trouble. TYPO3 is designed to use the' .
373 ' default set of PHP functions plus some common extensions. Possibly these functions are disabled' .
374 ' due to security considerations and most likely the list would include a function like' .
375 ' exec() which is used by TYPO3 at various places. Depending on which exact functions' .
376 ' are disabled, some parts of the system may just break without further notice.'
377 );
378 } elseif (strlen($disabledFunctions) > 0 && count($disabledFunctionsArray) === 0) {
379 $status = new Status\NoticeStatus();
380 $status->setTitle('Some PHP functions currently disabled but OK');
381 $status->setMessage(
382 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . '. These function(s)' .
383 ' are disabled. TYPO3 uses currently none of those, so you are good to go.'
384 );
385 } else {
386 $status = new Status\OkStatus();
387 $status->setTitle('No disabled PHP functions');
388 }
389 return $status;
390 }
391
392 /**
393 * Check if safe mode is enabled
394 *
395 * @return Status\StatusInterface
396 */
397 protected function checkSafeMode() {
398 $safeModeEnabled = FALSE;
399 if (version_compare(phpversion(), '5.4', '<')) {
400 $safeModeEnabled = filter_var(
401 ini_get('safe_mode'),
402 FILTER_VALIDATE_BOOLEAN,
403 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
404 );
405 }
406 if ($safeModeEnabled) {
407 $status = new Status\ErrorStatus();
408 $status->setTitle('PHP safe mode on');
409 $status->setMessage(
410 'safe_mode enabled. This is unsupported by TYPO3 CMS, it must be turned off.'
411 );
412 } else {
413 $status = new Status\OkStatus();
414 $status->setTitle('PHP safe mode off');
415 }
416 return $status;
417 }
418
419 /**
420 * Check for doc_root ini setting
421 *
422 * @return Status\StatusInterface
423 */
424 protected function checkDocRoot() {
425 $docRootSetting = trim(ini_get('doc_root'));
426 if (strlen($docRootSetting) > 0) {
427 $status = new Status\NoticeStatus();
428 $status->setTitle('doc_root is set');
429 $status->setMessage(
430 'doc_root=' . $docRootSetting . ' PHP cannot execute scripts' .
431 ' outside this directory. This setting is used seldom and must correlate' .
432 ' with your actual document root. You might be in trouble if your' .
433 ' TYPO3 CMS core code is linked to some different location.' .
434 ' If that is a problem, the setting must be adapted.'
435 );
436 } else {
437 $status = new Status\OkStatus();
438 $status->setTitle('PHP doc_root is not set');
439 }
440 return $status;
441 }
442
443 /**
444 * Check open_basedir
445 *
446 * @return Status\StatusInterface
447 */
448 protected function checkOpenBaseDir() {
449 $openBaseDirSetting = trim(ini_get('open_basedir'));
450 if (strlen($openBaseDirSetting) > 0) {
451 $status = new Status\NoticeStatus();
452 $status->setTitle('open_basedir set');
453 $status->setMessage(
454 'open_basedir = ' . ini_get('open_basedir') .
455 ' This restricts TYPO3 to open and include files only in this' .
456 ' path. Please make sure that this does not prevent TYPO3 from running,' .
457 ' if for example your TYPO3 CMS core is linked to a different directory' .
458 ' not included in this path.'
459 );
460 } else {
461 $status = new Status\OkStatus();
462 $status->setTitle('PHP open_basedir is off');
463 }
464 return $status;
465 }
466
467 /**
468 * If xdebug is loaded, the default max_nesting_level of 100 must be raised
469 *
470 * @return Status\StatusInterface
471 */
472 protected function checkXdebugMaxNestingLevel() {
473 if (extension_loaded('xdebug')) {
474 $recommendedMaxNestingLevel = 250;
475 $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level');
476 if ($currentMaxNestingLevel < $recommendedMaxNestingLevel) {
477 $status = new Status\ErrorStatus();
478 $status->setTitle('PHP xdebug.max_nesting_level not high enough');
479 $status->setMessage(
480 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . '. This setting' .
481 ' controls the maximum number of nested function calls to protect against' .
482 ' infinite recursion. The current value is too low for TYPO3 CMS and must' .
483 ' be either raised or xdebug unloaded. A value of ' . $recommendedMaxNestingLevel .
484 ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS' .
485 ' if the default value of 100 is not raised significantly.'
486 );
487 } else {
488 $status = new Status\OkStatus();
489 $status->setTitle('PHP xdebug.max_nesting_level ok');
490 }
491 } else {
492 $status = new Status\OkStatus();
493 $status->setTitle('PHP xdebug extension not loaded');
494 }
495 return $status;
496 }
497
498 /**
499 * Check accessibility and functionality of OpenSSL
500 *
501 * @return Status\StatusInterface
502 */
503 protected function checkOpenSslInstalled() {
504 if (extension_loaded('openssl')) {
505 $testKey = @openssl_pkey_new();
506 if (is_resource($testKey)) {
507 openssl_free_key($testKey);
508 $status = new Status\OkStatus();
509 $status->setTitle('OpenSSL installed properly');
510 } else {
511 $status = new Status\ErrorStatus();
512 $status->setTitle('OpenSSL extension not working');
513 $status->setMessage(
514 'Something went wrong while trying to create a new private key. ' .
515 'Please check your OpenSSL integration to verify the extension is installed correctly.'
516 );
517 }
518 } else {
519 $status = new Status\ErrorStatus();
520 $status->setTitle('OpenSSL extension not loaded');
521 $status->setMessage(
522 'OpenSSL is an extension to encrypt/decrypt data between requests. ' .
523 'TYPO3 CMS needs it to be able to store passwords encrypted to improve the security on database layer.'
524 );
525 }
526
527 return $status;
528 }
529
530 /**
531 * Check enabled suhosin
532 *
533 * @return Status\StatusInterface
534 */
535 protected function checkSuhosinLoaded() {
536 if ($this->isSuhosinLoaded()) {
537 $status = new Status\OkStatus();
538 $status->setTitle('PHP suhosin extension loaded');
539 } else {
540 $status = new Status\NoticeStatus();
541 $status->setTitle('PHP suhosin extension not loaded');
542 $status->setMessage(
543 'suhosin is an extension to harden the PHP environment. In general, it is' .
544 ' good to have it from a security point of view. While TYPO3 CMS works' .
545 ' fine with suhosin, it has some requirements different from default settings' .
546 ' to be set if enabled.'
547 );
548 }
549 return $status;
550 }
551
552 /**
553 * Check suhosin.request.max_vars
554 *
555 * @return Status\StatusInterface
556 */
557 protected function checkSuhosinRequestMaxVars() {
558 $recommendedRequestMaxVars = 400;
559 if ($this->isSuhosinLoaded()) {
560 $currentRequestMaxVars = ini_get('suhosin.request.max_vars');
561 if ($currentRequestMaxVars < $recommendedRequestMaxVars) {
562 $status = new Status\ErrorStatus();
563 $status->setTitle('PHP suhosin.request.max_vars not high enough');
564 $status->setMessage(
565 'suhosin.request.max_vars=' . $currentRequestMaxVars . '. This setting' .
566 ' can lead to lost information if submitting big forms in TYPO3 CMS like' .
567 ' it is done in the install tool. It is heavily recommended to raise this' .
568 ' to at least ' . $recommendedRequestMaxVars
569 );
570 } else {
571 $status = new Status\OkStatus();
572 $status->setTitle('PHP suhosin.request.max_vars ok');
573 }
574 } else {
575 $status = new Status\InfoStatus();
576 $status->setTitle('Suhosin not loaded');
577 $status->setMessage(
578 'If enabling suhosin, suhosin.request.max_vars' .
579 ' should be set to at least ' . $recommendedRequestMaxVars . '.'
580 );
581 }
582 return $status;
583 }
584
585 /**
586 * Check suhosin.post.max_vars
587 *
588 * @return Status\StatusInterface
589 */
590 protected function checkSuhosinPostMaxVars() {
591 $recommendedPostMaxVars = 400;
592 if ($this->isSuhosinLoaded()) {
593 $currentPostMaxVars = ini_get('suhosin.post.max_vars');
594 if ($currentPostMaxVars < $recommendedPostMaxVars) {
595 $status = new Status\ErrorStatus();
596 $status->setTitle('PHP suhosin.post.max_vars not high enough');
597 $status->setMessage(
598 'suhosin.post.max_vars=' . $currentPostMaxVars . '. This setting' .
599 ' can lead to lost information if submitting big forms in TYPO3 CMS like' .
600 ' it is done in the install tool. It is heavily recommended to raise this' .
601 ' to at least ' . $recommendedPostMaxVars . '.'
602 );
603 } else {
604 $status = new Status\OkStatus();
605 $status->setTitle('PHP suhosin.post.max_vars ok');
606 }
607 } else {
608 $status = new Status\InfoStatus();
609 $status->setTitle('Suhosin not loaded');
610 $status->setMessage(
611 'If enabling suhosin, suhosin.post.max_vars' .
612 ' should be set to at least ' . $recommendedPostMaxVars . '.'
613 );
614 }
615 return $status;
616 }
617
618 /**
619 * Check suhosin.get.max_value_length
620 *
621 * @return Status\StatusInterface
622 */
623 protected function checkSuhosinGetMaxValueLength() {
624 $recommendedGetMaxValueLength = 2000;
625 if ($this->isSuhosinLoaded()) {
626 $currentGetMaxValueLength = ini_get('suhosin.get.max_value_length');
627 if ($currentGetMaxValueLength < $recommendedGetMaxValueLength) {
628 $status = new Status\ErrorStatus();
629 $status->setTitle('PHP suhosin.get.max_value_length not high enough');
630 $status->setMessage(
631 'suhosin.get.max_value_length=' . $currentGetMaxValueLength . '. This setting' .
632 ' can lead to lost information if submitting big forms in TYPO3 CMS like' .
633 ' it is done in the install tool. It is heavily recommended to raise this' .
634 ' to at least ' . $recommendedGetMaxValueLength . '.'
635 );
636 } else {
637 $status = new Status\OkStatus();
638 $status->setTitle('PHP suhosin.get.max_value_length ok');
639 }
640 } else {
641 $status = new Status\InfoStatus();
642 $status->setTitle('Suhosin not loaded');
643 $status->setMessage(
644 'If enabling suhosin, suhosin.get.max_value_length' .
645 ' should be set to at least ' . $recommendedGetMaxValueLength
646 );
647 }
648 return $status;
649 }
650
651 /**
652 * Check suhosin.executor.include.whitelist contains phar
653 *
654 * @return Status\StatusInterface
655 */
656 protected function checkSuhosinExecutorIncludeWhiteListContainsPhar() {
657 if ($this->isSuhosinLoaded()) {
658 $currentWhiteListArray = $this->trimExplode(' ', ini_get('suhosin.executor.include.whitelist'));
659 if (!in_array('phar', $currentWhiteListArray)) {
660 $status = new Status\NoticeStatus();
661 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain phar');
662 $status->setMessage(
663 'suhosin.executor.include.whitelist= ' . implode(' ', $currentWhiteListArray) . '. phar' .
664 ' is currently not a hard requirement of TYPO3 CMS but is nice to have and a possible requirement' .
665 ' in future versions. A useful setting is "suhosin.executor.include.whitelist = phar vfs".'
666 );
667 } else {
668 $status = new Status\OkStatus();
669 $status->setTitle('PHP suhosin.executor.include.whitelist contains phar');
670 }
671 } else {
672 $status = new Status\InfoStatus();
673 $status->setTitle('Suhosin not loaded');
674 $status->setMessage(
675 'If enabling suhosin, a useful setting is "suhosin.executor.include.whitelist = phar vfs".'
676 );
677 }
678 return $status;
679 }
680
681 /**
682 * Check suhosin.executor.include.whitelist contains vfs
683 *
684 * @return Status\StatusInterface
685 */
686 protected function checkSuhosinExecutorIncludeWhiteListContainsVfs() {
687 if ($this->isSuhosinLoaded()) {
688 $currentWhiteListArray = $this->trimExplode(' ', ini_get('suhosin.executor.include.whitelist'));
689 if (!in_array('vfs', $currentWhiteListArray)) {
690 $status = new Status\WarningStatus();
691 $status->setTitle('PHP suhosin.executor.include.whitelist does not contain vfs');
692 $status->setMessage(
693 'suhosin.executor.include.whitelist= ' . implode(' ', $currentWhiteListArray) . '. vfs' .
694 ' is currently not a hard requirement of TYPO3 CMS but tons of unit tests rely on it.' .
695 ' Furthermore, vfs is likely a base for an additional compatibility layer in the future.' .
696 ' A useful setting is "suhosin.executor.include.whitelist = phar vfs".'
697 );
698 } else {
699 $status = new Status\OkStatus();
700 $status->setTitle('PHP suhosin.executor.include.whitelist contains vfs');
701 }
702 } else {
703 $status = new Status\InfoStatus();
704 $status->setTitle('Suhosin not loaded');
705 $status->setMessage(
706 'If enabling suhosin, a useful setting is "suhosin.executor.include.whitelist = phar vfs".'
707 );
708 }
709 return $status;
710 }
711
712 /**
713 * Check if some opcode cache is loaded
714 *
715 * @return Status\StatusInterface
716 */
717 protected function checkSomePhpOpcodeCacheIsLoaded() {
718 if (
719 // Currently APCu identifies itself both as "apcu" and "apc" (for compatibility) although it doesn't provide the APC-opcache functionality
720 extension_loaded('eaccelerator')
721 || extension_loaded('xcache')
722 || (extension_loaded('apc') && !extension_loaded('apcu'))
723 || extension_loaded('Zend Optimizer+')
724 || extension_loaded('Zend OPcache')
725 || extension_loaded('wincache')
726 ) {
727 $status = new Status\OkStatus();
728 $status->setTitle('A PHP opcode cache is loaded');
729 } else {
730 $status = new Status\WarningStatus();
731 $status->setTitle('No PHP opcode cache loaded');
732 $status->setMessage(
733 'PHP opcode caches hold a compiled version of executed PHP scripts in' .
734 ' memory and do not require to recompile any script on each access.' .
735 ' This can be a massive performance improvement and can put load off a' .
736 ' server in general, a parse time reduction by factor three for full cached' .
737 ' pages can be achieved easily if using some opcode cache.' .
738 ' If in doubt choosing one, APC runs well and can be used as data' .
739 ' cache layer in TYPO3 CMS as additional feature.'
740 );
741 }
742 return $status;
743 }
744
745 /**
746 * Check doc comments can be fetched by reflection
747 *
748 * @return Status\StatusInterface
749 */
750 protected function checkReflectionDocComment() {
751 $testReflection = new \ReflectionMethod(get_class($this), __FUNCTION__);
752 if (strlen($testReflection->getDocComment()) === 0) {
753 $status = new Status\ErrorStatus();
754 $status->setTitle('Doc comment reflection broken');
755 $status->setMessage(
756 'TYPO3 CMS core extensions like extbase and fluid heavily rely on method' .
757 ' comment parsing to fetch annotations and add magic according to them.' .
758 ' This does not work in the current environment and will lead to a lot of' .
759 ' broken extensions. The PHP extension eaccelerator is known to break this if' .
760 ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.' .
761 ' This compile flag must be given, otherwise TYPO3 CMS is no fun.'
762 );
763 } else {
764 $status = new Status\OkStatus();
765 $status->setTitle('Document comment reflection works');
766 }
767 return $status;
768 }
769
770 /**
771 * Checks thread stack size if on windows with apache
772 *
773 * @return Status\StatusInterface
774 */
775 protected function checkWindowsApacheThreadStackSize() {
776 if (
777 $this->isWindowsOs()
778 && substr($_SERVER['SERVER_SOFTWARE'], 0, 6) === 'Apache'
779 ) {
780 $status = new Status\WarningStatus();
781 $status->setTitle('Windows apache thread stack size');
782 $status->setMessage(
783 'This current value can not be checked by the system, so please ignore this warning if it' .
784 ' is already taken care of: Fluid uses complex regular expressions which require a lot' .
785 ' of stack space during the first processing.' .
786 ' On Windows the default stack size for Apache is a lot smaller than on UNIX.' .
787 ' You can increase the size to 8MB (default on UNIX) by adding to the httpd.conf:' .
788 ' <IfModule mpm_winnt_module>ThreadStackSize 8388608</IfModule>. Restart Apache after this change.'
789 );
790 } else {
791 $status = new Status\OkStatus();
792 $status->setTitle('ThreadStackSize is not an issue on UNIX systems');
793 }
794 return $status;
795 }
796
797 /**
798 * Check if a specific required PHP extension is loaded
799 *
800 * @param string $extension
801 * @return Status\StatusInterface
802 */
803 protected function checkRequiredPhpExtension($extension) {
804 if (!extension_loaded($extension)) {
805 $status = new Status\ErrorStatus();
806 $status->setTitle('PHP extension ' . $extension . ' not loaded');
807 $status->setMessage(
808 'TYPO3 CMS uses PHP extension ' . $extension . ' but it is not loaded' .
809 ' in your environment. Change your environment to provide this extension.'
810 );
811 } else {
812 $status = new Status\OkStatus();
813 $status->setTitle('PHP extension ' . $extension . ' loaded');
814 }
815 return $status;
816 }
817
818 /**
819 * Check imagecreatetruecolor to verify gdlib works as expected
820 *
821 * @return Status\StatusInterface
822 */
823 protected function checkGdLibTrueColorSupport() {
824 if (function_exists('imagecreatetruecolor')) {
825 $imageResource = @imagecreatetruecolor(50, 100);
826 if (is_resource($imageResource)) {
827 imagedestroy($imageResource);
828 $status = new Status\OkStatus();
829 $status->setTitle('PHP GD library true color works');
830 } else {
831 $status = new Status\ErrorStatus();
832 $status->setTitle('PHP GD library true color support broken');
833 $status->setMessage(
834 'GD is loaded, but calling a imagecreatetruecolor returned an error.' .
835 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
836 );
837 }
838 } else {
839 $status = new Status\ErrorStatus();
840 $status->setTitle('PHP GD library true color support missing');
841 $status->setMessage(
842 'Gdlib is essential for TYPO3 CMS to work properly.'
843 );
844 }
845 return $status;
846 }
847
848 /**
849 * Check gif support of GD library
850 *
851 * @return Status\StatusInterface
852 */
853 protected function checkGdLibGifSupport() {
854 if (
855 function_exists('imagecreatefromgif')
856 && function_exists('imagegif')
857 && (imagetypes() & IMG_GIF)
858 ) {
859 $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif');
860 if (is_resource($imageResource)) {
861 imagedestroy($imageResource);
862 $status = new Status\OkStatus();
863 $status->setTitle('PHP GD library has gif support');
864 } else {
865 $status = new Status\ErrorStatus();
866 $status->setTitle('PHP GD library gif support broken');
867 $status->setMessage(
868 'GD is loaded, but calling a gif related message gives errors.' .
869 ' This must be fixed, TYPO3 CMS won\'t work well otherwise.'
870 );
871 }
872 } else {
873 $status = new Status\ErrorStatus();
874 $status->setTitle('PHP GD library gif support missing');
875 $status->setMessage(
876 'GD must be compiled with gif support. This is essential for' .
877 ' TYPO3 CMS to work properly.'
878 );
879 }
880 return $status;
881 }
882
883 /**
884 * Check jgp support of GD library
885 *
886 * @return Status\StatusInterface
887 */
888 protected function checkGdLibJpgSupport() {
889 if (
890 function_exists('imagecreatefromjpeg')
891 && function_exists('imagejpeg')
892 && (imagetypes() & IMG_JPG)
893 ) {
894 $status = new Status\OkStatus();
895 $status->setTitle('PHP GD library has jpg support');
896 } else {
897 $status= new Status\ErrorStatus();
898 $status->setTitle('PHP GD library jpg support missing');
899 $status->setMessage(
900 'GD must be compiled with jpg support. This is essential for' .
901 ' TYPO3 CMS to work properly.'
902 );
903 }
904 return $status;
905 }
906
907 /**
908 * Check png support of GD library
909 *
910 * @return Status\StatusInterface
911 */
912 protected function checkGdLibPngSupport() {
913 if (
914 function_exists('imagecreatefrompng')
915 && function_exists('imagepng')
916 && (imagetypes() & IMG_PNG)
917 ) {
918 $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png');
919 if (is_resource($imageResource)) {
920 imagedestroy($imageResource);
921 $status = new Status\OkStatus();
922 $status->setTitle('PHP GD library has png support');
923 } else {
924 $status = new Status\ErrorStatus();
925 $status->setTitle('PHP GD library png support broken');
926 $status->setMessage(
927 'GD is compiled with png support, but a test call fails.' .
928 ' Check your environment and fix it, png in GD lib is important' .
929 ' for TYPO3 CMS to work properly.'
930 );
931 }
932 } else {
933 $status = new Status\ErrorStatus();
934 $status->setTitle('PHP GD library png support missing');
935 $status->setMessage(
936 'GD must be compiled with png support. This is essential for' .
937 ' TYPO3 CMS to work properly'
938 );
939 }
940 return $status;
941 }
942
943 /**
944 * Check gdlib supports freetype
945 *
946 * @return Status\StatusInterface
947 */
948 protected function checkGdLibFreeTypeSupport() {
949 if (function_exists('imagettftext')) {
950 $status = new Status\OkStatus();
951 $status->setTitle('PHP GD library has freetype font support');
952 $status->setMessage(
953 'There is a difference between the font size setting the GD' .
954 ' library should be feeded with. If installation is completed' .
955 ' a test in the install tool helps to find out the value you need.'
956 );
957 } else {
958 $status = new Status\ErrorStatus();
959 $status->setTitle('PHP GD library freetype support missing');
960 $status->setMessage(
961 'Some core functionality and extension rely on the GD' .
962 ' to render fonts on images. This support is missing' .
963 ' in your environment. Install it.'
964 );
965 }
966 return $status;
967 }
968
969 /**
970 * Create true type font test image
971 *
972 * @return Status\StatusInterface
973 */
974 protected function isTrueTypeFontDpiStandard() {
975 if (function_exists('imageftbbox')) {
976 // 20 Pixels at 96 DPI - the DefaultConfiguration
977 $fontSize = (20 / 96 * 72);
978 $textDimensions = @imageftbbox(
979 $fontSize,
980 0,
981 __DIR__ . '/../../Resources/Private/Font/vera.ttf',
982 'Testing true type support'
983 );
984 $fontBoxWidth = $textDimensions[2] - $textDimensions[0];
985 if ($fontBoxWidth < 300 && $fontBoxWidth > 200) {
986 $status = new Status\OkStatus();
987 $status->setTitle('FreeType True Type Font DPI');
988 $status->setMessage('Fonts are rendered by FreeType library. ' .
989 'We need to ensure that the final dimensions are as expected. ' .
990 'This server renderes fonts based on 96 DPI correctly'
991 );
992 } else {
993 $status = new Status\NoticeStatus();
994 $status->setTitle('FreeType True Type Font DPI');
995 $status->setMessage('Fonts are rendered by FreeType library. ' .
996 'This server renders fonts not as expected. ' .
997 'Please configure FreeType or TYPO3_CONF_VARS[GFX][TTFdpi]'
998 );
999 }
1000 } else {
1001 $status = new Status\ErrorStatus();
1002 $status->setTitle('PHP GD library freetype2 support missing');
1003 $status->setMessage(
1004 'The core relies on GD library compiled into PHP with freetype2' .
1005 ' support. This is missing on your system. Please install it.'
1006 );
1007 }
1008
1009 return $status;
1010 }
1011
1012 /**
1013 * Check php magic quotes
1014 *
1015 * @return Status\StatusInterface
1016 */
1017 protected function checkPhpMagicQuotes() {
1018 if (get_magic_quotes_gpc()) {
1019 $status = new Status\WarningStatus();
1020 $status->setTitle('PHP magic quotes on');
1021 $status->setMessage(
1022 'PHP ini setting magic_quotes_gpc in on. The setting is deprecated since PHP 5.3.' .
1023 ' You are advised to set it to "Off" until it gets completely removed.'
1024 );
1025 } else {
1026 $status = new Status\OkStatus();
1027 $status->setTitle('PHP magic quotes off');
1028 }
1029 return $status;
1030 }
1031
1032 /**
1033 * Check register globals
1034 *
1035 * @return Status\StatusInterface
1036 */
1037 protected function checkRegisterGlobals() {
1038 $registerGlobalsEnabled = filter_var(
1039 ini_get('register_globals'),
1040 FILTER_VALIDATE_BOOLEAN,
1041 array(FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE)
1042 );
1043 if ($registerGlobalsEnabled === TRUE) {
1044 $status = new Status\ErrorStatus();
1045 $status->setTitle('PHP register globals on');
1046 $status->setMessage(
1047 'TYPO3 requires PHP setting "register_globals" set to off.' .
1048 ' This ancient PHP setting is a big security problem and should' .
1049 ' never be enabled.'
1050 );
1051 } else {
1052 $status = new Status\OkStatus();
1053 $status->setTitle('PHP register globals off');
1054 }
1055 return $status;
1056 }
1057
1058 /**
1059 * Helper methods
1060 */
1061
1062 /**
1063 * Validate a given IP address.
1064 *
1065 * @param string $ip IP address to be tested
1066 * @return boolean
1067 */
1068 protected function isValidIp($ip) {
1069 return filter_var($ip, FILTER_VALIDATE_IP) !== FALSE;
1070 }
1071
1072 /**
1073 * Test if this instance runs on windows OS
1074 *
1075 * @return boolean TRUE if operating system is windows
1076 */
1077 protected function isWindowsOs() {
1078 $windowsOs = FALSE;
1079 if (!stristr(PHP_OS, 'darwin') && stristr(PHP_OS, 'win')) {
1080 $windowsOs = TRUE;
1081 }
1082 return $windowsOs;
1083 }
1084
1085 /**
1086 * Helper method to find out if suhosin extension is loaded
1087 *
1088 * @return boolean TRUE if suhosin PHP extension is loaded
1089 */
1090 protected function isSuhosinLoaded() {
1091 $suhosinLoaded = FALSE;
1092 if (extension_loaded('suhosin')) {
1093 $suhosinLoaded = TRUE;
1094 }
1095 return $suhosinLoaded;
1096 }
1097
1098 /**
1099 * Helper method to explode a string by delimeter and throw away empty values.
1100 * Removes empty values from result array.
1101 *
1102 * @param string $delimiter Delimiter string to explode with
1103 * @param string $string The string to explode
1104 * @return array Exploded values
1105 */
1106 protected function trimExplode($delimiter, $string) {
1107 $explodedValues = explode($delimiter, $string);
1108 $resultWithPossibleEmptyValues = array_map('trim', $explodedValues);
1109 $result = array();
1110 foreach ($resultWithPossibleEmptyValues as $value) {
1111 if ($value !== '') {
1112 $result[] = $value;
1113 }
1114 }
1115 return $result;
1116 }
1117
1118 /**
1119 * Helper method to get the bytes value from a measurement string like "100k".
1120 *
1121 * @param string $measurement The measurement (e.g. "100k")
1122 * @return integer The bytes value (e.g. 102400)
1123 */
1124 protected function getBytesFromSizeMeasurement($measurement) {
1125 $bytes = doubleval($measurement);
1126 if (stripos($measurement, 'G')) {
1127 $bytes *= 1024 * 1024 * 1024;
1128 } elseif (stripos($measurement, 'M')) {
1129 $bytes *= 1024 * 1024;
1130 } elseif (stripos($measurement, 'K')) {
1131 $bytes *= 1024;
1132 }
1133 return $bytes;
1134 }
1135 }
1136 ?>