SymfonyRequirements::__construct()   F
last analyzed

Complexity

Conditions 35
Paths > 20000

Size

Total Lines 353
Code Lines 231

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 35
eloc 231
c 0
b 0
f 0
nc 7004160
nop 0
dl 0
loc 353
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
/*
13
 * Users of PHP 5.2 should be able to run the requirements checks.
14
 * This is why the file and all classes must be compatible with PHP 5.2+
15
 * (e.g. not using namespaces and closures).
16
 *
17
 * ************** CAUTION **************
18
 *
19
 * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of
20
 * the installation/update process. The original file resides in the
21
 * SensioDistributionBundle.
22
 *
23
 * ************** CAUTION **************
24
 */
25
26
/**
27
 * Represents a single PHP requirement, e.g. an installed extension.
28
 * It can be a mandatory requirement or an optional recommendation.
29
 * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration.
30
 *
31
 * @author Tobias Schultze <http://tobion.de>
32
 */
33
class Requirement
34
{
35
    private $fulfilled;
36
    private $testMessage;
37
    private $helpText;
38
    private $helpHtml;
39
    private $optional;
40
41
    /**
42
     * Constructor that initializes the requirement.
43
     *
44
     * @param bool        $fulfilled   Whether the requirement is fulfilled
45
     * @param string      $testMessage The message for testing the requirement
46
     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
47
     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
48
     * @param bool        $optional    Whether this is only an optional recommendation not a mandatory requirement
49
     */
50
    public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false)
51
    {
52
        $this->fulfilled = (bool) $fulfilled;
53
        $this->testMessage = (string) $testMessage;
54
        $this->helpHtml = (string) $helpHtml;
55
        $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText;
56
        $this->optional = (bool) $optional;
57
    }
58
59
    /**
60
     * Returns whether the requirement is fulfilled.
61
     *
62
     * @return bool true if fulfilled, otherwise false
63
     */
64
    public function isFulfilled()
65
    {
66
        return $this->fulfilled;
67
    }
68
69
    /**
70
     * Returns the message for testing the requirement.
71
     *
72
     * @return string The test message
73
     */
74
    public function getTestMessage()
75
    {
76
        return $this->testMessage;
77
    }
78
79
    /**
80
     * Returns the help text for resolving the problem.
81
     *
82
     * @return string The help text
83
     */
84
    public function getHelpText()
85
    {
86
        return $this->helpText;
87
    }
88
89
    /**
90
     * Returns the help text formatted in HTML.
91
     *
92
     * @return string The HTML help
93
     */
94
    public function getHelpHtml()
95
    {
96
        return $this->helpHtml;
97
    }
98
99
    /**
100
     * Returns whether this is only an optional recommendation and not a mandatory requirement.
101
     *
102
     * @return bool true if optional, false if mandatory
103
     */
104
    public function isOptional()
105
    {
106
        return $this->optional;
107
    }
108
}
109
110
/**
111
 * Represents a PHP requirement in form of a php.ini configuration.
112
 *
113
 * @author Tobias Schultze <http://tobion.de>
114
 */
115
class PhpIniRequirement extends Requirement
116
{
117
    /**
118
     * Constructor that initializes the requirement.
119
     *
120
     * @param string        $cfgName           The configuration name used for ini_get()
121
     * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false,
122
     *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
123
     * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
124
     *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
125
     *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
126
     * @param string|null   $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
127
     * @param string|null   $helpHtml          The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
128
     * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
129
     * @param bool          $optional          Whether this is only an optional recommendation not a mandatory requirement
130
     */
131
    public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false)
132
    {
133
        $cfgValue = ini_get($cfgName);
134
135
        if (is_callable($evaluation)) {
136
            if (null === $testMessage || null === $helpHtml) {
137
                throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.');
138
            }
139
140
            $fulfilled = call_user_func($evaluation, $cfgValue);
0 ignored issues
show
Bug introduced by
It seems like $evaluation can also be of type boolean; however, parameter $function of call_user_func() does only seem to accept callable, 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

140
            $fulfilled = call_user_func(/** @scrutinizer ignore-type */ $evaluation, $cfgValue);
Loading history...
141
        } else {
142
            if (null === $testMessage) {
143
                $testMessage = sprintf('%s %s be %s in php.ini',
144
                    $cfgName,
145
                    $optional ? 'should' : 'must',
146
                    $evaluation ? 'enabled' : 'disabled'
147
                );
148
            }
149
150
            if (null === $helpHtml) {
151
                $helpHtml = sprintf('Set <strong>%s</strong> to <strong>%s</strong> in php.ini<a href="#phpini">*</a>.',
152
                    $cfgName,
153
                    $evaluation ? 'on' : 'off'
154
                );
155
            }
156
157
            $fulfilled = $evaluation == $cfgValue;
158
        }
159
160
        parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional);
161
    }
162
}
163
164
/**
165
 * A RequirementCollection represents a set of Requirement instances.
166
 *
167
 * @author Tobias Schultze <http://tobion.de>
168
 */
169
class RequirementCollection implements IteratorAggregate
170
{
171
    private $requirements = array();
172
173
    /**
174
     * Gets the current RequirementCollection as an Iterator.
175
     *
176
     * @return Traversable A Traversable interface
177
     */
178
    public function getIterator()
179
    {
180
        return new ArrayIterator($this->requirements);
181
    }
182
183
    /**
184
     * Adds a Requirement.
185
     *
186
     * @param Requirement $requirement A Requirement instance
187
     */
188
    public function add(Requirement $requirement)
189
    {
190
        $this->requirements[] = $requirement;
191
    }
192
193
    /**
194
     * Adds a mandatory requirement.
195
     *
196
     * @param bool        $fulfilled   Whether the requirement is fulfilled
197
     * @param string      $testMessage The message for testing the requirement
198
     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
199
     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
200
     */
201
    public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
202
    {
203
        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
204
    }
205
206
    /**
207
     * Adds an optional recommendation.
208
     *
209
     * @param bool        $fulfilled   Whether the recommendation is fulfilled
210
     * @param string      $testMessage The message for testing the recommendation
211
     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
212
     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
213
     */
214
    public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
215
    {
216
        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
217
    }
218
219
    /**
220
     * Adds a mandatory requirement in form of a php.ini configuration.
221
     *
222
     * @param string        $cfgName           The configuration name used for ini_get()
223
     * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false,
224
     *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
225
     * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
226
     *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
227
     *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
228
     * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
229
     * @param string        $helpHtml          The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
230
     * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
231
     */
232
    public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
233
    {
234
        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
235
    }
236
237
    /**
238
     * Adds an optional recommendation in form of a php.ini configuration.
239
     *
240
     * @param string        $cfgName           The configuration name used for ini_get()
241
     * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false,
242
     *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
243
     * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
244
     *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
245
     *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
246
     * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
247
     * @param string        $helpHtml          The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
248
     * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
249
     */
250
    public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
251
    {
252
        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
253
    }
254
255
    /**
256
     * Adds a requirement collection to the current set of requirements.
257
     *
258
     * @param RequirementCollection $collection A RequirementCollection instance
259
     */
260
    public function addCollection(RequirementCollection $collection)
261
    {
262
        $this->requirements = array_merge($this->requirements, $collection->all());
263
    }
264
265
    /**
266
     * Returns both requirements and recommendations.
267
     *
268
     * @return array Array of Requirement instances
269
     */
270
    public function all()
271
    {
272
        return $this->requirements;
273
    }
274
275
    /**
276
     * Returns all mandatory requirements.
277
     *
278
     * @return array Array of Requirement instances
279
     */
280
    public function getRequirements()
281
    {
282
        $array = array();
283
        foreach ($this->requirements as $req) {
284
            if (!$req->isOptional()) {
285
                $array[] = $req;
286
            }
287
        }
288
289
        return $array;
290
    }
291
292
    /**
293
     * Returns the mandatory requirements that were not met.
294
     *
295
     * @return array Array of Requirement instances
296
     */
297
    public function getFailedRequirements()
298
    {
299
        $array = array();
300
        foreach ($this->requirements as $req) {
301
            if (!$req->isFulfilled() && !$req->isOptional()) {
302
                $array[] = $req;
303
            }
304
        }
305
306
        return $array;
307
    }
308
309
    /**
310
     * Returns all optional recommendations.
311
     *
312
     * @return array Array of Requirement instances
313
     */
314
    public function getRecommendations()
315
    {
316
        $array = array();
317
        foreach ($this->requirements as $req) {
318
            if ($req->isOptional()) {
319
                $array[] = $req;
320
            }
321
        }
322
323
        return $array;
324
    }
325
326
    /**
327
     * Returns the recommendations that were not met.
328
     *
329
     * @return array Array of Requirement instances
330
     */
331
    public function getFailedRecommendations()
332
    {
333
        $array = array();
334
        foreach ($this->requirements as $req) {
335
            if (!$req->isFulfilled() && $req->isOptional()) {
336
                $array[] = $req;
337
            }
338
        }
339
340
        return $array;
341
    }
342
343
    /**
344
     * Returns whether a php.ini configuration is not correct.
345
     *
346
     * @return bool php.ini configuration problem?
347
     */
348
    public function hasPhpIniConfigIssue()
349
    {
350
        foreach ($this->requirements as $req) {
351
            if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
352
                return true;
353
            }
354
        }
355
356
        return false;
357
    }
358
359
    /**
360
     * Returns the PHP configuration file (php.ini) path.
361
     *
362
     * @return string|false php.ini file path
363
     */
364
    public function getPhpIniConfigPath()
365
    {
366
        return get_cfg_var('cfg_file_path');
367
    }
368
}
369
370
/**
371
 * This class specifies all requirements and optional recommendations that
372
 * are necessary to run the Symfony Standard Edition.
373
 *
374
 * @author Tobias Schultze <http://tobion.de>
375
 * @author Fabien Potencier <[email protected]>
376
 */
377
class SymfonyRequirements extends RequirementCollection
378
{
379
    const REQUIRED_PHP_VERSION = '5.3.3';
380
381
    /**
382
     * Constructor that initializes the requirements.
383
     */
384
    public function __construct()
385
    {
386
        /* mandatory requirements follow */
387
388
        $installedPhpVersion = phpversion();
389
390
        $this->addRequirement(
391
            version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='),
392
            sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion),
393
            sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
394
                Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
395
                $installedPhpVersion, self::REQUIRED_PHP_VERSION),
396
            sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion)
397
        );
398
399
        $this->addRequirement(
400
            version_compare($installedPhpVersion, '5.3.16', '!='),
401
            'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
402
            'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
403
        );
404
405
        $this->addRequirement(
406
            is_dir(__DIR__.'/../vendor/composer'),
407
            'Vendor libraries must be installed',
408
            'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. '.
409
                'Then run "<strong>php composer.phar install</strong>" to install them.'
410
        );
411
412
        $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache';
413
414
        $this->addRequirement(
415
            is_writable($cacheDir),
416
            'app/cache/ or var/cache/ directory must be writable',
417
            'Change the permissions of either "<strong>app/cache/</strong>" or  "<strong>var/cache/</strong>" directory so that the web server can write into it.'
418
        );
419
420
        $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs';
421
422
        $this->addRequirement(
423
            is_writable($logsDir),
424
            'app/logs/ or var/logs/ directory must be writable',
425
            'Change the permissions of either "<strong>app/logs/</strong>" or  "<strong>var/logs/</strong>" directory so that the web server can write into it.'
426
        );
427
428
        $this->addPhpIniRequirement(
429
            'date.timezone', true, false,
430
            'date.timezone setting must be set',
431
            'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
432
        );
433
434
        if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
435
            $timezones = array();
436
            foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
437
                foreach ($abbreviations as $abbreviation) {
438
                    $timezones[$abbreviation['timezone_id']] = true;
439
                }
440
            }
441
442
            $this->addRequirement(
443
                isset($timezones[@date_default_timezone_get()]),
444
                sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
445
                'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.'
446
            );
447
        }
448
449
        $this->addRequirement(
450
            function_exists('iconv'),
451
            'iconv() must be available',
452
            'Install and enable the <strong>iconv</strong> extension.'
453
        );
454
455
        $this->addRequirement(
456
            function_exists('json_encode'),
457
            'json_encode() must be available',
458
            'Install and enable the <strong>JSON</strong> extension.'
459
        );
460
461
        $this->addRequirement(
462
            function_exists('session_start'),
463
            'session_start() must be available',
464
            'Install and enable the <strong>session</strong> extension.'
465
        );
466
467
        $this->addRequirement(
468
            function_exists('ctype_alpha'),
469
            'ctype_alpha() must be available',
470
            'Install and enable the <strong>ctype</strong> extension.'
471
        );
472
473
        $this->addRequirement(
474
            function_exists('token_get_all'),
475
            'token_get_all() must be available',
476
            'Install and enable the <strong>Tokenizer</strong> extension.'
477
        );
478
479
        $this->addRequirement(
480
            function_exists('simplexml_import_dom'),
481
            'simplexml_import_dom() must be available',
482
            'Install and enable the <strong>SimpleXML</strong> extension.'
483
        );
484
485
        if (function_exists('apc_store') && ini_get('apc.enabled')) {
486
            if (version_compare($installedPhpVersion, '5.4.0', '>=')) {
487
                $this->addRequirement(
488
                    version_compare(phpversion('apc'), '3.1.13', '>='),
489
                    'APC version must be at least 3.1.13 when using PHP 5.4',
490
                    'Upgrade your <strong>APC</strong> extension (3.1.13+).'
491
                );
492
            } else {
493
                $this->addRequirement(
494
                    version_compare(phpversion('apc'), '3.0.17', '>='),
495
                    'APC version must be at least 3.0.17',
496
                    'Upgrade your <strong>APC</strong> extension (3.0.17+).'
497
                );
498
            }
499
        }
500
501
        $this->addPhpIniRequirement('detect_unicode', false);
502
503
        if (extension_loaded('suhosin')) {
504
            $this->addPhpIniRequirement(
505
                'suhosin.executor.include.whitelist',
506
                create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
0 ignored issues
show
Deprecated Code introduced by
The function create_function() has been deprecated: 7.2 ( Ignorable by Annotation )

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

506
                /** @scrutinizer ignore-deprecated */ create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
507
                false,
508
                'suhosin.executor.include.whitelist must be configured correctly in php.ini',
509
                'Add "<strong>phar</strong>" to <strong>suhosin.executor.include.whitelist</strong> in php.ini<a href="#phpini">*</a>.'
510
            );
511
        }
512
513
        if (extension_loaded('xdebug')) {
514
            $this->addPhpIniRequirement(
515
                'xdebug.show_exception_trace', false, true
516
            );
517
518
            $this->addPhpIniRequirement(
519
                'xdebug.scream', false, true
520
            );
521
522
            $this->addPhpIniRecommendation(
523
                'xdebug.max_nesting_level',
524
                create_function('$cfgValue', 'return $cfgValue > 100;'),
0 ignored issues
show
Deprecated Code introduced by
The function create_function() has been deprecated: 7.2 ( Ignorable by Annotation )

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

524
                /** @scrutinizer ignore-deprecated */ create_function('$cfgValue', 'return $cfgValue > 100;'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
525
                true,
526
                'xdebug.max_nesting_level should be above 100 in php.ini',
527
                'Set "<strong>xdebug.max_nesting_level</strong>" to e.g. "<strong>250</strong>" in php.ini<a href="#phpini">*</a> to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.'
528
            );
529
        }
530
531
        $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
532
533
        $this->addRequirement(
534
            null !== $pcreVersion,
535
            'PCRE extension must be available',
536
            'Install the <strong>PCRE</strong> extension (version 8.0+).'
537
        );
538
539
        if (extension_loaded('mbstring')) {
540
            $this->addPhpIniRequirement(
541
                'mbstring.func_overload',
542
                create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
0 ignored issues
show
Deprecated Code introduced by
The function create_function() has been deprecated: 7.2 ( Ignorable by Annotation )

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

542
                /** @scrutinizer ignore-deprecated */ create_function('$cfgValue', 'return (int) $cfgValue === 0;'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
543
                true,
544
                'string functions should not be overloaded',
545
                'Set "<strong>mbstring.func_overload</strong>" to <strong>0</strong> in php.ini<a href="#phpini">*</a> to disable function overloading by the mbstring extension.'
546
            );
547
        }
548
549
        /* optional recommendations follow */
550
551
        if (file_exists(__DIR__.'/../vendor/composer')) {
552
            require_once __DIR__.'/../vendor/autoload.php';
553
554
            try {
555
                $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
556
557
                $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
558
            } catch (ReflectionException $e) {
559
                $contents = '';
560
            }
561
            $this->addRecommendation(
562
                file_get_contents(__FILE__) === $contents,
563
                'Requirements file should be up-to-date',
564
                'Your requirements file is outdated. Run composer install and re-check your configuration.'
565
            );
566
        }
567
568
        $this->addRecommendation(
569
            version_compare($installedPhpVersion, '5.3.4', '>='),
570
            'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
571
            'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.'
572
        );
573
574
        $this->addRecommendation(
575
            version_compare($installedPhpVersion, '5.3.8', '>='),
576
            'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
577
            'Install PHP 5.3.8 or newer if your project uses annotations.'
578
        );
579
580
        $this->addRecommendation(
581
            version_compare($installedPhpVersion, '5.4.0', '!='),
582
            'You should not use PHP 5.4.0 due to the PHP bug #61453',
583
            'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.'
584
        );
585
586
        $this->addRecommendation(
587
            version_compare($installedPhpVersion, '5.4.11', '>='),
588
            'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)',
589
            'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.'
590
        );
591
592
        $this->addRecommendation(
593
            (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<'))
594
            ||
595
            version_compare($installedPhpVersion, '5.4.8', '>='),
596
            'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909',
597
            'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.'
598
        );
599
600
        if (null !== $pcreVersion) {
601
            $this->addRecommendation(
602
                $pcreVersion >= 8.0,
603
                sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
604
                '<strong>PCRE 8.0+</strong> is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.'
605
            );
606
        }
607
608
        $this->addRecommendation(
609
            class_exists('DomDocument'),
610
            'PHP-DOM and PHP-XML modules should be installed',
611
            'Install and enable the <strong>PHP-DOM</strong> and the <strong>PHP-XML</strong> modules.'
612
        );
613
614
        $this->addRecommendation(
615
            function_exists('mb_strlen'),
616
            'mb_strlen() should be available',
617
            'Install and enable the <strong>mbstring</strong> extension.'
618
        );
619
620
        $this->addRecommendation(
621
            function_exists('iconv'),
622
            'iconv() should be available',
623
            'Install and enable the <strong>iconv</strong> extension.'
624
        );
625
626
        $this->addRecommendation(
627
            function_exists('utf8_decode'),
628
            'utf8_decode() should be available',
629
            'Install and enable the <strong>XML</strong> extension.'
630
        );
631
632
        $this->addRecommendation(
633
            function_exists('filter_var'),
634
            'filter_var() should be available',
635
            'Install and enable the <strong>filter</strong> extension.'
636
        );
637
638
        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
639
            $this->addRecommendation(
640
                function_exists('posix_isatty'),
641
                'posix_isatty() should be available',
642
                'Install and enable the <strong>php_posix</strong> extension (used to colorize the CLI output).'
643
            );
644
        }
645
646
        $this->addRecommendation(
647
            extension_loaded('intl'),
648
            'intl extension should be available',
649
            'Install and enable the <strong>intl</strong> extension (used for validators).'
650
        );
651
652
        if (extension_loaded('intl')) {
653
            // in some WAMP server installations, new Collator() returns null
654
            $this->addRecommendation(
655
                null !== new Collator('fr_FR'),
656
                'intl extension should be correctly configured',
657
                'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
658
            );
659
660
            // check for compatible ICU versions (only done when you have the intl extension)
661
            if (defined('INTL_ICU_VERSION')) {
662
                $version = INTL_ICU_VERSION;
663
            } else {
664
                $reflector = new ReflectionExtension('intl');
665
666
                ob_start();
667
                $reflector->info();
668
                $output = strip_tags(ob_get_clean());
669
670
                preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
671
                $version = $matches[1];
672
            }
673
674
            $this->addRecommendation(
675
                version_compare($version, '4.0', '>='),
676
                'intl ICU version should be at least 4+',
677
                'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).'
678
            );
679
680
            $this->addPhpIniRecommendation(
681
                'intl.error_level',
682
                create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
0 ignored issues
show
Deprecated Code introduced by
The function create_function() has been deprecated: 7.2 ( Ignorable by Annotation )

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

682
                /** @scrutinizer ignore-deprecated */ create_function('$cfgValue', 'return (int) $cfgValue === 0;'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
683
                true,
684
                'intl.error_level should be 0 in php.ini',
685
                'Set "<strong>intl.error_level</strong>" to "<strong>0</strong>" in php.ini<a href="#phpini">*</a> to inhibit the messages when an error occurs in ICU functions.'
686
            );
687
        }
688
689
        $accelerator =
690
            (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'))
691
            ||
692
            (extension_loaded('apc') && ini_get('apc.enabled'))
693
            ||
694
            (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable'))
695
            ||
696
            (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
697
            ||
698
            (extension_loaded('xcache') && ini_get('xcache.cacher'))
699
            ||
700
            (extension_loaded('wincache') && ini_get('wincache.ocenabled'))
701
        ;
702
703
        $this->addRecommendation(
704
            $accelerator,
705
            'a PHP accelerator should be installed',
706
            'Install and/or enable a <strong>PHP accelerator</strong> (highly recommended).'
707
        );
708
709
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
710
            $this->addRecommendation(
711
                $this->getRealpathCacheSize() > 1000,
712
                'realpath_cache_size should be above 1024 in php.ini',
713
                'Set "<strong>realpath_cache_size</strong>" to e.g. "<strong>1024</strong>" in php.ini<a href="#phpini">*</a> to improve performance on windows.'
714
            );
715
        }
716
717
        $this->addPhpIniRecommendation('short_open_tag', false);
718
719
        $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
720
721
        $this->addPhpIniRecommendation('register_globals', false, true);
722
723
        $this->addPhpIniRecommendation('session.auto_start', false);
724
725
        $this->addRecommendation(
726
            class_exists('PDO'),
727
            'PDO should be installed',
728
            'Install <strong>PDO</strong> (mandatory for Doctrine).'
729
        );
730
731
        if (class_exists('PDO')) {
732
            $drivers = PDO::getAvailableDrivers();
733
            $this->addRecommendation(
734
                count($drivers) > 0,
735
                sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
736
                'Install <strong>PDO drivers</strong> (mandatory for Doctrine).'
737
            );
738
        }
739
    }
740
741
    /**
742
     * Loads realpath_cache_size from php.ini and converts it to int.
743
     *
744
     * (e.g. 16k is converted to 16384 int)
745
     *
746
     * @return int
747
     */
748
    protected function getRealpathCacheSize()
749
    {
750
        $size = ini_get('realpath_cache_size');
751
        $size = trim($size);
752
        $unit = strtolower(substr($size, -1, 1));
753
        switch ($unit) {
754
            case 'g':
755
                return $size * 1024 * 1024 * 1024;
756
            case 'm':
757
                return $size * 1024 * 1024;
758
            case 'k':
759
                return $size * 1024;
760
            default:
761
                return (int) $size;
762
        }
763
    }
764
}
765