[TASK] Suggest PHP "intl" extension
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / SystemEnvironment / Check.php
1 <?php
2 namespace TYPO3\CMS\Install\SystemEnvironment;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Messaging\FlashMessage;
18 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
19
20 /**
21 * Check system environment status
22 *
23 * This class is a hardcoded requirement check of the underlying
24 * server and PHP system.
25 *
26 * The class *must not* check for any TYPO3 specific things like
27 * specific configuration values or directories. It should not fail
28 * if there is no TYPO3 at all.
29 *
30 * The only core code used is the class loader
31 *
32 * This class is instantiated as the *very first* class during
33 * installation. It is meant to be *standalone* und must not have
34 * any requirements, except the status classes. It must be possible
35 * to run this script separated from the rest of the core, without
36 * dependencies.
37 *
38 * This means especially:
39 * * No hooks or anything like that
40 * * No usage of *any* TYPO3 code like GeneralUtility
41 * * No require of anything but the status classes
42 * * No localization
43 *
44 * The status messages and title *must not* include HTML, use plain
45 * text only. The return values of this class are not bound to HTML
46 * and can be used in different scopes (eg. as json array).
47 */
48 class Check implements CheckInterface
49 {
50 /**
51 * @var FlashMessageQueue
52 */
53 protected $messageQueue;
54
55 /**
56 * @var array List of required PHP extensions
57 */
58 protected $requiredPhpExtensions = [
59 'filter',
60 'gd',
61 'hash',
62 'json',
63 'mysqli',
64 'openssl',
65 'session',
66 'SPL',
67 'standard',
68 'xml',
69 'zip',
70 'zlib',
71 ];
72
73 /**
74 * @var string[]
75 */
76 protected $suggestedPhpExtensions = [
77 'fileinfo' => 'This extension is used for proper file type detection in the File Abstraction Layer.',
78 'intl' => 'This extension is used for correct language and locale handling.'
79 ];
80
81 /**
82 * Get all status information as array with status objects
83 *
84 * @return FlashMessageQueue
85 */
86 public function getStatus(): FlashMessageQueue
87 {
88 $this->messageQueue = new FlashMessageQueue('install');
89 $this->checkCurrentDirectoryIsInIncludePath();
90 $this->checkFileUploadEnabled();
91 $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
92 $this->checkMemorySettings();
93 $this->checkPhpVersion();
94 $this->checkMaxExecutionTime();
95 $this->checkDisableFunctions();
96 $this->checkMysqliReconnectSetting();
97 $this->checkDocRoot();
98 $this->checkOpenBaseDir();
99 $this->checkXdebugMaxNestingLevel();
100 $this->checkOpenSslInstalled();
101
102 $this->checkMaxInputVars();
103 $this->checkReflectionDocComment();
104 $this->checkWindowsApacheThreadStackSize();
105
106 foreach ($this->requiredPhpExtensions as $extension) {
107 $this->checkPhpExtension($extension);
108 }
109
110 foreach ($this->suggestedPhpExtensions as $extension => $purpose) {
111 $this->checkPhpExtension($extension, false, $purpose);
112 }
113
114 $this->checkPcreVersion();
115 $this->checkGdLibTrueColorSupport();
116 $this->checkGdLibGifSupport();
117 $this->checkGdLibJpgSupport();
118 $this->checkGdLibPngSupport();
119 $this->checkGdLibFreeTypeSupport();
120
121 return $this->messageQueue;
122 }
123
124 /**
125 * Checks if current directory (.) is in PHP include path
126 */
127 protected function checkCurrentDirectoryIsInIncludePath()
128 {
129 $includePath = ini_get('include_path');
130 $delimiter = $this->isWindowsOs() ? ';' : ':';
131 $pathArray = $this->trimExplode($delimiter, $includePath);
132 if (!in_array('.', $pathArray)) {
133 $this->messageQueue->enqueue(new FlashMessage(
134 'include_path = ' . implode(' ', $pathArray) . LF
135 . 'Normally the current path \'.\' is included in the'
136 . ' include_path of PHP. Although TYPO3 does not rely on this,'
137 . ' it is an unusual setting that may introduce problems for'
138 . ' some extensions.',
139 'Current directory (./) is not within PHP include path',
140 FlashMessage::WARNING
141 ));
142 } else {
143 $this->messageQueue->enqueue(new FlashMessage(
144 '',
145 'Current directory (./) is within PHP include path.'
146 ));
147 }
148 }
149
150 /**
151 * Check if file uploads are enabled in PHP
152 */
153 protected function checkFileUploadEnabled()
154 {
155 if (!ini_get('file_uploads')) {
156 $this->messageQueue->enqueue(new FlashMessage(
157 'file_uploads=' . ini_get('file_uploads') . LF
158 . 'TYPO3 uses the ability to upload files from the browser in various cases.'
159 . ' If this flag is disabled in PHP, you won\'t be able to upload files.'
160 . ' But it doesn\'t end here, because not only are files not accepted by'
161 . ' the server - ALL content in the forms are discarded and therefore'
162 . ' nothing at all will be editable if you don\'t set this flag!',
163 'File uploads not allowed in PHP',
164 FlashMessage::ERROR
165 ));
166 } else {
167 $this->messageQueue->enqueue(new FlashMessage(
168 '',
169 'File uploads allowed in PHP'
170 ));
171 }
172 }
173
174 /**
175 * Check maximum post upload size correlates with maximum file upload
176 */
177 protected function checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize()
178 {
179 $maximumUploadFilesize = $this->getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
180 $maximumPostSize = $this->getBytesFromSizeMeasurement(ini_get('post_max_size'));
181 if ($maximumPostSize > 0 && $maximumPostSize < $maximumUploadFilesize) {
182 $this->messageQueue->enqueue(new FlashMessage(
183 'upload_max_filesize=' . ini_get('upload_max_filesize') . LF
184 . 'post_max_size=' . ini_get('post_max_size') . LF
185 . 'You have defined a maximum size for file uploads in PHP which'
186 . ' exceeds the allowed size for POST requests. Therefore the'
187 . ' file uploads can also not be larger than ' . ini_get('post_max_size') . '.',
188 'Maximum size for POST requests is smaller than maximum upload filesize in PHP',
189 FlashMessage::ERROR
190 ));
191 } else {
192 $this->messageQueue->enqueue(new FlashMessage(
193 'The maximum size for file uploads is actually set to ' . ini_get('post_max_size'),
194 'Maximum post upload size correlates with maximum upload file size in PHP'
195 ));
196 }
197 }
198
199 /**
200 * Check memory settings
201 */
202 protected function checkMemorySettings()
203 {
204 $minimumMemoryLimit = 64;
205 $recommendedMemoryLimit = 128;
206 $memoryLimit = $this->getBytesFromSizeMeasurement(ini_get('memory_limit'));
207 if ($memoryLimit <= 0) {
208 $this->messageQueue->enqueue(new FlashMessage(
209 'PHP is configured not to limit memory usage at all. This is a risk'
210 . ' and should be avoided in production setup. In general it\'s best practice to limit this.'
211 . ' To be safe, set a limit in PHP, but with a minimum of ' . $recommendedMemoryLimit . 'MB:' . LF
212 . 'memory_limit=' . $recommendedMemoryLimit . 'M',
213 'Unlimited memory limit for PHP',
214 FlashMessage::WARNING
215 ));
216 } elseif ($memoryLimit < 1024 * 1024 * $minimumMemoryLimit) {
217 $this->messageQueue->enqueue(new FlashMessage(
218 'memory_limit=' . ini_get('memory_limit') . LF
219 . 'Your system is configured to enforce a memory limit for PHP scripts lower than '
220 . $minimumMemoryLimit . 'MB. It is required to raise the limit.'
221 . ' We recommend a minimum PHP memory limit of ' . $recommendedMemoryLimit . 'MB:' . LF
222 . 'memory_limit=' . $recommendedMemoryLimit . 'M',
223 'PHP Memory limit below ' . $minimumMemoryLimit . 'MB',
224 FlashMessage::ERROR
225 ));
226 } elseif ($memoryLimit < 1024 * 1024 * $recommendedMemoryLimit) {
227 $this->messageQueue->enqueue(new FlashMessage(
228 'memory_limit=' . ini_get('memory_limit') . LF
229 . 'Your system is configured to enforce a memory limit for PHP scripts lower than '
230 . $recommendedMemoryLimit . 'MB.'
231 . ' A slim TYPO3 instance without many extensions will probably work, but you should monitor your'
232 . ' system for "allowed memory size of X bytes exhausted" messages, especially if using the backend.'
233 . ' To be on the safe side,' . ' we recommend a minimum PHP memory limit of '
234 . $recommendedMemoryLimit . 'MB:' . LF
235 . 'memory_limit=' . $recommendedMemoryLimit . 'M',
236 'PHP Memory limit below ' . $recommendedMemoryLimit . 'MB',
237 FlashMessage::WARNING
238 ));
239 } else {
240 $this->messageQueue->enqueue(new FlashMessage(
241 '',
242 'PHP Memory limit is equal to or more than ' . $recommendedMemoryLimit . 'MB'
243 ));
244 }
245 }
246
247 /**
248 * Check minimum PHP version
249 */
250 protected function checkPhpVersion()
251 {
252 $minimumPhpVersion = '7.0.0';
253 $currentPhpVersion = phpversion();
254 if (version_compare($currentPhpVersion, $minimumPhpVersion) < 0) {
255 $this->messageQueue->enqueue(new FlashMessage(
256 'Your PHP version ' . $currentPhpVersion . ' is too old. TYPO3 CMS does not run'
257 . ' with this version. Update to at least PHP ' . $minimumPhpVersion,
258 'PHP version too low',
259 FlashMessage::ERROR
260 ));
261 } else {
262 $this->messageQueue->enqueue(new FlashMessage(
263 '',
264 'PHP version is fine'
265 ));
266 }
267 }
268
269 /**
270 * Check PRCE module is loaded and minimum version
271 */
272 protected function checkPcreVersion()
273 {
274 $minimumPcreVersion = '8.38';
275 if (!extension_loaded('pcre')) {
276 $this->messageQueue->enqueue(new FlashMessage(
277 'TYPO3 CMS uses PHP extension pcre but it is not loaded'
278 . ' in your environment. Change your environment to provide this extension'
279 . ' in with minimum version ' . $minimumPcreVersion . '.',
280 'PHP extension pcre not loaded',
281 FlashMessage::ERROR
282 ));
283 } else {
284 $installedPcreVersionString = trim(PCRE_VERSION); // '8.39 2016-06-14'
285 $mainPcreVersionString = explode(' ', $installedPcreVersionString);
286 $mainPcreVersionString = $mainPcreVersionString[0]; // '8.39'
287 if (version_compare($mainPcreVersionString, $minimumPcreVersion) < 0) {
288 $this->messageQueue->enqueue(new FlashMessage(
289 'Your PCRE version ' . PCRE_VERSION . ' is too old. TYPO3 CMS may trigger PHP segmentantion'
290 . ' faults with this version. Update to at least PCRE ' . $minimumPcreVersion,
291 'PCRE version too low',
292 FlashMessage::ERROR
293 ));
294 } else {
295 $this->messageQueue->enqueue(new FlashMessage(
296 '',
297 'PHP extension PCRE is loaded and version is fine'
298 ));
299 }
300 }
301 }
302
303 /**
304 * Check maximum execution time
305 */
306 protected function checkMaxExecutionTime()
307 {
308 $minimumMaximumExecutionTime = 30;
309 $recommendedMaximumExecutionTime = 240;
310 $currentMaximumExecutionTime = ini_get('max_execution_time');
311 if ($currentMaximumExecutionTime == 0) {
312 $this->messageQueue->enqueue(new FlashMessage(
313 'max_execution_time=0' . LF
314 . 'While TYPO3 is fine with this, you risk a denial-of-service for your system if for whatever'
315 . ' reason some script hangs in an infinite loop. You are usually on the safe side '
316 . ' if it is reduced to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF
317 . 'max_execution_time=' . $recommendedMaximumExecutionTime,
318 'Infinite PHP script execution time',
319 FlashMessage::WARNING
320 ));
321 } elseif ($currentMaximumExecutionTime < $minimumMaximumExecutionTime) {
322 $this->messageQueue->enqueue(new FlashMessage(
323 'max_execution_time=' . $currentMaximumExecutionTime . LF
324 . 'Your max_execution_time is too low. Some expensive operations in TYPO3 can take longer than that.'
325 . ' It is recommended to raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF
326 . 'max_execution_time=' . $recommendedMaximumExecutionTime,
327 'Low PHP script execution time',
328 FlashMessage::ERROR
329 ));
330 } elseif ($currentMaximumExecutionTime < $recommendedMaximumExecutionTime) {
331 $this->messageQueue->enqueue(new FlashMessage(
332 'max_execution_time=' . $currentMaximumExecutionTime . LF
333 . 'Your max_execution_time is low. While TYPO3 often runs without problems'
334 . ' with ' . $minimumMaximumExecutionTime . ' seconds,'
335 . ' it may still happen that script execution is stopped before finishing'
336 . ' calculations. You should monitor the system for messages in this area'
337 . ' and maybe raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF
338 . 'max_execution_time=' . $recommendedMaximumExecutionTime,
339 'Low PHP script execution time',
340 FlashMessage::WARNING
341 ));
342 } else {
343 $this->messageQueue->enqueue(new FlashMessage(
344 '',
345 'Maximum PHP script execution time is equal to or more than ' . $recommendedMaximumExecutionTime
346 ));
347 }
348 }
349
350 /**
351 * Check for disabled functions
352 */
353 protected function checkDisableFunctions()
354 {
355 $disabledFunctions = trim(ini_get('disable_functions'));
356
357 // Filter "disable_functions"
358 $disabledFunctionsArray = $this->trimExplode(',', $disabledFunctions);
359
360 // Array with strings to find
361 $findStrings = [
362 // Disabled by default on Ubuntu OS but this is okay since the Core does not use them
363 'pcntl_',
364 ];
365 foreach ($disabledFunctionsArray as $key => $disabledFunction) {
366 foreach ($findStrings as $findString) {
367 if (strpos($disabledFunction, $findString) !== false) {
368 unset($disabledFunctionsArray[$key]);
369 }
370 }
371 }
372
373 if ($disabledFunctions !== '') {
374 if (!empty($disabledFunctionsArray)) {
375 $this->messageQueue->enqueue(new FlashMessage(
376 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF
377 . 'These function(s) are disabled. TYPO3 uses some of those, so there might be trouble.'
378 . ' TYPO3 is designed to use the default set of PHP functions plus some common extensions.'
379 . ' Possibly these functions are disabled'
380 . ' due to security considerations and most likely the list would include a function like'
381 . ' exec() which is used by TYPO3 at various places. Depending on which exact functions'
382 . ' are disabled, some parts of the system may just break without further notice.',
383 'Some PHP functions disabled',
384 FlashMessage::ERROR
385 ));
386 } else {
387 $this->messageQueue->enqueue(new FlashMessage(
388 'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF
389 . 'These function(s) are disabled. TYPO3 uses currently none of those, so you are good to go.',
390 'Some PHP functions currently disabled but OK'
391 ));
392 }
393 } else {
394 $this->messageQueue->enqueue(new FlashMessage(
395 '',
396 'No disabled PHP functions'
397 ));
398 }
399 }
400
401 /**
402 * Verify that mysqli.reconnect is set to 0 in order to avoid improper reconnects
403 */
404 protected function checkMysqliReconnectSetting()
405 {
406 $currentMysqliReconnectSetting = ini_get('mysqli.reconnect');
407 if ($currentMysqliReconnectSetting === '1') {
408 $this->messageQueue->enqueue(new FlashMessage(
409 'mysqli.reconnect=1' . LF
410 . 'PHP is configured to automatically reconnect the database connection on disconnection.' . LF
411 . ' Warning: If (e.g. during a long-running task) the connection is dropped and automatically reconnected, '
412 . ' it may not be reinitialized properly (e.g. charset) and write mangled data to the database!',
413 'PHP mysqli.reconnect is enabled',
414 FlashMessage::ERROR
415 ));
416 } else {
417 $this->messageQueue->enqueue(new FlashMessage(
418 '',
419 'PHP mysqli.reconnect is fine'
420 ));
421 }
422 }
423
424 /**
425 * Check for doc_root ini setting
426 */
427 protected function checkDocRoot()
428 {
429 $docRootSetting = trim(ini_get('doc_root'));
430 if ($docRootSetting !== '') {
431 $this->messageQueue->enqueue(new FlashMessage(
432 'doc_root=' . $docRootSetting . LF
433 . 'PHP cannot execute scripts'
434 . ' outside this directory. This setting is seldom used and must correlate'
435 . ' with your actual document root. You might be in trouble if your'
436 . ' TYPO3 CMS core code is linked to some different location.'
437 . ' If that is a problem, the setting must be changed.',
438 'doc_root is set',
439 FlashMessage::NOTICE
440 ));
441 } else {
442 $this->messageQueue->enqueue(new FlashMessage(
443 '',
444 'PHP doc_root is not set'
445 ));
446 }
447 }
448
449 /**
450 * Check open_basedir
451 */
452 protected function checkOpenBaseDir()
453 {
454 $openBaseDirSetting = trim(ini_get('open_basedir'));
455 if ($openBaseDirSetting !== '') {
456 $this->messageQueue->enqueue(new FlashMessage(
457 'open_basedir = ' . ini_get('open_basedir') . LF
458 . 'This restricts TYPO3 to open and include files only in this'
459 . ' path. Please make sure that this does not prevent TYPO3 from running,'
460 . ' if for example your TYPO3 CMS core is linked to a different directory'
461 . ' not included in this path.',
462 'PHP open_basedir is set',
463 FlashMessage::NOTICE
464 ));
465 } else {
466 $this->messageQueue->enqueue(new FlashMessage(
467 '',
468 'PHP open_basedir is off'
469 ));
470 }
471 }
472
473 /**
474 * If xdebug is loaded, the default max_nesting_level of 100 must be raised
475 */
476 protected function checkXdebugMaxNestingLevel()
477 {
478 if (extension_loaded('xdebug')) {
479 $recommendedMaxNestingLevel = 400;
480 $errorThreshold = 250;
481 $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level');
482 if ($currentMaxNestingLevel < $errorThreshold) {
483 $this->messageQueue->enqueue(new FlashMessage(
484 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF
485 . 'This setting controls the maximum number of nested function calls to protect against'
486 . ' infinite recursion. The current value is too low for TYPO3 CMS and must'
487 . ' be either raised or xdebug has to be unloaded. A value of ' . $recommendedMaxNestingLevel
488 . ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS'
489 . ' if the value is not raised significantly to:' . LF
490 . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel,
491 'PHP xdebug.max_nesting_level is critically low',
492 FlashMessage::ERROR
493 ));
494 } elseif ($currentMaxNestingLevel < $recommendedMaxNestingLevel) {
495 $this->messageQueue->enqueue(new FlashMessage(
496 'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF
497 . 'This setting controls the maximum number of nested function calls to protect against'
498 . ' infinite recursion. The current value is high enough for the TYPO3 CMS core to work'
499 . ' fine, but still some extensions could raise fatal PHP errors if the setting is not'
500 . ' raised further. A value of ' . $recommendedMaxNestingLevel . ' is recommended.' . LF
501 . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel,
502 'PHP xdebug.max_nesting_level is low',
503 FlashMessage::WARNING
504 ));
505 } else {
506 $this->messageQueue->enqueue(new FlashMessage(
507 '',
508 'PHP xdebug.max_nesting_level ok'
509 ));
510 }
511 } else {
512 $this->messageQueue->enqueue(new FlashMessage(
513 '',
514 'PHP xdebug extension not loaded'
515 ));
516 }
517 }
518
519 /**
520 * Check accessibility and functionality of OpenSSL
521 */
522 protected function checkOpenSslInstalled()
523 {
524 if (extension_loaded('openssl')) {
525 $testKey = @openssl_pkey_new();
526 if (is_resource($testKey)) {
527 openssl_free_key($testKey);
528 $this->messageQueue->enqueue(new FlashMessage(
529 '',
530 'PHP OpenSSL extension installed properly'
531 ));
532 } else {
533 $this->messageQueue->enqueue(new FlashMessage(
534 'Something went wrong while trying to create a new private key for testing.'
535 . ' Please check the integration of the PHP OpenSSL extension and if it is installed correctly.',
536 'PHP OpenSSL extension not working',
537 FlashMessage::ERROR
538 ));
539 }
540 } else {
541 $this->messageQueue->enqueue(new FlashMessage(
542 'OpenSSL is a PHP extension to encrypt/decrypt data between requests.'
543 . ' TYPO3 CMS requires it to be able to encrypt stored passwords to improve the security in the'
544 . ' database layer.',
545 'PHP OpenSSL extension not loaded',
546 FlashMessage::ERROR
547 ));
548 }
549 }
550
551 /**
552 * Get max_input_vars status
553 */
554 protected function checkMaxInputVars()
555 {
556 $recommendedMaxInputVars = 1500;
557 $minimumMaxInputVars = 1000;
558 $currentMaxInputVars = ini_get('max_input_vars');
559
560 if ($currentMaxInputVars < $minimumMaxInputVars) {
561 $this->messageQueue->enqueue(new FlashMessage(
562 'max_input_vars=' . $currentMaxInputVars . LF
563 . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS'
564 . ' (as the install tool does). It is highly recommended to raise this'
565 . ' to at least ' . $recommendedMaxInputVars . ':' . LF
566 . 'max_input_vars=' . $recommendedMaxInputVars,
567 'PHP max_input_vars too low',
568 FlashMessage::ERROR
569 ));
570 } elseif ($currentMaxInputVars < $recommendedMaxInputVars) {
571 $this->messageQueue->enqueue(new FlashMessage(
572 'max_input_vars=' . $currentMaxInputVars . LF
573 . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS'
574 . ' (as the install tool does). It is highly recommended to raise this'
575 . ' to at least ' . $recommendedMaxInputVars . ':' . LF
576 . 'max_input_vars=' . $recommendedMaxInputVars,
577 'PHP max_input_vars very low',
578 FlashMessage::WARNING
579 ));
580 } else {
581 $this->messageQueue->enqueue(new FlashMessage(
582 '',
583 'PHP max_input_vars ok'
584 ));
585 }
586 }
587
588 /**
589 * Check doc comments can be fetched by reflection
590 */
591 protected function checkReflectionDocComment()
592 {
593 $testReflection = new \ReflectionMethod(static::class, __FUNCTION__);
594 if ($testReflection->getDocComment() === false) {
595 $this->messageQueue->enqueue(new FlashMessage(
596 'TYPO3 CMS core extensions like extbase and fluid heavily rely on method'
597 . ' comment parsing to fetch annotations and add magic belonging to them.'
598 . ' This does not work in the current environment and so we cannot install'
599 . ' TYPO3 CMS.' . LF
600 . ' Here are some possibilities: ' . LF
601 . '* In Zend OPcache you can disable saving/loading comments. If you are using'
602 . ' Zend OPcache (included since PHP 5.5) then check your php.ini settings for'
603 . ' opcache.save_comments and opcache.load_comments and enable them.' . LF
604 . '* In Zend Optimizer+ you can disable saving comments. If you are using'
605 . ' Zend Optimizer+ then check your php.ini settings for'
606 . ' zend_optimizerplus.save_comments and enable it.' . LF
607 . '* The PHP extension eaccelerator is known to break this if'
608 . ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.'
609 . ' This compile flag must be specified, otherwise TYPO3 CMS will not work.' . LF
610 . 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.',
611 'PHP Doc comment reflection broken',
612 FlashMessage::ERROR
613 ));
614 } else {
615 $this->messageQueue->enqueue(new FlashMessage(
616 '',
617 'PHP Doc comment reflection works'
618 ));
619 }
620 }
621
622 /**
623 * Checks thread stack size if on windows with apache
624 */
625 protected function checkWindowsApacheThreadStackSize()
626 {
627 if ($this->isWindowsOs()
628 && substr($_SERVER['SERVER_SOFTWARE'], 0, 6) === 'Apache'
629 ) {
630 $this->messageQueue->enqueue(new FlashMessage(
631 'This current value cannot be checked by the system, so please ignore this warning if it'
632 . ' is already taken care of: Fluid uses complex regular expressions which require a lot'
633 . ' of stack space during the first processing.'
634 . ' On Windows the default stack size for Apache is a lot smaller than on UNIX.'
635 . ' You can increase the size to 8MB (default on UNIX) by adding the following configuration'
636 . ' to httpd.conf and restarting Apache afterwards:' . LF
637 . '&lt;IfModule mpm_winnt_module&gt;' . LF
638 . 'ThreadStackSize 8388608' . LF
639 . '&lt;/IfModule&gt;',
640 'Windows apache thread stack size',
641 FlashMessage::WARNING
642 ));
643 } else {
644 $this->messageQueue->enqueue(new FlashMessage(
645 '',
646 'Apache ThreadStackSize is not an issue on UNIX systems'
647 ));
648 }
649 }
650
651 /**
652 * Checks if a specific PHP extension is loaded.
653 *
654 * @param string $extension
655 * @param bool $required
656 * @param string $purpose
657 */
658 protected function checkPhpExtension(string $extension, bool $required = true, string $purpose = '')
659 {
660 if (!extension_loaded($extension)) {
661 $this->messageQueue->enqueue(new FlashMessage(
662 'TYPO3 uses the PHP extension "' . $extension . '" but it is not loaded'
663 . ' in your environment. Change your environment to provide this extension. '
664 . $purpose,
665 'PHP extension "' . $extension . '" not loaded',
666 $required ? FlashMessage::ERROR : FlashMessage::WARNING
667 ));
668 } else {
669 $this->messageQueue->enqueue(new FlashMessage(
670 '',
671 'PHP extension "' . $extension . '" loaded'
672 ));
673 }
674 }
675
676 /**
677 * Check imagecreatetruecolor to verify gdlib works as expected
678 */
679 protected function checkGdLibTrueColorSupport()
680 {
681 if (function_exists('imagecreatetruecolor')) {
682 $imageResource = @imagecreatetruecolor(50, 100);
683 if (is_resource($imageResource)) {
684 imagedestroy($imageResource);
685 $this->messageQueue->enqueue(new FlashMessage(
686 '',
687 'PHP GD library true color works'
688 ));
689 } else {
690 $this->messageQueue->enqueue(new FlashMessage(
691 'GD is loaded, but calling imagecreatetruecolor() fails.'
692 . ' This must be fixed, TYPO3 CMS won\'t work well otherwise.',
693 'PHP GD library true color support broken',
694 FlashMessage::ERROR
695 ));
696 }
697 } else {
698 $this->messageQueue->enqueue(new FlashMessage(
699 'Gdlib is essential for TYPO3 CMS to work properly.',
700 'PHP GD library true color support missing',
701 FlashMessage::ERROR
702 ));
703 }
704 }
705
706 /**
707 * Check gif support of GD library
708 */
709 protected function checkGdLibGifSupport()
710 {
711 if (function_exists('imagecreatefromgif')
712 && function_exists('imagegif')
713 && (imagetypes() & IMG_GIF)
714 ) {
715 // See http://stackoverflow.com/a/13139830
716 $imageResource = @imagecreatefromgif('data://image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
717 if (is_resource($imageResource)) {
718 imagedestroy($imageResource);
719 $this->messageQueue->enqueue(new FlashMessage(
720 '',
721 'PHP GD library has gif support'
722 ));
723 } else {
724 $this->messageQueue->enqueue(new FlashMessage(
725 'GD is loaded, but calling imagecreatefromgif() fails. This must be fixed, TYPO3 CMS won\'t work well otherwise.',
726 'PHP GD library gif support broken',
727 FlashMessage::ERROR
728 ));
729 }
730 } else {
731 $this->messageQueue->enqueue(new FlashMessage(
732 'GD must be compiled with gif support. This is essential for TYPO3 CMS to work properly.',
733 'PHP GD library gif support missing',
734 FlashMessage::ERROR
735 ));
736 }
737 }
738
739 /**
740 * Check jgp support of GD library
741 */
742 protected function checkGdLibJpgSupport()
743 {
744 if (function_exists('imagecreatefromjpeg')
745 && function_exists('imagejpeg')
746 && (imagetypes() & IMG_JPG)
747 ) {
748 $this->messageQueue->enqueue(new FlashMessage(
749 '',
750 'PHP GD library has jpg support'
751 ));
752 } else {
753 $this->messageQueue->enqueue(new FlashMessage(
754 'GD must be compiled with jpg support. This is essential for TYPO3 CMS to work properly.',
755 'PHP GD library jpg support missing',
756 FlashMessage::ERROR
757 ));
758 }
759 }
760
761 /**
762 * Check png support of GD library
763 */
764 protected function checkGdLibPngSupport()
765 {
766 if (function_exists('imagecreatefrompng')
767 && function_exists('imagepng')
768 && (imagetypes() & IMG_PNG)
769 ) {
770 $imageResource = @imagecreatefrompng('data://image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII');
771 if (is_resource($imageResource)) {
772 imagedestroy($imageResource);
773 $this->messageQueue->enqueue(new FlashMessage(
774 '',
775 'PHP GD library has png support'
776 ));
777 } else {
778 $this->messageQueue->enqueue(new FlashMessage(
779 'GD is compiled with png support, but calling imagecreatefrompng() fails.'
780 . ' Check your environment and fix it, png in GD lib is important'
781 . ' for TYPO3 CMS to work properly.',
782 'PHP GD library png support broken',
783 FlashMessage::ERROR
784 ));
785 }
786 } else {
787 $this->messageQueue->enqueue(new FlashMessage(
788 'GD must be compiled with png support. This is essential for TYPO3 CMS to work properly',
789 'PHP GD library png support missing',
790 FlashMessage::ERROR
791 ));
792 }
793 }
794
795 /**
796 * Check gdlib supports freetype
797 */
798 protected function checkGdLibFreeTypeSupport()
799 {
800 if (function_exists('imagettftext')) {
801 $this->messageQueue->enqueue(new FlashMessage(
802 'There is a difference between the font size setting which the GD'
803 . ' library should be supplied with. If installation is completed'
804 . ' a test in the install tool helps to find out the value you need.',
805 'PHP GD library has freetype font support'
806 ));
807 } else {
808 $this->messageQueue->enqueue(new FlashMessage(
809 'Some core functionality and extension rely on the GD'
810 . ' to render fonts on images. This support is missing'
811 . ' in your environment. Install it.',
812 'PHP GD library freetype support missing',
813 FlashMessage::ERROR
814 ));
815 }
816 }
817
818 /**
819 * Helper methods
820 */
821
822 /**
823 * Validate a given IP address.
824 *
825 * @param string $ip IP address to be tested
826 * @return bool
827 */
828 protected function isValidIp($ip)
829 {
830 return filter_var($ip, FILTER_VALIDATE_IP) !== false;
831 }
832
833 /**
834 * Test if this instance runs on windows OS
835 *
836 * @return bool TRUE if operating system is windows
837 */
838 protected function isWindowsOs()
839 {
840 $windowsOs = false;
841 if (!stristr(PHP_OS, 'darwin') && stristr(PHP_OS, 'win')) {
842 $windowsOs = true;
843 }
844 return $windowsOs;
845 }
846
847 /**
848 * Helper method to explode a string by delimiter and throw away empty values.
849 * Removes empty values from result array.
850 *
851 * @param string $delimiter Delimiter string to explode with
852 * @param string $string The string to explode
853 * @return array Exploded values
854 */
855 protected function trimExplode($delimiter, $string)
856 {
857 $explodedValues = explode($delimiter, $string);
858 $resultWithPossibleEmptyValues = array_map('trim', $explodedValues);
859 $result = [];
860 foreach ($resultWithPossibleEmptyValues as $value) {
861 if ($value !== '') {
862 $result[] = $value;
863 }
864 }
865 return $result;
866 }
867
868 /**
869 * Helper method to get the bytes value from a measurement string like "100k".
870 *
871 * @param string $measurement The measurement (e.g. "100k")
872 * @return int The bytes value (e.g. 102400)
873 */
874 protected function getBytesFromSizeMeasurement($measurement)
875 {
876 $bytes = (float)$measurement;
877 if (stripos($measurement, 'G')) {
878 $bytes *= 1024 * 1024 * 1024;
879 } elseif (stripos($measurement, 'M')) {
880 $bytes *= 1024 * 1024;
881 } elseif (stripos($measurement, 'K')) {
882 $bytes *= 1024;
883 }
884 return (int)$bytes;
885 }
886 }