Passed
Push — master ( 0a3947...bfb42c )
by
unknown
18:00
created

Check::checkImageResource()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Install\SystemEnvironment;
19
20
use TYPO3\CMS\Core\Information\Typo3Information;
21
use TYPO3\CMS\Core\Messaging\FlashMessage;
22
use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
23
24
/**
25
 * Check system environment status
26
 *
27
 * This class is a hardcoded requirement check of the underlying
28
 * server and PHP system.
29
 *
30
 * The class *must not* check for any TYPO3 specific things like
31
 * specific configuration values or directories. It should not fail
32
 * if there is no TYPO3 at all.
33
 *
34
 * The only core code used is the class loader
35
 *
36
 * This class is instantiated as the *very first* class during
37
 * installation. It is meant to be *standalone* und must not have
38
 * any requirements, except the status classes. It must be possible
39
 * to run this script separated from the rest of the core, without
40
 * dependencies.
41
 *
42
 * This means especially:
43
 * * No hooks or anything like that
44
 * * No usage of *any* TYPO3 code like GeneralUtility
45
 * * No require of anything but the status classes
46
 * * No localization
47
 *
48
 * The status messages and title *must not* include HTML, use plain
49
 * text only. The return values of this class are not bound to HTML
50
 * and can be used in different scopes (eg. as json array).
51
 *
52
 * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
53
 */
54
class Check implements CheckInterface
55
{
56
    /**
57
     * @var FlashMessageQueue
58
     */
59
    protected $messageQueue;
60
61
    /**
62
     * @var array List of required PHP extensions
63
     */
64
    protected $requiredPhpExtensions = [
65
        'filter',
66
        'gd',
67
        'hash',
68
        'json',
69
        'libxml',
70
        'PDO',
71
        'session',
72
        'SPL',
73
        'standard',
74
        'xml',
75
        'zip',
76
        'zlib',
77
    ];
78
79
    /**
80
     * @var string[]
81
     */
82
    protected $suggestedPhpExtensions = [
83
        'fileinfo' => 'This extension is used for proper file type detection in the File Abstraction Layer.',
84
        'intl' => 'This extension is used for correct language and locale handling.',
85
        'openssl' => 'This extension is used for sending SMTP mails over an encrypted channel endpoint, and for extensions such as "rsaauth".'
86
    ];
87
88
    public function __construct()
89
    {
90
        $this->messageQueue = new FlashMessageQueue('install');
91
    }
92
93
    public function getMessageQueue(): FlashMessageQueue
94
    {
95
        return $this->messageQueue;
96
    }
97
98
    /**
99
     * Get all status information as array with status objects
100
     *
101
     * @return FlashMessageQueue
102
     */
103
    public function getStatus(): FlashMessageQueue
104
    {
105
        $this->checkCurrentDirectoryIsInIncludePath();
106
        $this->checkFileUploadEnabled();
107
        $this->checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize();
108
        $this->checkMemorySettings();
109
        $this->checkPhpVersion();
110
        $this->checkMaxExecutionTime();
111
        $this->checkDisableFunctions();
112
        $this->checkDocRoot();
113
        $this->checkOpenBaseDir();
114
        $this->checkXdebugMaxNestingLevel();
115
116
        $this->checkMaxInputVars();
117
        $this->checkReflectionDocComment();
118
        $this->checkWindowsApacheThreadStackSize();
119
120
        foreach ($this->requiredPhpExtensions as $extension) {
121
            $this->checkPhpExtension($extension);
122
        }
123
124
        foreach ($this->suggestedPhpExtensions as $extension => $purpose) {
125
            $this->checkPhpExtension($extension, false, $purpose);
126
        }
127
128
        $this->checkPcreVersion();
129
        $this->checkGdLibTrueColorSupport();
130
        $this->checkGdLibGifSupport();
131
        $this->checkGdLibJpgSupport();
132
        $this->checkGdLibPngSupport();
133
        $this->checkGdLibFreeTypeSupport();
134
135
        return $this->messageQueue;
136
    }
137
138
    /**
139
     * Checks if current directory (.) is in PHP include path
140
     */
141
    protected function checkCurrentDirectoryIsInIncludePath()
142
    {
143
        $includePath = (string)ini_get('include_path');
144
        $delimiter = $this->isWindowsOs() ? ';' : ':';
145
        $pathArray = $this->trimExplode($delimiter, $includePath);
146
        if (!in_array('.', $pathArray)) {
147
            $this->messageQueue->enqueue(new FlashMessage(
148
                'include_path = ' . implode(' ', $pathArray) . LF
149
                    . 'Normally the current path \'.\' is included in the'
150
                    . ' include_path of PHP. Although TYPO3 does not rely on this,'
151
                    . ' it is an unusual setting that may introduce problems for'
152
                    . ' some extensions.',
153
                'Current directory (./) is not within PHP include path',
154
                FlashMessage::WARNING
155
            ));
156
        } else {
157
            $this->messageQueue->enqueue(new FlashMessage(
158
                '',
159
                'Current directory (./) is within PHP include path.'
160
            ));
161
        }
162
    }
163
164
    /**
165
     * Check if file uploads are enabled in PHP
166
     */
167
    protected function checkFileUploadEnabled()
168
    {
169
        if (!ini_get('file_uploads')) {
170
            $this->messageQueue->enqueue(new FlashMessage(
171
                'file_uploads=' . ini_get('file_uploads') . LF
172
                    . 'TYPO3 uses the ability to upload files from the browser in various cases.'
173
                    . ' If this flag is disabled in PHP, you won\'t be able to upload files.'
174
                    . ' But it doesn\'t end here, because not only are files not accepted by'
175
                    . ' the server - ALL content in the forms are discarded and therefore'
176
                    . ' nothing at all will be editable if you don\'t set this flag!',
177
                'File uploads not allowed in PHP',
178
                FlashMessage::ERROR
179
            ));
180
        } else {
181
            $this->messageQueue->enqueue(new FlashMessage(
182
                '',
183
                'File uploads allowed in PHP'
184
            ));
185
        }
186
    }
187
188
    /**
189
     * Check maximum post upload size correlates with maximum file upload
190
     */
191
    protected function checkPostUploadSizeIsHigherOrEqualMaximumFileUploadSize()
192
    {
193
        $maximumUploadFilesize = $this->getBytesFromSizeMeasurement((string)ini_get('upload_max_filesize'));
194
        $maximumPostSize = $this->getBytesFromSizeMeasurement((string)ini_get('post_max_size'));
195
        if ($maximumPostSize > 0 && $maximumPostSize < $maximumUploadFilesize) {
196
            $this->messageQueue->enqueue(new FlashMessage(
197
                'upload_max_filesize=' . ini_get('upload_max_filesize') . LF
198
                    . 'post_max_size=' . ini_get('post_max_size') . LF
199
                    . 'You have defined a maximum size for file uploads in PHP which'
200
                    . ' exceeds the allowed size for POST requests. Therefore the'
201
                    . ' file uploads can also not be larger than ' . ini_get('post_max_size') . '.',
202
                'Maximum size for POST requests is smaller than maximum upload filesize in PHP',
203
                FlashMessage::ERROR
204
            ));
205
        } elseif ($maximumPostSize === $maximumUploadFilesize) {
206
            $this->messageQueue->enqueue(new FlashMessage(
207
                'The maximum size for file uploads is set to ' . ini_get('upload_max_filesize'),
208
                'Maximum post upload size correlates with maximum upload file size in PHP'
209
            ));
210
        } else {
211
            $this->messageQueue->enqueue(new FlashMessage(
212
                'The maximum size for file uploads is set to ' . ini_get('upload_max_filesize'),
213
                'Maximum post upload size is higher than maximum upload file size in PHP, which is fine.'
214
            ));
215
        }
216
    }
217
218
    /**
219
     * Check memory settings
220
     */
221
    protected function checkMemorySettings()
222
    {
223
        $minimumMemoryLimit = 64;
224
        $recommendedMemoryLimit = 128;
225
        $memoryLimit = $this->getBytesFromSizeMeasurement((string)ini_get('memory_limit'));
226
        if ($memoryLimit <= 0) {
227
            $this->messageQueue->enqueue(new FlashMessage(
228
                'PHP is configured not to limit memory usage at all. This is a risk'
229
                    . ' and should be avoided in production setup. In general it\'s best practice to limit this.'
230
                    . ' To be safe, set a limit in PHP, but with a minimum of ' . $recommendedMemoryLimit . 'MB:' . LF
231
                    . 'memory_limit=' . $recommendedMemoryLimit . 'M',
232
                'Unlimited memory limit for PHP',
233
                FlashMessage::WARNING
234
            ));
235
        } elseif ($memoryLimit < 1024 * 1024 * $minimumMemoryLimit) {
236
            $this->messageQueue->enqueue(new FlashMessage(
237
                'memory_limit=' . ini_get('memory_limit') . LF
238
                    . 'Your system is configured to enforce a memory limit for PHP scripts lower than '
239
                    . $minimumMemoryLimit . 'MB. It is required to raise the limit.'
240
                    . ' We recommend a minimum PHP memory limit of ' . $recommendedMemoryLimit . 'MB:' . LF
241
                    . 'memory_limit=' . $recommendedMemoryLimit . 'M',
242
                'PHP Memory limit below ' . $minimumMemoryLimit . 'MB',
243
                FlashMessage::ERROR
244
            ));
245
        } elseif ($memoryLimit < 1024 * 1024 * $recommendedMemoryLimit) {
246
            $this->messageQueue->enqueue(new FlashMessage(
247
                'memory_limit=' . ini_get('memory_limit') . LF
248
                    . 'Your system is configured to enforce a memory limit for PHP scripts lower than '
249
                    . $recommendedMemoryLimit . 'MB.'
250
                    . ' A slim TYPO3 instance without many extensions will probably work, but you should monitor your'
251
                    . ' system for "allowed memory size of X bytes exhausted" messages, especially if using the backend.'
252
                    . ' To be on the safe side, we recommend a minimum PHP memory limit of '
253
                    . $recommendedMemoryLimit . 'MB:' . LF
254
                    . 'memory_limit=' . $recommendedMemoryLimit . 'M',
255
                'PHP Memory limit below ' . $recommendedMemoryLimit . 'MB',
256
                FlashMessage::WARNING
257
            ));
258
        } else {
259
            $this->messageQueue->enqueue(new FlashMessage(
260
                '',
261
                'PHP Memory limit is equal to or more than ' . $recommendedMemoryLimit . 'MB'
262
            ));
263
        }
264
    }
265
266
    /**
267
     * Check minimum PHP version
268
     */
269
    protected function checkPhpVersion()
270
    {
271
        $minimumPhpVersion = '7.2.0';
272
        $currentPhpVersion = PHP_VERSION;
273
        if (version_compare($currentPhpVersion, $minimumPhpVersion) < 0) {
274
            $this->messageQueue->enqueue(new FlashMessage(
275
                'Your PHP version ' . $currentPhpVersion . ' is too old. TYPO3 CMS does not run'
276
                    . ' with this version. Update to at least PHP ' . $minimumPhpVersion,
277
                'PHP version too low',
278
                FlashMessage::ERROR
279
            ));
280
        } else {
281
            $this->messageQueue->enqueue(new FlashMessage(
282
                '',
283
                'PHP version is fine'
284
            ));
285
        }
286
    }
287
288
    /**
289
     * Check PRCE module is loaded and minimum version
290
     */
291
    protected function checkPcreVersion()
292
    {
293
        $minimumPcreVersion = '8.38';
294
        if (!extension_loaded('pcre')) {
295
            $this->messageQueue->enqueue(new FlashMessage(
296
                'TYPO3 CMS uses PHP extension pcre but it is not loaded'
297
                    . ' in your environment. Change your environment to provide this extension'
298
                    . ' in with minimum version ' . $minimumPcreVersion . '.',
299
                'PHP extension pcre not loaded',
300
                FlashMessage::ERROR
301
            ));
302
        } else {
303
            $installedPcreVersionString = trim(PCRE_VERSION); // '8.39 2016-06-14'
304
            $mainPcreVersionString = explode(' ', $installedPcreVersionString);
305
            $mainPcreVersionString = $mainPcreVersionString[0]; // '8.39'
306
            if (version_compare($mainPcreVersionString, $minimumPcreVersion) < 0) {
307
                $this->messageQueue->enqueue(new FlashMessage(
308
                    'Your PCRE version ' . PCRE_VERSION . ' is too old. TYPO3 CMS may trigger PHP segmentantion'
309
                        . ' faults with this version. Update to at least PCRE ' . $minimumPcreVersion,
310
                    'PCRE version too low',
311
                    FlashMessage::ERROR
312
                ));
313
            } else {
314
                $this->messageQueue->enqueue(new FlashMessage(
315
                    '',
316
                    'PHP extension PCRE is loaded and version is fine'
317
                ));
318
            }
319
        }
320
    }
321
322
    /**
323
     * Check maximum execution time
324
     */
325
    protected function checkMaxExecutionTime()
326
    {
327
        $minimumMaximumExecutionTime = 30;
328
        $recommendedMaximumExecutionTime = 240;
329
        $currentMaximumExecutionTime = ini_get('max_execution_time');
330
        if ($currentMaximumExecutionTime == 0) {
331
            $this->messageQueue->enqueue(new FlashMessage(
332
                'max_execution_time=0' . LF
333
                    . 'While TYPO3 is fine with this, you risk a denial-of-service for your system if for whatever'
334
                    . ' reason some script hangs in an infinite loop. You are usually on the safe side '
335
                    . ' if it is reduced to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF
336
                    . 'max_execution_time=' . $recommendedMaximumExecutionTime,
337
                'Infinite PHP script execution time',
338
                FlashMessage::WARNING
339
            ));
340
        } elseif ($currentMaximumExecutionTime < $minimumMaximumExecutionTime) {
341
            $this->messageQueue->enqueue(new FlashMessage(
342
                'max_execution_time=' . $currentMaximumExecutionTime . LF
343
                    . 'Your max_execution_time is too low. Some expensive operations in TYPO3 can take longer than that.'
344
                    . ' It is recommended to raise the limit to ' . $recommendedMaximumExecutionTime . ' seconds:' . LF
345
                    . 'max_execution_time=' . $recommendedMaximumExecutionTime,
346
                'Low PHP script execution time',
347
                FlashMessage::ERROR
348
            ));
349
        } elseif ($currentMaximumExecutionTime < $recommendedMaximumExecutionTime) {
350
            $this->messageQueue->enqueue(new FlashMessage(
351
                'max_execution_time=' . $currentMaximumExecutionTime . LF
352
                    . 'Your max_execution_time is low. While TYPO3 often runs without problems'
353
                    . ' with ' . $minimumMaximumExecutionTime . ' seconds,'
354
                    . ' it may still 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 . ' seconds:' . LF
357
                    . 'max_execution_time=' . $recommendedMaximumExecutionTime,
358
                'Low PHP script execution time',
359
                FlashMessage::WARNING
360
            ));
361
        } else {
362
            $this->messageQueue->enqueue(new FlashMessage(
363
                '',
364
                'Maximum PHP script execution time is equal to or more than ' . $recommendedMaximumExecutionTime
365
            ));
366
        }
367
    }
368
369
    /**
370
     * Check for disabled functions
371
     */
372
    protected function checkDisableFunctions()
373
    {
374
        $disabledFunctions = trim((string)ini_get('disable_functions'));
375
376
        // Filter "disable_functions"
377
        $disabledFunctionsArray = $this->trimExplode(',', $disabledFunctions);
378
379
        // Array with strings to find
380
        $findStrings = [
381
            // Disabled by default on Ubuntu OS but this is okay since the Core does not use them
382
            'pcntl_',
383
        ];
384
        foreach ($disabledFunctionsArray as $key => $disabledFunction) {
385
            foreach ($findStrings as $findString) {
386
                if (strpos($disabledFunction, $findString) !== false) {
387
                    unset($disabledFunctionsArray[$key]);
388
                }
389
            }
390
        }
391
392
        if ($disabledFunctions !== '') {
393
            if (!empty($disabledFunctionsArray)) {
394
                $this->messageQueue->enqueue(new FlashMessage(
395
                    'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF
396
                        . 'These function(s) are disabled. TYPO3 uses some of those, so there might be trouble.'
397
                        . ' TYPO3 is designed to use the default set of PHP functions plus some common extensions.'
398
                        . ' Possibly these functions are disabled'
399
                        . ' due to security considerations and most likely the list would include a function like'
400
                        . ' exec() which is used by TYPO3 at various places. Depending on which exact functions'
401
                        . ' are disabled, some parts of the system may just break without further notice.',
402
                    'Some PHP functions disabled',
403
                    FlashMessage::ERROR
404
                ));
405
            } else {
406
                $this->messageQueue->enqueue(new FlashMessage(
407
                    'disable_functions=' . implode(' ', explode(',', $disabledFunctions)) . LF
408
                        . 'These function(s) are disabled. TYPO3 uses currently none of those, so you are good to go.',
409
                    'Some PHP functions currently disabled but OK'
410
                ));
411
            }
412
        } else {
413
            $this->messageQueue->enqueue(new FlashMessage(
414
                '',
415
                'No disabled PHP functions'
416
            ));
417
        }
418
    }
419
420
    /**
421
     * Check for doc_root ini setting
422
     */
423
    protected function checkDocRoot()
424
    {
425
        $docRootSetting = trim((string)ini_get('doc_root'));
426
        if ($docRootSetting !== '') {
427
            $this->messageQueue->enqueue(new FlashMessage(
428
                'doc_root=' . $docRootSetting . LF
429
                    . 'PHP cannot execute scripts'
430
                    . ' outside this directory. This setting is seldom used and must correlate'
431
                    . ' with your actual document root. You might be in trouble if your'
432
                    . ' TYPO3 CMS core code is linked to some different location.'
433
                    . ' If that is a problem, the setting must be changed.',
434
                'doc_root is set',
435
                FlashMessage::NOTICE
436
            ));
437
        } else {
438
            $this->messageQueue->enqueue(new FlashMessage(
439
                '',
440
                'PHP doc_root is not set'
441
            ));
442
        }
443
    }
444
445
    /**
446
     * Check open_basedir
447
     */
448
    protected function checkOpenBaseDir()
449
    {
450
        $openBaseDirSetting = trim((string)ini_get('open_basedir'));
451
        if ($openBaseDirSetting !== '') {
452
            $this->messageQueue->enqueue(new FlashMessage(
453
                'open_basedir = ' . ini_get('open_basedir') . LF
454
                    . 'This restricts TYPO3 to open and include files only in this'
455
                    . ' path. Please make sure that this does not prevent TYPO3 from running,'
456
                    . ' if for example your TYPO3 CMS core is linked to a different directory'
457
                    . ' not included in this path.',
458
                'PHP open_basedir is set',
459
                FlashMessage::NOTICE
460
            ));
461
        } else {
462
            $this->messageQueue->enqueue(new FlashMessage(
463
                '',
464
                'PHP open_basedir is off'
465
            ));
466
        }
467
    }
468
469
    /**
470
     * If xdebug is loaded, the default max_nesting_level of 100 must be raised
471
     */
472
    protected function checkXdebugMaxNestingLevel()
473
    {
474
        if (extension_loaded('xdebug')) {
475
            $recommendedMaxNestingLevel = 400;
476
            $errorThreshold = 250;
477
            $currentMaxNestingLevel = ini_get('xdebug.max_nesting_level');
478
            if ($currentMaxNestingLevel < $errorThreshold) {
479
                $this->messageQueue->enqueue(new FlashMessage(
480
                    'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF
481
                        . 'This setting controls the maximum number of nested function calls to protect against'
482
                        . ' infinite recursion. The current value is too low for TYPO3 CMS and must'
483
                        . ' be either raised or xdebug has to be unloaded. A value of ' . $recommendedMaxNestingLevel
484
                        . ' is recommended. Warning: Expect fatal PHP errors in central parts of the CMS'
485
                        . ' if the value is not raised significantly to:' . LF
486
                        . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel,
487
                    'PHP xdebug.max_nesting_level is critically low',
488
                    FlashMessage::ERROR
489
                ));
490
            } elseif ($currentMaxNestingLevel < $recommendedMaxNestingLevel) {
491
                $this->messageQueue->enqueue(new FlashMessage(
492
                    'xdebug.max_nesting_level=' . $currentMaxNestingLevel . LF
493
                        . 'This setting controls the maximum number of nested function calls to protect against'
494
                        . ' infinite recursion. The current value is high enough for the TYPO3 CMS core to work'
495
                        . ' fine, but still some extensions could raise fatal PHP errors if the setting is not'
496
                        . ' raised further. A value of ' . $recommendedMaxNestingLevel . ' is recommended.' . LF
497
                        . 'xdebug.max_nesting_level=' . $recommendedMaxNestingLevel,
498
                    'PHP xdebug.max_nesting_level is low',
499
                    FlashMessage::WARNING
500
                ));
501
            } else {
502
                $this->messageQueue->enqueue(new FlashMessage(
503
                    '',
504
                    'PHP xdebug.max_nesting_level ok'
505
                ));
506
            }
507
        } else {
508
            $this->messageQueue->enqueue(new FlashMessage(
509
                '',
510
                'PHP xdebug extension not loaded'
511
            ));
512
        }
513
    }
514
515
    /**
516
     * Get max_input_vars status
517
     */
518
    protected function checkMaxInputVars()
519
    {
520
        $recommendedMaxInputVars = 1500;
521
        $minimumMaxInputVars = 1000;
522
        $currentMaxInputVars = ini_get('max_input_vars');
523
524
        if ($currentMaxInputVars < $minimumMaxInputVars) {
525
            $this->messageQueue->enqueue(new FlashMessage(
526
                'max_input_vars=' . $currentMaxInputVars . LF
527
                    . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS'
528
                    . ' (as the install tool does). It is highly recommended to raise this'
529
                    . ' to at least ' . $recommendedMaxInputVars . ':' . LF
530
                    . 'max_input_vars=' . $recommendedMaxInputVars,
531
                'PHP max_input_vars too low',
532
                FlashMessage::ERROR
533
            ));
534
        } elseif ($currentMaxInputVars < $recommendedMaxInputVars) {
535
            $this->messageQueue->enqueue(new FlashMessage(
536
                'max_input_vars=' . $currentMaxInputVars . LF
537
                    . 'This setting can lead to lost information if submitting forms with lots of data in TYPO3 CMS'
538
                    . ' (as the install tool does). It is highly recommended to raise this'
539
                    . ' to at least ' . $recommendedMaxInputVars . ':' . LF
540
                    . 'max_input_vars=' . $recommendedMaxInputVars,
541
                'PHP max_input_vars very low',
542
                FlashMessage::WARNING
543
            ));
544
        } else {
545
            $this->messageQueue->enqueue(new FlashMessage(
546
                '',
547
                'PHP max_input_vars ok'
548
            ));
549
        }
550
    }
551
552
    /**
553
     * Check doc comments can be fetched by reflection
554
     */
555
    protected function checkReflectionDocComment()
556
    {
557
        $testReflection = new \ReflectionMethod(static::class, __FUNCTION__);
558
        if ($testReflection->getDocComment() === false) {
559
            $this->messageQueue->enqueue(new FlashMessage(
560
                'TYPO3 CMS core extensions like extbase and fluid heavily rely on method'
561
                    . ' comment parsing to fetch annotations and add magic belonging to them.'
562
                    . ' This does not work in the current environment and so we cannot install'
563
                    . ' TYPO3 CMS.' . LF
564
                    . ' Here are some possibilities: ' . LF
565
                    . '* In Zend OPcache you can disable saving/loading comments. If you are using'
566
                    . ' Zend OPcache (included since PHP 5.5) then check your php.ini settings for'
567
                    . ' opcache.save_comments and opcache.load_comments and enable them.' . LF
568
                    . '* In Zend Optimizer+ you can disable saving comments. If you are using'
569
                    . ' Zend Optimizer+ then check your php.ini settings for'
570
                    . ' zend_optimizerplus.save_comments and enable it.' . LF
571
                    . '* The PHP extension eaccelerator is known to break this if'
572
                    . ' it is compiled without --with-eaccelerator-doc-comment-inclusion flag.'
573
                    . ' This compile flag must be specified, otherwise TYPO3 CMS will not work.' . LF
574
                    . 'For more information take a look in our wiki ' . Typo3Information::URL_OPCACHE . '.',
575
                'PHP Doc comment reflection broken',
576
                FlashMessage::ERROR
577
            ));
578
        } else {
579
            $this->messageQueue->enqueue(new FlashMessage(
580
                '',
581
                'PHP Doc comment reflection works'
582
            ));
583
        }
584
    }
585
586
    /**
587
     * Checks thread stack size if on windows with apache
588
     */
589
    protected function checkWindowsApacheThreadStackSize()
590
    {
591
        if ($this->isWindowsOs()
592
            && strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === 0
593
        ) {
594
            $this->messageQueue->enqueue(new FlashMessage(
595
                'This current value cannot be checked by the system, so please ignore this warning if it'
596
                    . ' is already taken care of: Fluid uses complex regular expressions which require a lot'
597
                    . ' of stack space during the first processing.'
598
                    . ' On Windows the default stack size for Apache is a lot smaller than on UNIX.'
599
                    . ' You can increase the size to 8MB (default on UNIX) by adding the following configuration'
600
                    . ' to httpd.conf and restarting Apache afterwards:' . LF
601
                    . '<IfModule mpm_winnt_module>ThreadStackSize 8388608</IfModule>',
602
                'Windows apache thread stack size',
603
                FlashMessage::WARNING
604
            ));
605
        } else {
606
            $this->messageQueue->enqueue(new FlashMessage(
607
                '',
608
                'Apache ThreadStackSize is not an issue on UNIX systems'
609
            ));
610
        }
611
    }
612
613
    /**
614
     * Checks if a specific PHP extension is loaded.
615
     *
616
     * @param string $extension
617
     * @param bool $required
618
     * @param string $purpose
619
     */
620
    public function checkPhpExtension(string $extension, bool $required = true, string $purpose = '')
621
    {
622
        if (!extension_loaded($extension)) {
623
            $this->messageQueue->enqueue(new FlashMessage(
624
                'TYPO3 uses the PHP extension "' . $extension . '" but it is not loaded'
625
                    . ' in your environment. Change your environment to provide this extension. '
626
                    . $purpose,
627
                'PHP extension "' . $extension . '" not loaded',
628
                $required ? FlashMessage::ERROR : FlashMessage::WARNING
629
            ));
630
        } else {
631
            $this->messageQueue->enqueue(new FlashMessage(
632
                '',
633
                'PHP extension "' . $extension . '" loaded'
634
            ));
635
        }
636
    }
637
638
    /**
639
     * Check imagecreatetruecolor to verify gdlib works as expected
640
     */
641
    protected function checkGdLibTrueColorSupport()
642
    {
643
        if (function_exists('imagecreatetruecolor')) {
644
            $imageResource = @imagecreatetruecolor(50, 100);
645
            if ($this->checkImageResource($imageResource)) {
646
                imagedestroy($imageResource);
0 ignored issues
show
Bug introduced by
It seems like $imageResource can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

646
                imagedestroy(/** @scrutinizer ignore-type */ $imageResource);
Loading history...
647
                $this->messageQueue->enqueue(new FlashMessage(
648
                    '',
649
                    'PHP GD library true color works'
650
                ));
651
            } else {
652
                $this->messageQueue->enqueue(new FlashMessage(
653
                    'GD is loaded, but calling imagecreatetruecolor() fails.'
654
                        . ' This must be fixed, TYPO3 CMS won\'t work well otherwise.',
655
                    'PHP GD library true color support broken',
656
                    FlashMessage::ERROR
657
                ));
658
            }
659
        } else {
660
            $this->messageQueue->enqueue(new FlashMessage(
661
                'Gdlib is essential for TYPO3 CMS to work properly.',
662
                'PHP GD library true color support missing',
663
                FlashMessage::ERROR
664
            ));
665
        }
666
    }
667
668
    /**
669
     * Check gif support of GD library
670
     */
671
    protected function checkGdLibGifSupport()
672
    {
673
        if (function_exists('imagecreatefromgif')
674
            && function_exists('imagegif')
675
            && (imagetypes() & IMG_GIF)
676
        ) {
677
            // Do not use data:// wrapper to be independent of allow_url_fopen
678
            $imageResource = @imagecreatefromgif(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.gif');
679
            if ($this->checkImageResource($imageResource)) {
680
                imagedestroy($imageResource);
0 ignored issues
show
Bug introduced by
It seems like $imageResource can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

680
                imagedestroy(/** @scrutinizer ignore-type */ $imageResource);
Loading history...
681
                $this->messageQueue->enqueue(new FlashMessage(
682
                    '',
683
                    'PHP GD library has gif support'
684
                ));
685
            } else {
686
                $this->messageQueue->enqueue(new FlashMessage(
687
                    'GD is loaded, but calling imagecreatefromgif() fails. This must be fixed, TYPO3 CMS won\'t work well otherwise.',
688
                    'PHP GD library gif support broken',
689
                    FlashMessage::ERROR
690
                ));
691
            }
692
        } else {
693
            $this->messageQueue->enqueue(new FlashMessage(
694
                'GD must be compiled with gif support. This is essential for TYPO3 CMS to work properly.',
695
                'PHP GD library gif support missing',
696
                FlashMessage::ERROR
697
            ));
698
        }
699
    }
700
701
    /**
702
     * Check jpg support of GD library
703
     */
704
    protected function checkGdLibJpgSupport()
705
    {
706
        if (function_exists('imagecreatefromjpeg')
707
            && function_exists('imagejpeg')
708
            && (imagetypes() & IMG_JPG)
709
        ) {
710
            $this->messageQueue->enqueue(new FlashMessage(
711
                '',
712
                'PHP GD library has jpg support'
713
            ));
714
        } else {
715
            $this->messageQueue->enqueue(new FlashMessage(
716
                'GD must be compiled with jpg support. This is essential for TYPO3 CMS to work properly.',
717
                'PHP GD library jpg support missing',
718
                FlashMessage::ERROR
719
            ));
720
        }
721
    }
722
723
    /**
724
     * Check png support of GD library
725
     */
726
    protected function checkGdLibPngSupport()
727
    {
728
        if (function_exists('imagecreatefrompng')
729
            && function_exists('imagepng')
730
            && (imagetypes() & IMG_PNG)
731
        ) {
732
            // Do not use data:// wrapper to be independent of allow_url_fopen
733
            $imageResource = @imagecreatefrompng(__DIR__ . '/../../Resources/Public/Images/TestInput/Test.png');
734
            if ($this->checkImageResource($imageResource)) {
735
                imagedestroy($imageResource);
0 ignored issues
show
Bug introduced by
It seems like $imageResource can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

735
                imagedestroy(/** @scrutinizer ignore-type */ $imageResource);
Loading history...
736
                $this->messageQueue->enqueue(new FlashMessage(
737
                    '',
738
                    'PHP GD library has png support'
739
                ));
740
            } else {
741
                $this->messageQueue->enqueue(new FlashMessage(
742
                    'GD is compiled with png support, but calling imagecreatefrompng() fails.'
743
                        . ' Check your environment and fix it, png in GD lib is important'
744
                        . ' for TYPO3 CMS to work properly.',
745
                    'PHP GD library png support broken',
746
                    FlashMessage::ERROR
747
                ));
748
            }
749
        } else {
750
            $this->messageQueue->enqueue(new FlashMessage(
751
                'GD must be compiled with png support. This is essential for TYPO3 CMS to work properly',
752
                'PHP GD library png support missing',
753
                FlashMessage::ERROR
754
            ));
755
        }
756
    }
757
758
    /**
759
     * Check gdlib supports freetype
760
     */
761
    protected function checkGdLibFreeTypeSupport()
762
    {
763
        if (function_exists('imagettftext')) {
764
            $this->messageQueue->enqueue(new FlashMessage(
765
                'There is a difference between the font size setting which the GD'
766
                    . ' library should be supplied  with. If installation is completed'
767
                    . ' a test in the install tool helps to find out the value you need.',
768
                'PHP GD library has freetype font support'
769
            ));
770
        } else {
771
            $this->messageQueue->enqueue(new FlashMessage(
772
                'Some core functionality and extension rely on the GD'
773
                    . ' to render fonts on images. This support is missing'
774
                    . ' in your environment. Install it.',
775
                'PHP GD library freetype support missing',
776
                FlashMessage::ERROR
777
            ));
778
        }
779
    }
780
781
    /**
782
     * Helper methods
783
     */
784
785
    /**
786
     * Validate a given IP address.
787
     *
788
     * @param string $ip IP address to be tested
789
     * @return bool
790
     */
791
    protected function isValidIp($ip)
792
    {
793
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
794
    }
795
796
    /**
797
     * Test if this instance runs on windows OS
798
     *
799
     * @return bool TRUE if operating system is windows
800
     */
801
    protected function isWindowsOs()
802
    {
803
        $windowsOs = false;
804
        if (stripos(PHP_OS, 'darwin') === false && stripos(PHP_OS, 'win') !== false) {
805
            $windowsOs = true;
806
        }
807
        return $windowsOs;
808
    }
809
810
    /**
811
     * Helper method to explode a string by delimiter and throw away empty values.
812
     * Removes empty values from result array.
813
     *
814
     * @param string $delimiter Delimiter string to explode with
815
     * @param string $string The string to explode
816
     * @return array Exploded values
817
     */
818
    protected function trimExplode($delimiter, $string)
819
    {
820
        $explodedValues = explode($delimiter, $string);
821
        $explodedValues = is_array($explodedValues) ? $explodedValues : [];
0 ignored issues
show
introduced by
The condition is_array($explodedValues) is always true.
Loading history...
822
        $resultWithPossibleEmptyValues = array_map('trim', $explodedValues);
823
        $result = [];
824
        foreach ($resultWithPossibleEmptyValues as $value) {
825
            if ($value !== '') {
826
                $result[] = $value;
827
            }
828
        }
829
        return $result;
830
    }
831
832
    /**
833
     * Helper method to get the bytes value from a measurement string like "100k".
834
     *
835
     * @param string $measurement The measurement (e.g. "100k")
836
     * @return int The bytes value (e.g. 102400)
837
     */
838
    protected function getBytesFromSizeMeasurement($measurement)
839
    {
840
        $bytes = (float)$measurement;
841
        if (stripos($measurement, 'G')) {
842
            $bytes *= 1024 * 1024 * 1024;
843
        } elseif (stripos($measurement, 'M')) {
844
            $bytes *= 1024 * 1024;
845
        } elseif (stripos($measurement, 'K')) {
846
            $bytes *= 1024;
847
        }
848
        return (int)$bytes;
849
    }
850
851
    private function checkImageResource($imageResource): bool
852
    {
853
        return is_resource($imageResource) || (PHP_MAJOR_VERSION >= 8 && $imageResource instanceof \GdImage);
0 ignored issues
show
Bug introduced by
The type GdImage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
854
    }
855
}
856