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