Issues (30)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

var/SymfonyRequirements.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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);
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
    /**
172
     * @var Requirement[]
173
     */
174
    private $requirements = array();
175
176
    /**
177
     * Gets the current RequirementCollection as an Iterator.
178
     *
179
     * @return Traversable A Traversable interface
180
     */
181
    public function getIterator()
182
    {
183
        return new ArrayIterator($this->requirements);
184
    }
185
186
    /**
187
     * Adds a Requirement.
188
     *
189
     * @param Requirement $requirement A Requirement instance
190
     */
191
    public function add(Requirement $requirement)
192
    {
193
        $this->requirements[] = $requirement;
194
    }
195
196
    /**
197
     * Adds a mandatory requirement.
198
     *
199
     * @param bool        $fulfilled   Whether the requirement is fulfilled
200
     * @param string      $testMessage The message for testing the requirement
201
     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
202
     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
203
     */
204
    public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
205
    {
206
        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
207
    }
208
209
    /**
210
     * Adds an optional recommendation.
211
     *
212
     * @param bool        $fulfilled   Whether the recommendation is fulfilled
213
     * @param string      $testMessage The message for testing the recommendation
214
     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
215
     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
216
     */
217
    public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
218
    {
219
        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
220
    }
221
222
    /**
223
     * Adds a mandatory requirement in form of a php.ini configuration.
224
     *
225
     * @param string        $cfgName           The configuration name used for ini_get()
226
     * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false,
227
     *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
228
     * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
229
     *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
230
     *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
231
     * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
0 ignored issues
show
Should the type for parameter $testMessage not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
232
     * @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)
0 ignored issues
show
Should the type for parameter $helpHtml not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
233
     * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
234
     */
235
    public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
236
    {
237
        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
238
    }
239
240
    /**
241
     * Adds an optional recommendation in form of a php.ini configuration.
242
     *
243
     * @param string        $cfgName           The configuration name used for ini_get()
244
     * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false,
245
     *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
246
     * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
247
     *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
248
     *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
249
     * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
0 ignored issues
show
Should the type for parameter $testMessage not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
250
     * @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)
0 ignored issues
show
Should the type for parameter $helpHtml not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
251
     * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
252
     */
253
    public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
254
    {
255
        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
256
    }
257
258
    /**
259
     * Adds a requirement collection to the current set of requirements.
260
     *
261
     * @param RequirementCollection $collection A RequirementCollection instance
262
     */
263
    public function addCollection(RequirementCollection $collection)
264
    {
265
        $this->requirements = array_merge($this->requirements, $collection->all());
266
    }
267
268
    /**
269
     * Returns both requirements and recommendations.
270
     *
271
     * @return Requirement[]
272
     */
273
    public function all()
274
    {
275
        return $this->requirements;
276
    }
277
278
    /**
279
     * Returns all mandatory requirements.
280
     *
281
     * @return Requirement[]
282
     */
283
    public function getRequirements()
284
    {
285
        $array = array();
286
        foreach ($this->requirements as $req) {
287
            if (!$req->isOptional()) {
288
                $array[] = $req;
289
            }
290
        }
291
292
        return $array;
293
    }
294
295
    /**
296
     * Returns the mandatory requirements that were not met.
297
     *
298
     * @return Requirement[]
299
     */
300
    public function getFailedRequirements()
301
    {
302
        $array = array();
303
        foreach ($this->requirements as $req) {
304
            if (!$req->isFulfilled() && !$req->isOptional()) {
305
                $array[] = $req;
306
            }
307
        }
308
309
        return $array;
310
    }
311
312
    /**
313
     * Returns all optional recommendations.
314
     *
315
     * @return Requirement[]
316
     */
317
    public function getRecommendations()
318
    {
319
        $array = array();
320
        foreach ($this->requirements as $req) {
321
            if ($req->isOptional()) {
322
                $array[] = $req;
323
            }
324
        }
325
326
        return $array;
327
    }
328
329
    /**
330
     * Returns the recommendations that were not met.
331
     *
332
     * @return Requirement[]
333
     */
334
    public function getFailedRecommendations()
335
    {
336
        $array = array();
337
        foreach ($this->requirements as $req) {
338
            if (!$req->isFulfilled() && $req->isOptional()) {
339
                $array[] = $req;
340
            }
341
        }
342
343
        return $array;
344
    }
345
346
    /**
347
     * Returns whether a php.ini configuration is not correct.
348
     *
349
     * @return bool php.ini configuration problem?
350
     */
351
    public function hasPhpIniConfigIssue()
352
    {
353
        foreach ($this->requirements as $req) {
354
            if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
355
                return true;
356
            }
357
        }
358
359
        return false;
360
    }
361
362
    /**
363
     * Returns the PHP configuration file (php.ini) path.
364
     *
365
     * @return string|false php.ini file path
366
     */
367
    public function getPhpIniConfigPath()
368
    {
369
        return get_cfg_var('cfg_file_path');
370
    }
371
}
372
373
/**
374
 * This class specifies all requirements and optional recommendations that
375
 * are necessary to run the Symfony Standard Edition.
376
 *
377
 * @author Tobias Schultze <http://tobion.de>
378
 * @author Fabien Potencier <[email protected]>
379
 */
380
class SymfonyRequirements extends RequirementCollection
381
{
382
    const LEGACY_REQUIRED_PHP_VERSION = '5.3.3';
383
    const REQUIRED_PHP_VERSION = '5.5.9';
384
385
    /**
386
     * Constructor that initializes the requirements.
387
     */
388
    public function __construct()
389
    {
390
        /* mandatory requirements follow */
391
392
        $installedPhpVersion = PHP_VERSION;
393
        $requiredPhpVersion = $this->getPhpRequiredVersion();
394
395
        $this->addRecommendation(
396
            $requiredPhpVersion,
397
            'Vendors should be installed in order to check all requirements.',
398
            'Run the <code>composer install</code> command.',
399
            'Run the "composer install" command.'
400
        );
401
402
        if (false !== $requiredPhpVersion) {
403
            $this->addRequirement(
404
                version_compare($installedPhpVersion, $requiredPhpVersion, '>='),
405
                sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion),
406
                sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
407
                Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
408
                    $installedPhpVersion, $requiredPhpVersion),
409
                sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion)
410
            );
411
        }
412
413
        $this->addRequirement(
414
            version_compare($installedPhpVersion, '5.3.16', '!='),
415
            'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
416
            'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
417
        );
418
419
        $this->addRequirement(
420
            is_dir(__DIR__.'/../vendor/composer'),
421
            'Vendor libraries must be installed',
422
            'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. '.
423
                'Then run "<strong>php composer.phar install</strong>" to install them.'
424
        );
425
426
        $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache';
427
428
        $this->addRequirement(
429
            is_writable($cacheDir),
430
            'app/cache/ or var/cache/ directory must be writable',
431
            'Change the permissions of either "<strong>app/cache/</strong>" or  "<strong>var/cache/</strong>" directory so that the web server can write into it.'
432
        );
433
434
        $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs';
435
436
        $this->addRequirement(
437
            is_writable($logsDir),
438
            'app/logs/ or var/logs/ directory must be writable',
439
            'Change the permissions of either "<strong>app/logs/</strong>" or  "<strong>var/logs/</strong>" directory so that the web server can write into it.'
440
        );
441
442
        if (version_compare($installedPhpVersion, '7.0.0', '<')) {
443
            $this->addPhpIniRequirement(
444
                'date.timezone', true, false,
445
                'date.timezone setting must be set',
446
                'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
447
            );
448
        }
449
450
        if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) {
451
            $this->addRequirement(
452
                in_array(@date_default_timezone_get(), DateTimeZone::listIdentifiers(), true),
453
                sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
454
                '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>.'
455
            );
456
        }
457
458
        $this->addRequirement(
459
            function_exists('iconv'),
460
            'iconv() must be available',
461
            'Install and enable the <strong>iconv</strong> extension.'
462
        );
463
464
        $this->addRequirement(
465
            function_exists('json_encode'),
466
            'json_encode() must be available',
467
            'Install and enable the <strong>JSON</strong> extension.'
468
        );
469
470
        $this->addRequirement(
471
            function_exists('session_start'),
472
            'session_start() must be available',
473
            'Install and enable the <strong>session</strong> extension.'
474
        );
475
476
        $this->addRequirement(
477
            function_exists('ctype_alpha'),
478
            'ctype_alpha() must be available',
479
            'Install and enable the <strong>ctype</strong> extension.'
480
        );
481
482
        $this->addRequirement(
483
            function_exists('token_get_all'),
484
            'token_get_all() must be available',
485
            'Install and enable the <strong>Tokenizer</strong> extension.'
486
        );
487
488
        $this->addRequirement(
489
            function_exists('simplexml_import_dom'),
490
            'simplexml_import_dom() must be available',
491
            'Install and enable the <strong>SimpleXML</strong> extension.'
492
        );
493
494
        if (function_exists('apc_store') && ini_get('apc.enabled')) {
495
            if (version_compare($installedPhpVersion, '5.4.0', '>=')) {
496
                $this->addRequirement(
497
                    version_compare(phpversion('apc'), '3.1.13', '>='),
498
                    'APC version must be at least 3.1.13 when using PHP 5.4',
499
                    'Upgrade your <strong>APC</strong> extension (3.1.13+).'
500
                );
501
            } else {
502
                $this->addRequirement(
503
                    version_compare(phpversion('apc'), '3.0.17', '>='),
504
                    'APC version must be at least 3.0.17',
505
                    'Upgrade your <strong>APC</strong> extension (3.0.17+).'
506
                );
507
            }
508
        }
509
510
        $this->addPhpIniRequirement('detect_unicode', false);
511
512
        if (extension_loaded('suhosin')) {
513
            $this->addPhpIniRequirement(
514
                'suhosin.executor.include.whitelist',
515
                create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
516
                false,
517
                'suhosin.executor.include.whitelist must be configured correctly in php.ini',
518
                'Add "<strong>phar</strong>" to <strong>suhosin.executor.include.whitelist</strong> in php.ini<a href="#phpini">*</a>.'
519
            );
520
        }
521
522
        if (extension_loaded('xdebug')) {
523
            $this->addPhpIniRequirement(
524
                'xdebug.show_exception_trace', false, true
525
            );
526
527
            $this->addPhpIniRequirement(
528
                'xdebug.scream', false, true
529
            );
530
531
            $this->addPhpIniRecommendation(
532
                'xdebug.max_nesting_level',
533
                create_function('$cfgValue', 'return $cfgValue > 100;'),
534
                true,
535
                'xdebug.max_nesting_level should be above 100 in php.ini',
536
                '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.'
537
            );
538
        }
539
540
        $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
541
542
        $this->addRequirement(
543
            null !== $pcreVersion,
544
            'PCRE extension must be available',
545
            'Install the <strong>PCRE</strong> extension (version 8.0+).'
546
        );
547
548
        if (extension_loaded('mbstring')) {
549
            $this->addPhpIniRequirement(
550
                'mbstring.func_overload',
551
                create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
552
                true,
553
                'string functions should not be overloaded',
554
                '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.'
555
            );
556
        }
557
558
        /* optional recommendations follow */
559
560
        if (file_exists(__DIR__.'/../vendor/composer')) {
561
            require_once __DIR__.'/../vendor/autoload.php';
562
563
            try {
564
                $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
565
566
                $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
567
            } catch (ReflectionException $e) {
568
                $contents = '';
569
            }
570
            $this->addRecommendation(
571
                file_get_contents(__FILE__) === $contents,
572
                'Requirements file should be up-to-date',
573
                'Your requirements file is outdated. Run composer install and re-check your configuration.'
574
            );
575
        }
576
577
        $this->addRecommendation(
578
            version_compare($installedPhpVersion, '5.3.4', '>='),
579
            'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
580
            '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.'
581
        );
582
583
        $this->addRecommendation(
584
            version_compare($installedPhpVersion, '5.3.8', '>='),
585
            'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
586
            'Install PHP 5.3.8 or newer if your project uses annotations.'
587
        );
588
589
        $this->addRecommendation(
590
            version_compare($installedPhpVersion, '5.4.0', '!='),
591
            'You should not use PHP 5.4.0 due to the PHP bug #61453',
592
            '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.'
593
        );
594
595
        $this->addRecommendation(
596
            version_compare($installedPhpVersion, '5.4.11', '>='),
597
            '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)',
598
            'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.'
599
        );
600
601
        $this->addRecommendation(
602
            (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<'))
603
            ||
604
            version_compare($installedPhpVersion, '5.4.8', '>='),
605
            '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',
606
            'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.'
607
        );
608
609
        if (null !== $pcreVersion) {
610
            $this->addRecommendation(
611
                $pcreVersion >= 8.0,
612
                sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
613
                '<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.'
614
            );
615
        }
616
617
        $this->addRecommendation(
618
            class_exists('DomDocument'),
619
            'PHP-DOM and PHP-XML modules should be installed',
620
            'Install and enable the <strong>PHP-DOM</strong> and the <strong>PHP-XML</strong> modules.'
621
        );
622
623
        $this->addRecommendation(
624
            function_exists('mb_strlen'),
625
            'mb_strlen() should be available',
626
            'Install and enable the <strong>mbstring</strong> extension.'
627
        );
628
629
        $this->addRecommendation(
630
            function_exists('utf8_decode'),
631
            'utf8_decode() should be available',
632
            'Install and enable the <strong>XML</strong> extension.'
633
        );
634
635
        $this->addRecommendation(
636
            function_exists('filter_var'),
637
            'filter_var() should be available',
638
            'Install and enable the <strong>filter</strong> extension.'
639
        );
640
641
        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
642
            $this->addRecommendation(
643
                function_exists('posix_isatty'),
644
                'posix_isatty() should be available',
645
                'Install and enable the <strong>php_posix</strong> extension (used to colorize the CLI output).'
646
            );
647
        }
648
649
        $this->addRecommendation(
650
            extension_loaded('intl'),
651
            'intl extension should be available',
652
            'Install and enable the <strong>intl</strong> extension (used for validators).'
653
        );
654
655
        if (extension_loaded('intl')) {
656
            // in some WAMP server installations, new Collator() returns null
657
            $this->addRecommendation(
658
                null !== new Collator('fr_FR'),
659
                'intl extension should be correctly configured',
660
                'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
661
            );
662
663
            // check for compatible ICU versions (only done when you have the intl extension)
664
            if (defined('INTL_ICU_VERSION')) {
665
                $version = INTL_ICU_VERSION;
666
            } else {
667
                $reflector = new ReflectionExtension('intl');
668
669
                ob_start();
670
                $reflector->info();
671
                $output = strip_tags(ob_get_clean());
672
673
                preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
674
                $version = $matches[1];
675
            }
676
677
            $this->addRecommendation(
678
                version_compare($version, '4.0', '>='),
679
                'intl ICU version should be at least 4+',
680
                'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).'
681
            );
682
683
            if (class_exists('Symfony\Component\Intl\Intl')) {
684
                $this->addRecommendation(
685
                    \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(),
686
                    sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
687
                    'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.'
688
                );
689
                if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) {
690
                    $this->addRecommendation(
691
                        \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(),
692
                        sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
693
                        'To avoid internationalization data inconsistencies upgrade the symfony/intl component.'
694
                    );
695
                }
696
            }
697
698
            $this->addPhpIniRecommendation(
699
                'intl.error_level',
700
                create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
701
                true,
702
                'intl.error_level should be 0 in php.ini',
703
                '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.'
704
            );
705
        }
706
707
        $accelerator =
708
            (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'))
709
            ||
710
            (extension_loaded('apc') && ini_get('apc.enabled'))
711
            ||
712
            (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable'))
713
            ||
714
            (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
715
            ||
716
            (extension_loaded('xcache') && ini_get('xcache.cacher'))
717
            ||
718
            (extension_loaded('wincache') && ini_get('wincache.ocenabled'))
719
        ;
720
721
        $this->addRecommendation(
722
            $accelerator,
723
            'a PHP accelerator should be installed',
724
            'Install and/or enable a <strong>PHP accelerator</strong> (highly recommended).'
725
        );
726
727
        if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
728
            $this->addRecommendation(
729
                $this->getRealpathCacheSize() >= 5 * 1024 * 1024,
730
                'realpath_cache_size should be at least 5M in php.ini',
731
                'Setting "<strong>realpath_cache_size</strong>" to e.g. "<strong>5242880</strong>" or "<strong>5M</strong>" in php.ini<a href="#phpini">*</a> may improve performance on Windows significantly in some cases.'
732
            );
733
        }
734
735
        $this->addPhpIniRecommendation('short_open_tag', false);
736
737
        $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
738
739
        $this->addPhpIniRecommendation('register_globals', false, true);
740
741
        $this->addPhpIniRecommendation('session.auto_start', false);
742
743
        $this->addRecommendation(
744
            class_exists('PDO'),
745
            'PDO should be installed',
746
            'Install <strong>PDO</strong> (mandatory for Doctrine).'
747
        );
748
749
        if (class_exists('PDO')) {
750
            $drivers = PDO::getAvailableDrivers();
751
            $this->addRecommendation(
752
                count($drivers) > 0,
753
                sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
754
                'Install <strong>PDO drivers</strong> (mandatory for Doctrine).'
755
            );
756
        }
757
    }
758
759
    /**
760
     * Loads realpath_cache_size from php.ini and converts it to int.
761
     *
762
     * (e.g. 16k is converted to 16384 int)
763
     *
764
     * @return int
0 ignored issues
show
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
765
     */
766
    protected function getRealpathCacheSize()
767
    {
768
        $size = ini_get('realpath_cache_size');
769
        $size = trim($size);
770
        $unit = '';
771
        if (!ctype_digit($size)) {
772
            $unit = strtolower(substr($size, -1, 1));
773
            $size = (int) substr($size, 0, -1);
774
        }
775
        switch ($unit) {
776
            case 'g':
777
                return $size * 1024 * 1024 * 1024;
778
            case 'm':
779
                return $size * 1024 * 1024;
780
            case 'k':
781
                return $size * 1024;
782
            default:
783
                return (int) $size;
784
        }
785
    }
786
787
    /**
788
     * Defines PHP required version from Symfony version.
789
     *
790
     * @return string|false The PHP required version or false if it could not be guessed
791
     */
792
    protected function getPhpRequiredVersion()
793
    {
794
        if (!file_exists($path = __DIR__.'/../composer.lock')) {
795
            return false;
796
        }
797
798
        $composerLock = json_decode(file_get_contents($path), true);
799
        foreach ($composerLock['packages'] as $package) {
800
            $name = $package['name'];
801
            if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) {
802
                continue;
803
            }
804
805
            return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION;
806
        }
807
808
        return false;
809
    }
810
}
811