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