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