├── .gitignore ├── SensioDistributionBundle.php ├── Resources ├── config │ └── security.xml ├── bin │ ├── build_bootstrap.php │ ├── build_demo.sh │ └── build.sh └── skeleton │ ├── app │ ├── check.php │ └── SymfonyRequirements.php │ └── web │ └── config.php ├── UPGRADE.md ├── composer.json ├── DependencyInjection └── SensioDistributionExtension.php ├── LICENSE ├── README.rst └── Composer └── ScriptHandler.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | /vendor/ 3 | 4 | -------------------------------------------------------------------------------- /SensioDistributionBundle.php: -------------------------------------------------------------------------------- 1 | 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 | namespace Sensio\Bundle\DistributionBundle; 13 | 14 | use Symfony\Component\HttpKernel\Bundle\Bundle; 15 | 16 | /** 17 | * SensioDistributionBundle. 18 | * 19 | * @author Fabien Potencier 20 | * @author Marc Weistroff 21 | * @author Jérôme Vieilledent 22 | */ 23 | class SensioDistributionBundle extends Bundle 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Resources/config/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | UPGRADE FROM 4.0 to 5.0 2 | ======================= 3 | 4 | * The web configurator got removed. So you need to remove the `_configurator` 5 | routing entry from `app/config/routing_dev.yml`. 6 | 7 | * The generated `app/bootstrap.php.cache` does not include autoloading anymore. 8 | So you need to add the autoloading code in your front controllers `web/app.php`, 9 | `web/app_dev.php`, `app/console` and `app/phpunit.xml.dist` (bootstrap config). 10 | 11 | * If you have been using the Symfony 3 directory structure already, you need to 12 | overwrite the cache and log directories in your `AppKernel` as it is also done 13 | in Symfony 3 now (see 14 | [`app/AppKernel.php`](https://github.com/symfony/symfony-standard/blob/3.3/app/AppKernel.php#L40-L48)). 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sensio/distribution-bundle", 3 | "description": "Base bundle for Symfony Distributions", 4 | "keywords": ["distribution","configuration"], 5 | "type": "symfony-bundle", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Fabien Potencier", 10 | "email": "fabien@symfony.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.3.9", 15 | "symfony/dependency-injection": "~2.3|~3.0", 16 | "symfony/config": "~2.3|~3.0", 17 | "symfony/filesystem": "~2.3|~3.0", 18 | "symfony/http-kernel": "~2.3|~3.0", 19 | "symfony/class-loader": "~2.3|~3.0", 20 | "symfony/process": "~2.3|~3.0", 21 | "sensiolabs/security-checker": "~5.0|~6.0" 22 | }, 23 | "autoload": { 24 | "psr-4": { "Sensio\\Bundle\\DistributionBundle\\": "" } 25 | }, 26 | "extra": { 27 | "branch-alias": { 28 | "dev-master": "5.0.x-dev" 29 | } 30 | }, 31 | "minimum-stability": "dev" 32 | } 33 | -------------------------------------------------------------------------------- /DependencyInjection/SensioDistributionExtension.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class SensioDistributionExtension extends Extension 16 | { 17 | public function load(array $configs, ContainerBuilder $container) 18 | { 19 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 20 | 21 | $loader->load('security.xml'); 22 | } 23 | 24 | public function getNamespace() 25 | { 26 | return 'http://symfony.com/schema/dic/symfony/sensiodistribution'; 27 | } 28 | 29 | public function getAlias() 30 | { 31 | return 'sensio_distribution'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2017 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | SensioDistributionBundle 2 | ======================== 3 | 4 | **WARNING**: This bundle does not support Symfony 4. Symfony Flex is a total replacement for this bundle. 5 | 6 | SensioDistributionBundle provides useful developer features that can be re-used 7 | amongst several Symfony Distributions. 8 | 9 | Composer Hooks 10 | -------------- 11 | 12 | The bundle hooks up into the Composer process to automate the following actions 13 | when running an install or an update: 14 | 15 | * Update the ``bootstrap.php.cache`` file (and clears the cache); 16 | 17 | * Install the assets under the web root directory; 18 | 19 | * Update the requirements file. 20 | 21 | Security 22 | -------- 23 | 24 | The bundle includes the SensioLabs Security Checker. When included in a Symfony 25 | application, the check is available: 26 | 27 | .. code-block:: bash 28 | 29 | // In Symfony 2.x 30 | $ ./app/console security:check 31 | 32 | // As of Symfony 2.8 and 3.x 33 | $ ./bin/console security:check 34 | 35 | Contributing 36 | ------------ 37 | 38 | To contribute to this bundle, you just need a GitHub account. 39 | If you need some help to start, you can check the `Symfony guidelines`_ and `code style conventions`_. 40 | Bug fixes should be submitted against the 4.0 branch when possible, and new features are accepted on master only. 41 | 42 | Pull requests are welcome! 43 | 44 | .. _Symfony guidelines: https://symfony.com/doc/current/contributing/code/patches.html 45 | .. _code style conventions: https://symfony.com/doc/current/contributing/code/standards.html 46 | -------------------------------------------------------------------------------- /Resources/bin/build_bootstrap.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | use Sensio\Bundle\DistributionBundle\Composer\ScriptHandler; 14 | 15 | if (PHP_SAPI !== 'cli') { 16 | echo 'Warning: '.__FILE__.' should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL; 17 | } 18 | 19 | function getRealpath($path, $message = 'Directory %s does not seem to be valid.') 20 | { 21 | if (!$path = realpath($path)) { 22 | exit(sprintf($message, $path)); 23 | } 24 | 25 | return $path; 26 | } 27 | 28 | $argv = $_SERVER['argv']; 29 | $autoloadDir = $bootstrapDir = null; 30 | $useNewDirectoryStructure = false; 31 | 32 | // allow the base path to be passed as the first argument, or default 33 | if (!empty($argv[1])) { 34 | $bootstrapDir = getRealpath($argv[1]); 35 | } 36 | 37 | if (!empty($argv[2])) { 38 | $autoloadDir = getRealpath($argv[2]); 39 | } 40 | 41 | if (!empty($argv[3])) { 42 | $useNewDirectoryStructure = true; 43 | } 44 | 45 | $rootDir = __DIR__.'/../../../../..'; 46 | if (null === $autoloadDir) { 47 | $autoloadDir = getRealpath($rootDir.'/app', 'Looks like you don\'t have a standard layout.'); 48 | } 49 | if (null === $bootstrapDir) { 50 | $bootstrapDir = $autoloadDir; 51 | if ($useNewDirectoryStructure) { 52 | $bootstrapDir = getRealpath($rootDir.'/var'); 53 | } 54 | } 55 | 56 | require_once $autoloadDir.'/autoload.php'; 57 | 58 | // here we pass realpaths as resolution between absolute and relative path can be wrong 59 | ScriptHandler::doBuildBootstrap($bootstrapDir); 60 | -------------------------------------------------------------------------------- /Resources/bin/build_demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This file is part of the Symfony Standard Edition. 4 | # 5 | # (c) Fabien Potencier 6 | # 7 | # For the full copyright and license information, please view the LICENSE 8 | # file that was distributed with this source code. 9 | 10 | if [ ! $1 ]; then 11 | echo "\033[37;41mYou must pass the build dir as an absolute path\033[0m" 12 | exit 1 13 | fi 14 | 15 | DIR=$1 16 | CURRENT=`php -r "echo realpath(dirname(\\$_SERVER['argv'][0]));"` 17 | 18 | if [[ ! "$DIR" = /* ]]; then 19 | DIR="$CURRENT/$DIR" 20 | fi 21 | 22 | if [ ! -d $DIR ]; then 23 | echo "\033[37;41mThe build dir does not exist\033[0m" 24 | exit 1 25 | fi 26 | 27 | # avoid the creation of ._* files 28 | export COPY_EXTENDED_ATTRIBUTES_DISABLE=true 29 | export COPYFILE_DISABLE=true 30 | 31 | # Prepare temp. dir 32 | rm -rf /tmp/Symfony 33 | mkdir /tmp/Symfony 34 | 35 | # Clone demo application and install its dependencies 36 | git clone https://github.com/symfony/symfony-demo /tmp/Symfony 37 | cd /tmp/Symfony 38 | composer install --prefer-dist --no-interaction --ignore-platform-reqs --no-plugins --optimize-autoloader 39 | 40 | # cleanup 41 | cd /tmp/Symfony 42 | rm -f UPGRADE* 43 | mv .gitignore keep.gitignore 44 | rm -rf app/cache/* app/logs/* .git* 45 | mv keep.gitignore .gitignore 46 | chmod 777 app/cache app/logs 47 | find . -name .DS_Store | xargs rm -rf - 48 | 49 | # remove unneded dependencies files 50 | cd /tmp/Symfony 51 | TARGET=/tmp/Symfony/vendor 52 | 53 | # Doctrine 54 | cd $TARGET/doctrine/orm && rm -rf UPGRADE* build* bin tests tools lib/vendor 55 | cd $TARGET/doctrine/dbal && rm -rf bin build* tests lib/vendor 56 | cd $TARGET/doctrine/common && rm -rf build* tests lib/vendor 57 | if [ -d $TARGET/doctrine/doctrine-bundle/Doctrine/Bundle/DoctrineBundle ]; then 58 | cd $TARGET/doctrine/doctrine-bundle/Doctrine/Bundle/DoctrineBundle && rm -rf Tests Resources/doc 59 | else 60 | cd $TARGET/doctrine/doctrine-bundle && rm -rf Tests Resources/doc 61 | fi 62 | 63 | # kriswallsmith 64 | cd $TARGET/kriswallsmith/assetic && rm -rf CHANGELOG* phpunit.xml* tests docs 65 | 66 | # Monolog 67 | cd $TARGET/monolog/monolog && rm -rf README.markdown phpunit.xml* tests 68 | 69 | # Sensio 70 | cd $TARGET/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 71 | cd $TARGET/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 72 | cd $TARGET/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 73 | 74 | # Swiftmailer 75 | cd $TARGET/swiftmailer/swiftmailer && rm -rf CHANGES README* build* docs notes test-suite tests create_pear_package.php package* 76 | 77 | # Symfony 78 | cd $TARGET/symfony/symfony && rm -rf README.md phpunit.xml* tests *.sh vendor 79 | 80 | if [ -d $TARGET/symfony/assetic-bundle/Symfony/Bundle/AsseticBundle ]; then 81 | cd $TARGET/symfony/assetic-bundle/Symfony/Bundle/AsseticBundle && rm -rf Tests Resources/doc 82 | else 83 | cd $TARGET/symfony/assetic-bundle && rm -rf Tests Resources/doc 84 | fi 85 | 86 | if [ -d $TARGET/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle ]; then 87 | cd $TARGET/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle && rm -rf Tests Resources/doc 88 | else 89 | cd $TARGET/symfony/swiftmailer-bundle && rm -rf Tests Resources/doc 90 | fi 91 | 92 | if [ -d $TARGET/symfony/monolog-bundle/Symfony/Bundle/MonologBundle ]; then 93 | cd $TARGET/symfony/monolog-bundle/Symfony/Bundle/MonologBundle && rm -rf Tests Resources/doc 94 | else 95 | cd $TARGET/symfony/monolog-bundle && rm -rf Tests Resources/doc 96 | fi 97 | 98 | # Twig 99 | cd $TARGET/twig/twig && rm -rf AUTHORS CHANGELOG README.markdown bin doc package.xml.tpl phpunit.xml* test 100 | cd $TARGET/twig/extensions && rm -rf README doc phpunit.xml* test 101 | 102 | # final cleanup 103 | find $TARGET -name .git | xargs rm -rf - 104 | find $TARGET -name .gitignore | xargs rm -rf - 105 | find $TARGET -name .gitmodules | xargs rm -rf - 106 | find $TARGET -name .svn | xargs rm -rf - 107 | 108 | # build ZIP and TGZ packages 109 | cd /tmp 110 | tar zcpf $DIR/Symfony_Demo.tgz Symfony 111 | rm -f $DIR/Symfony_Demo.zip 112 | zip -rq $DIR/Symfony_Demo.zip Symfony 113 | -------------------------------------------------------------------------------- /Resources/skeleton/app/check.php: -------------------------------------------------------------------------------- 1 | getPhpIniConfigPath(); 8 | 9 | echo_title('Symfony Requirements Checker'); 10 | 11 | echo '> PHP is using the following php.ini file:'.PHP_EOL; 12 | if ($iniPath) { 13 | echo_style('green', ' '.$iniPath); 14 | } else { 15 | echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!'); 16 | } 17 | 18 | echo PHP_EOL.PHP_EOL; 19 | 20 | echo '> Checking Symfony requirements:'.PHP_EOL.' '; 21 | 22 | $messages = array(); 23 | foreach ($symfonyRequirements->getRequirements() as $req) { 24 | if ($helpText = get_error_message($req, $lineSize)) { 25 | echo_style('red', 'E'); 26 | $messages['error'][] = $helpText; 27 | } else { 28 | echo_style('green', '.'); 29 | } 30 | } 31 | 32 | $checkPassed = empty($messages['error']); 33 | 34 | foreach ($symfonyRequirements->getRecommendations() as $req) { 35 | if ($helpText = get_error_message($req, $lineSize)) { 36 | echo_style('yellow', 'W'); 37 | $messages['warning'][] = $helpText; 38 | } else { 39 | echo_style('green', '.'); 40 | } 41 | } 42 | 43 | if ($checkPassed) { 44 | echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); 45 | } else { 46 | echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); 47 | 48 | echo_title('Fix the following mandatory requirements', 'red'); 49 | 50 | foreach ($messages['error'] as $helpText) { 51 | echo ' * '.$helpText.PHP_EOL; 52 | } 53 | } 54 | 55 | if (!empty($messages['warning'])) { 56 | echo_title('Optional recommendations to improve your setup', 'yellow'); 57 | 58 | foreach ($messages['warning'] as $helpText) { 59 | echo ' * '.$helpText.PHP_EOL; 60 | } 61 | } 62 | 63 | echo PHP_EOL; 64 | echo_style('title', 'Note'); 65 | echo ' The command console could use a different php.ini file'.PHP_EOL; 66 | echo_style('title', '~~~~'); 67 | echo ' than the one used with your web server. To be on the'.PHP_EOL; 68 | echo ' safe side, please check the requirements from your web'.PHP_EOL; 69 | echo ' server using the '; 70 | echo_style('yellow', 'web/config.php'); 71 | echo ' script.'.PHP_EOL; 72 | echo PHP_EOL; 73 | 74 | exit($checkPassed ? 0 : 1); 75 | 76 | function get_error_message(Requirement $requirement, $lineSize) 77 | { 78 | if ($requirement->isFulfilled()) { 79 | return; 80 | } 81 | 82 | $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; 83 | $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; 84 | 85 | return $errorMessage; 86 | } 87 | 88 | function echo_title($title, $style = null) 89 | { 90 | $style = $style ?: 'title'; 91 | 92 | echo PHP_EOL; 93 | echo_style($style, $title.PHP_EOL); 94 | echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); 95 | echo PHP_EOL; 96 | } 97 | 98 | function echo_style($style, $message) 99 | { 100 | // ANSI color codes 101 | $styles = array( 102 | 'reset' => "\033[0m", 103 | 'red' => "\033[31m", 104 | 'green' => "\033[32m", 105 | 'yellow' => "\033[33m", 106 | 'error' => "\033[37;41m", 107 | 'success' => "\033[37;42m", 108 | 'title' => "\033[34m", 109 | ); 110 | $supports = has_color_support(); 111 | 112 | echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); 113 | } 114 | 115 | function echo_block($style, $title, $message) 116 | { 117 | $message = ' '.trim($message).' '; 118 | $width = strlen($message); 119 | 120 | echo PHP_EOL.PHP_EOL; 121 | 122 | echo_style($style, str_repeat(' ', $width)); 123 | echo PHP_EOL; 124 | echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT)); 125 | echo PHP_EOL; 126 | echo_style($style, $message); 127 | echo PHP_EOL; 128 | echo_style($style, str_repeat(' ', $width)); 129 | echo PHP_EOL; 130 | } 131 | 132 | function has_color_support() 133 | { 134 | static $support; 135 | 136 | if (null === $support) { 137 | if (DIRECTORY_SEPARATOR == '\\') { 138 | $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); 139 | } else { 140 | $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); 141 | } 142 | } 143 | 144 | return $support; 145 | } 146 | -------------------------------------------------------------------------------- /Resources/bin/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This file is part of the Symfony Standard Edition. 4 | # 5 | # (c) Fabien Potencier 6 | # 7 | # For the full copyright and license information, please view the LICENSE 8 | # file that was distributed with this source code. 9 | 10 | if [ ! $1 ]; then 11 | echo "\033[37;41mYou must pass the build dir as an absolute path\033[0m" 12 | exit 1 13 | fi 14 | 15 | if [ ! $2 ]; then 16 | echo "\033[37;41mYou must pass the version to build\033[0m" 17 | exit 1 18 | fi 19 | 20 | DIR=$1 21 | CURRENT=`php -r "echo realpath(dirname(\\$_SERVER['argv'][0]));"` 22 | 23 | if [[ ! "$DIR" = /* ]]; then 24 | DIR="$CURRENT/$DIR" 25 | fi 26 | 27 | if [ ! -d $DIR ]; then 28 | echo "\033[37;41mThe build dir does not exist\033[0m" 29 | exit 1 30 | fi 31 | 32 | # avoid the creation of ._* files 33 | export COPY_EXTENDED_ATTRIBUTES_DISABLE=true 34 | export COPYFILE_DISABLE=true 35 | 36 | # Temp dir 37 | rm -rf /tmp/Symfony 38 | mkdir /tmp/Symfony 39 | 40 | # Create project 41 | composer create-project --prefer-dist --no-interaction symfony/framework-standard-edition /tmp/Symfony $2 42 | 43 | if [ 0 -ne $? ]; then 44 | echo "\033[37;41mVersion $2 does not exist\033[0m" 45 | exit 1 46 | fi 47 | 48 | cd /tmp/Symfony 49 | 50 | # cleanup 51 | rm -rf app/cache/* app/logs/* var/cache/* var/logs/* 52 | chmod 777 app/cache app/logs var/cache var/logs 53 | find . -name .DS_Store | xargs rm -rf - 54 | 55 | VERSION=`grep ' VERSION ' vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php | sed -E "s/.*'(.+)'.*/\1/g"` 56 | 57 | # With vendors 58 | cd /tmp/Symfony 59 | TARGET=/tmp/Symfony/vendor 60 | 61 | # Doctrine 62 | cd $TARGET/doctrine/orm && rm -rf UPGRADE* build* tests tools lib/vendor 63 | cd $TARGET/doctrine/dbal && rm -rf build* tests lib/vendor 64 | cd $TARGET/doctrine/common && rm -rf build* tests lib/vendor 65 | if [ -d $TARGET/doctrine/doctrine-bundle/Doctrine/Bundle/DoctrineBundle ]; then 66 | cd $TARGET/doctrine/doctrine-bundle/Doctrine/Bundle/DoctrineBundle && rm -rf Tests Resources/doc 67 | else 68 | cd $TARGET/doctrine/doctrine-bundle && rm -rf Tests Resources/doc 69 | fi 70 | 71 | # kriswallsmith 72 | if [ -d $TARGET/kriswallsmith/assetic ]; then 73 | cd $TARGET/kriswallsmith/assetic && rm -rf CHANGELOG* phpunit.xml* tests docs 74 | fi 75 | 76 | # Monolog 77 | cd $TARGET/monolog/monolog && rm -rf README.markdown phpunit.xml* tests 78 | 79 | # Sensio 80 | if [ -d $TARGET/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle ]; then 81 | cd $TARGET/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 82 | else 83 | cd $TARGET/sensio/distribution-bundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 84 | fi 85 | if [ -d $TARGET/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle ]; then 86 | cd $TARGET/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 87 | else 88 | cd $TARGET/sensio/framework-extra-bundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 89 | fi 90 | if [ -d $TARGET/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle ]; then 91 | cd $TARGET/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 92 | else 93 | cd $TARGET/sensio/generator-bundle && rm -rf phpunit.xml* Tests CHANGELOG* Resources/doc 94 | fi 95 | 96 | # Swiftmailer 97 | cd $TARGET/swiftmailer/swiftmailer && rm -rf CHANGES README* build* docs notes test-suite tests create_pear_package.php package* 98 | 99 | # Symfony 100 | cd $TARGET/symfony/symfony && rm -rf README.md phpunit.xml* tests *.sh vendor 101 | 102 | if [ -d $TARGET/symfony/assetic-bundle/Symfony/Bundle/AsseticBundle ]; then 103 | cd $TARGET/symfony/assetic-bundle/Symfony/Bundle/AsseticBundle && rm -rf Tests Resources/doc 104 | elif [ -d $TARGET/symfony/assetic-bundle ]; then 105 | cd $TARGET/symfony/assetic-bundle && rm -rf Tests Resources/doc 106 | fi 107 | 108 | if [ -d $TARGET/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle ]; then 109 | cd $TARGET/symfony/swiftmailer-bundle/Symfony/Bundle/SwiftmailerBundle && rm -rf Tests Resources/doc 110 | else 111 | cd $TARGET/symfony/swiftmailer-bundle && rm -rf Tests Resources/doc 112 | fi 113 | 114 | if [ -d $TARGET/symfony/monolog-bundle/Symfony/Bundle/MonologBundle ]; then 115 | cd $TARGET/symfony/monolog-bundle/Symfony/Bundle/MonologBundle && rm -rf Tests Resources/doc 116 | else 117 | cd $TARGET/symfony/monolog-bundle && rm -rf Tests Resources/doc 118 | fi 119 | 120 | # Twig 121 | cd $TARGET/twig/twig && rm -rf AUTHORS CHANGELOG README.markdown bin doc package.xml.tpl phpunit.xml* test 122 | 123 | # cleanup 124 | find $TARGET -name .git | xargs rm -rf - 125 | find $TARGET -name .gitignore | xargs rm -rf - 126 | find $TARGET -name .gitmodules | xargs rm -rf - 127 | find $TARGET -name .svn | xargs rm -rf - 128 | 129 | # With vendors 130 | cd /tmp 131 | tar zcpf $DIR/Symfony_Standard_Vendors_$VERSION.tgz Symfony 132 | rm -f $DIR/Symfony_Standard_Vendors_$VERSION.zip 133 | zip -rq $DIR/Symfony_Standard_Vendors_$VERSION.zip Symfony 134 | 135 | # Without vendors 136 | cd /tmp 137 | rm -rf Symfony/vendor 138 | tar zcpf $DIR/Symfony_Standard_$VERSION.tgz Symfony 139 | rm -f $DIR/Symfony_Standard_$VERSION.zip 140 | zip -rq $DIR/Symfony_Standard_$VERSION.zip Symfony 141 | -------------------------------------------------------------------------------- /Composer/ScriptHandler.php: -------------------------------------------------------------------------------- 1 | 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 | namespace Sensio\Bundle\DistributionBundle\Composer; 13 | 14 | use Symfony\Component\ClassLoader\ClassCollectionLoader; 15 | use Symfony\Component\Filesystem\Filesystem; 16 | use Symfony\Component\Process\Process; 17 | use Symfony\Component\Process\PhpExecutableFinder; 18 | use Composer\Script\Event; 19 | use Composer\Util\ProcessExecutor; 20 | 21 | /** 22 | * @author Jordi Boggiano 23 | */ 24 | class ScriptHandler 25 | { 26 | /** 27 | * Composer variables are declared static so that an event could update 28 | * a composer.json and set new options, making them immediately available 29 | * to forthcoming listeners. 30 | */ 31 | protected static $options = array( 32 | 'symfony-app-dir' => 'app', 33 | 'symfony-web-dir' => 'web', 34 | 'symfony-assets-install' => 'hard', 35 | 'symfony-cache-warmup' => false, 36 | ); 37 | 38 | /** 39 | * Asks if the new directory structure should be used, installs the structure if needed. 40 | * 41 | * @param Event $event 42 | */ 43 | public static function defineDirectoryStructure(Event $event) 44 | { 45 | $options = static::getOptions($event); 46 | 47 | if (!getenv('SENSIOLABS_ENABLE_NEW_DIRECTORY_STRUCTURE') || !$event->getIO()->askConfirmation('Would you like to use Symfony 3 directory structure? [y/N] ', false)) { 48 | return; 49 | } 50 | 51 | $rootDir = getcwd(); 52 | $appDir = $options['symfony-app-dir']; 53 | $webDir = $options['symfony-web-dir']; 54 | $binDir = static::$options['symfony-bin-dir'] = 'bin'; 55 | $varDir = static::$options['symfony-var-dir'] = 'var'; 56 | 57 | static::updateDirectoryStructure($event, $rootDir, $appDir, $binDir, $varDir, $webDir); 58 | } 59 | 60 | /** 61 | * Builds the bootstrap file. 62 | * 63 | * The bootstrap file contains PHP file that are always needed by the application. 64 | * It speeds up the application bootstrapping. 65 | * 66 | * @param Event $event 67 | */ 68 | public static function buildBootstrap(Event $event) 69 | { 70 | $options = static::getOptions($event); 71 | $bootstrapDir = $autoloadDir = $options['symfony-app-dir']; 72 | 73 | if (static::useNewDirectoryStructure($options)) { 74 | $bootstrapDir = $options['symfony-var-dir']; 75 | if (!static::hasDirectory($event, 'symfony-var-dir', $bootstrapDir, 'build bootstrap file')) { 76 | return; 77 | } 78 | } 79 | 80 | if (!static::useSymfonyAutoloader($options)) { 81 | $autoloadDir = $options['vendor-dir']; 82 | } 83 | 84 | if (!static::hasDirectory($event, 'symfony-app-dir', $autoloadDir, 'build bootstrap file')) { 85 | return; 86 | } 87 | 88 | static::executeBuildBootstrap($event, $bootstrapDir, $autoloadDir, $options['process-timeout']); 89 | } 90 | 91 | protected static function hasDirectory(Event $event, $configName, $path, $actionName) 92 | { 93 | if (!is_dir($path)) { 94 | $event->getIO()->write(sprintf('The %s (%s) specified in composer.json was not found in %s, can not %s.', $configName, $path, getcwd(), $actionName)); 95 | 96 | return false; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | /** 103 | * Sets up deployment target specific features. 104 | * Could be custom web server configs, boot command files etc. 105 | * 106 | * @param Event $event 107 | */ 108 | public static function prepareDeploymentTarget(Event $event) 109 | { 110 | static::prepareDeploymentTargetHeroku($event); 111 | } 112 | 113 | protected static function prepareDeploymentTargetHeroku(Event $event) 114 | { 115 | $options = static::getOptions($event); 116 | if (($stack = getenv('STACK')) && ('cedar-14' == $stack || 'heroku-16' == $stack)) { 117 | $fs = new Filesystem(); 118 | if (!$fs->exists('Procfile')) { 119 | $event->getIO()->write('Heroku deploy detected; creating default Procfile for "web" dyno'); 120 | $fs->dumpFile('Procfile', sprintf('web: heroku-php-apache2 %s/', $options['symfony-web-dir'])); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Clears the Symfony cache. 127 | * 128 | * @param Event $event 129 | */ 130 | public static function clearCache(Event $event) 131 | { 132 | $options = static::getOptions($event); 133 | $consoleDir = static::getConsoleDir($event, 'clear the cache'); 134 | 135 | if (null === $consoleDir) { 136 | return; 137 | } 138 | 139 | $warmup = ''; 140 | if (!$options['symfony-cache-warmup']) { 141 | $warmup = ' --no-warmup'; 142 | } 143 | 144 | static::executeCommand($event, $consoleDir, 'cache:clear'.$warmup, $options['process-timeout']); 145 | } 146 | 147 | /** 148 | * Installs the assets under the web root directory. 149 | * 150 | * For better interoperability, assets are copied instead of symlinked by default. 151 | * 152 | * Even if symlinks work on Windows, this is only true on Windows Vista and later, 153 | * but then, only when running the console with admin rights or when disabling the 154 | * strict user permission checks (which can be done on Windows 7 but not on Windows 155 | * Vista). 156 | * 157 | * @param Event $event 158 | */ 159 | public static function installAssets(Event $event) 160 | { 161 | $options = static::getOptions($event); 162 | $consoleDir = static::getConsoleDir($event, 'install assets'); 163 | 164 | if (null === $consoleDir) { 165 | return; 166 | } 167 | 168 | $webDir = $options['symfony-web-dir']; 169 | 170 | $symlink = ''; 171 | if ('symlink' == $options['symfony-assets-install']) { 172 | $symlink = '--symlink '; 173 | } elseif ('relative' == $options['symfony-assets-install']) { 174 | $symlink = '--symlink --relative '; 175 | } 176 | 177 | if (!static::hasDirectory($event, 'symfony-web-dir', $webDir, 'install assets')) { 178 | return; 179 | } 180 | 181 | static::executeCommand($event, $consoleDir, 'assets:install '.$symlink.ProcessExecutor::escape($webDir), $options['process-timeout']); 182 | } 183 | 184 | /** 185 | * Updated the requirements file. 186 | * 187 | * @param Event $event 188 | */ 189 | public static function installRequirementsFile(Event $event) 190 | { 191 | $options = static::getOptions($event); 192 | $appDir = $options['symfony-app-dir']; 193 | $fs = new Filesystem(); 194 | 195 | $newDirectoryStructure = static::useNewDirectoryStructure($options); 196 | 197 | if (!$newDirectoryStructure) { 198 | if (!static::hasDirectory($event, 'symfony-app-dir', $appDir, 'install the requirements files')) { 199 | return; 200 | } 201 | $fs->copy(__DIR__.'/../Resources/skeleton/app/SymfonyRequirements.php', $appDir.'/SymfonyRequirements.php', true); 202 | $fs->copy(__DIR__.'/../Resources/skeleton/app/check.php', $appDir.'/check.php', true); 203 | } else { 204 | $binDir = $options['symfony-bin-dir']; 205 | $varDir = $options['symfony-var-dir']; 206 | if (!static::hasDirectory($event, 'symfony-var-dir', $varDir, 'install the requirements files')) { 207 | return; 208 | } 209 | if (!static::hasDirectory($event, 'symfony-bin-dir', $binDir, 'install the requirements files')) { 210 | return; 211 | } 212 | $fs->copy(__DIR__.'/../Resources/skeleton/app/SymfonyRequirements.php', $varDir.'/SymfonyRequirements.php', true); 213 | $fs->copy(__DIR__.'/../Resources/skeleton/app/check.php', $binDir.'/symfony_requirements', true); 214 | $fs->remove(array($appDir.'/check.php', $appDir.'/SymfonyRequirements.php', true)); 215 | 216 | $fs->dumpFile($binDir.'/symfony_requirements', '#!/usr/bin/env php'."\n".str_replace(".'/SymfonyRequirements.php'", ".'/".$fs->makePathRelative(realpath($varDir), realpath($binDir))."SymfonyRequirements.php'", file_get_contents($binDir.'/symfony_requirements'))); 217 | $fs->chmod($binDir.'/symfony_requirements', 0755); 218 | } 219 | 220 | $webDir = $options['symfony-web-dir']; 221 | 222 | // if the user has already removed the config.php file, do nothing 223 | // as the file must be removed for production use 224 | if ($fs->exists($webDir.'/config.php')) { 225 | $requiredDir = $newDirectoryStructure ? $varDir : $appDir; 226 | 227 | $fs->dumpFile($webDir.'/config.php', str_replace('/../app/SymfonyRequirements.php', '/'.$fs->makePathRelative(realpath($requiredDir), realpath($webDir)).'SymfonyRequirements.php', file_get_contents(__DIR__.'/../Resources/skeleton/web/config.php'))); 228 | } 229 | } 230 | 231 | public static function removeSymfonyStandardFiles(Event $event) 232 | { 233 | $options = static::getOptions($event); 234 | $appDir = $options['symfony-app-dir']; 235 | 236 | if (!is_dir($appDir)) { 237 | return; 238 | } 239 | 240 | if (!is_dir($appDir.'/SymfonyStandard')) { 241 | return; 242 | } 243 | 244 | $fs = new Filesystem(); 245 | $fs->remove($appDir.'/SymfonyStandard'); 246 | } 247 | 248 | public static function doBuildBootstrap($bootstrapDir) 249 | { 250 | $file = $bootstrapDir.'/bootstrap.php.cache'; 251 | if (file_exists($file)) { 252 | unlink($file); 253 | } 254 | 255 | $classes = array( 256 | 'Symfony\\Component\\HttpFoundation\\ParameterBag', 257 | 'Symfony\\Component\\HttpFoundation\\HeaderBag', 258 | 'Symfony\\Component\\HttpFoundation\\FileBag', 259 | 'Symfony\\Component\\HttpFoundation\\ServerBag', 260 | 'Symfony\\Component\\HttpFoundation\\Request', 261 | 262 | 'Symfony\\Component\\ClassLoader\\ClassCollectionLoader', 263 | ); 264 | 265 | if (method_exists('Symfony\Component\ClassLoader\ClassCollectionLoader', 'inline')) { 266 | ClassCollectionLoader::inline($classes, $file, array()); 267 | } else { 268 | ClassCollectionLoader::load($classes, dirname($file), basename($file, '.php.cache'), false, false, '.php.cache'); 269 | } 270 | 271 | $bootstrapContent = substr(file_get_contents($file), 5); 272 | 273 | file_put_contents($file, sprintf(<<<'EOF' 274 | getIO()->isDecorated()) { 288 | $console .= ' --ansi'; 289 | } 290 | 291 | $process = new Process($php.($phpArgs ? ' '.$phpArgs : '').' '.$console.' '.$cmd, null, null, null, $timeout); 292 | $process->run(function ($type, $buffer) use ($event) { $event->getIO()->write($buffer, false); }); 293 | if (!$process->isSuccessful()) { 294 | throw new \RuntimeException(sprintf("An error occurred when executing the \"%s\" command:\n\n%s\n\n%s", ProcessExecutor::escape($cmd), self::removeDecoration($process->getOutput()), self::removeDecoration($process->getErrorOutput()))); 295 | } 296 | } 297 | 298 | protected static function executeBuildBootstrap(Event $event, $bootstrapDir, $autoloadDir, $timeout = 300) 299 | { 300 | $php = ProcessExecutor::escape(static::getPhp(false)); 301 | $phpArgs = implode(' ', array_map(array('Composer\Util\ProcessExecutor', 'escape'), static::getPhpArguments())); 302 | $cmd = ProcessExecutor::escape(__DIR__.'/../Resources/bin/build_bootstrap.php'); 303 | $bootstrapDir = ProcessExecutor::escape($bootstrapDir); 304 | $autoloadDir = ProcessExecutor::escape($autoloadDir); 305 | $useNewDirectoryStructure = ''; 306 | if (static::useNewDirectoryStructure(static::getOptions($event))) { 307 | $useNewDirectoryStructure = ProcessExecutor::escape('--use-new-directory-structure'); 308 | } 309 | 310 | $process = new Process($php.($phpArgs ? ' '.$phpArgs : '').' '.$cmd.' '.$bootstrapDir.' '.$autoloadDir.' '.$useNewDirectoryStructure, getcwd(), null, null, $timeout); 311 | $process->run(function ($type, $buffer) use ($event) { $event->getIO()->write($buffer, false); }); 312 | if (!$process->isSuccessful()) { 313 | throw new \RuntimeException('An error occurred when generating the bootstrap file.'); 314 | } 315 | } 316 | 317 | protected static function updateDirectoryStructure(Event $event, $rootDir, $appDir, $binDir, $varDir, $webDir) 318 | { 319 | $event->getIO()->write('Updating Symfony directory structure...'); 320 | 321 | $fs = new Filesystem(); 322 | 323 | $fs->mkdir(array($binDir, $varDir)); 324 | 325 | foreach (array( 326 | $appDir.'/console' => $binDir.'/console', 327 | $appDir.'/phpunit.xml.dist' => $rootDir.'/phpunit.xml.dist', 328 | ) as $source => $target) { 329 | $fs->rename($source, $target, true); 330 | } 331 | 332 | foreach (array('/logs', '/cache') as $dir) { 333 | $fs->rename($appDir.$dir, $varDir.$dir); 334 | } 335 | 336 | $gitignore = << 355 | 356 | 357 | --> 358 | EOF; 359 | $phpunitKernelAfter = << 361 | 362 | 363 | EOF; 364 | $phpunit = str_replace(array('../src', '"bootstrap.php.cache"', $phpunitKernelBefore), array('src', '"'.$varDir.'/bootstrap.php.cache"', $phpunitKernelAfter), file_get_contents($rootDir.'/phpunit.xml.dist')); 365 | $composer = str_replace('"symfony-app-dir": "app",', "\"symfony-app-dir\": \"app\",\n \"symfony-bin-dir\": \"bin\",\n \"symfony-var-dir\": \"var\",", file_get_contents($rootDir.'/composer.json')); 366 | 367 | $fs->dumpFile($webDir.'/app.php', str_replace($appDir.'/bootstrap.php.cache', $varDir.'/bootstrap.php.cache', file_get_contents($webDir.'/app.php'))); 368 | $fs->dumpFile($webDir.'/app_dev.php', str_replace($appDir.'/bootstrap.php.cache', $varDir.'/bootstrap.php.cache', file_get_contents($webDir.'/app_dev.php'))); 369 | $fs->dumpFile($binDir.'/console', str_replace(array(".'/bootstrap.php.cache'", ".'/AppKernel.php'"), array(".'/".$fs->makePathRelative(realpath($varDir), realpath($binDir))."bootstrap.php.cache'", ".'/".$fs->makePathRelative(realpath($appDir), realpath($binDir))."AppKernel.php'"), file_get_contents($binDir.'/console'))); 370 | $fs->dumpFile($rootDir.'/phpunit.xml.dist', $phpunit); 371 | $fs->dumpFile($rootDir.'/composer.json', $composer); 372 | 373 | $fs->dumpFile($rootDir.'/.gitignore', $gitignore); 374 | 375 | $fs->chmod($binDir.'/console', 0755); 376 | } 377 | 378 | protected static function getOptions(Event $event) 379 | { 380 | $options = array_merge(static::$options, $event->getComposer()->getPackage()->getExtra()); 381 | 382 | $options['symfony-assets-install'] = getenv('SYMFONY_ASSETS_INSTALL') ?: $options['symfony-assets-install']; 383 | $options['symfony-cache-warmup'] = getenv('SYMFONY_CACHE_WARMUP') ?: $options['symfony-cache-warmup']; 384 | 385 | $options['process-timeout'] = $event->getComposer()->getConfig()->get('process-timeout'); 386 | $options['vendor-dir'] = $event->getComposer()->getConfig()->get('vendor-dir'); 387 | 388 | return $options; 389 | } 390 | 391 | protected static function getPhp($includeArgs = true) 392 | { 393 | $phpFinder = new PhpExecutableFinder(); 394 | if (!$phpPath = $phpFinder->find($includeArgs)) { 395 | throw new \RuntimeException('The php executable could not be found, add it to your PATH environment variable and try again'); 396 | } 397 | 398 | return $phpPath; 399 | } 400 | 401 | protected static function getPhpArguments() 402 | { 403 | $ini = null; 404 | $arguments = array(); 405 | 406 | $phpFinder = new PhpExecutableFinder(); 407 | if (method_exists($phpFinder, 'findArguments')) { 408 | $arguments = $phpFinder->findArguments(); 409 | } 410 | 411 | if ($env = getenv('COMPOSER_ORIGINAL_INIS')) { 412 | $paths = explode(PATH_SEPARATOR, $env); 413 | $ini = array_shift($paths); 414 | } else { 415 | $ini = php_ini_loaded_file(); 416 | } 417 | 418 | if ($ini) { 419 | $arguments[] = '--php-ini='.$ini; 420 | } 421 | 422 | return $arguments; 423 | } 424 | 425 | /** 426 | * Returns a relative path to the directory that contains the `console` command. 427 | * 428 | * @param Event $event The command event 429 | * @param string $actionName The name of the action 430 | * 431 | * @return string|null The path to the console directory, null if not found 432 | */ 433 | protected static function getConsoleDir(Event $event, $actionName) 434 | { 435 | $options = static::getOptions($event); 436 | 437 | if (static::useNewDirectoryStructure($options)) { 438 | if (!static::hasDirectory($event, 'symfony-bin-dir', $options['symfony-bin-dir'], $actionName)) { 439 | return; 440 | } 441 | 442 | return $options['symfony-bin-dir']; 443 | } 444 | 445 | if (!static::hasDirectory($event, 'symfony-app-dir', $options['symfony-app-dir'], 'execute command')) { 446 | return; 447 | } 448 | 449 | return $options['symfony-app-dir']; 450 | } 451 | 452 | /** 453 | * Returns true if the new directory structure is used. 454 | * 455 | * @param array $options Composer options 456 | * 457 | * @return bool 458 | */ 459 | protected static function useNewDirectoryStructure(array $options) 460 | { 461 | return isset($options['symfony-var-dir']) && is_dir($options['symfony-var-dir']); 462 | } 463 | 464 | /** 465 | * Returns true if the application bespoke autoloader is used. 466 | * 467 | * @param array $options Composer options 468 | * 469 | * @return bool 470 | */ 471 | protected static function useSymfonyAutoloader(array $options) 472 | { 473 | return isset($options['symfony-app-dir']) && is_file($options['symfony-app-dir'].'/autoload.php'); 474 | } 475 | 476 | private static function removeDecoration($string) 477 | { 478 | return preg_replace("/\033\[[^m]*m/", '', $string); 479 | } 480 | } 481 | -------------------------------------------------------------------------------- /Resources/skeleton/web/config.php: -------------------------------------------------------------------------------- 1 | getFailedRequirements(); 30 | $minorProblems = $symfonyRequirements->getFailedRecommendations(); 31 | $hasMajorProblems = (bool) count($majorProblems); 32 | $hasMinorProblems = (bool) count($minorProblems); 33 | 34 | ?> 35 | 36 | 37 | 38 | 39 | 40 | Symfony Configuration Checker 41 | 331 | 332 | 333 |
334 |
335 | 338 | 339 | 359 |
360 | 361 |
362 |
363 |
364 |

Configuration Checker

365 |

366 | This script analyzes your system to check whether is 367 | ready to run Symfony applications. 368 |

369 | 370 | 371 |

Major problems

372 |

Major problems have been detected and must be fixed before continuing:

373 |
    374 | 375 |
  1. getTestMessage() ?> 376 |

    getHelpHtml() ?>

    377 |
  2. 378 | 379 |
380 | 381 | 382 | 383 |

Recommendations

384 |

385 | Additionally, toTo enhance your Symfony experience, 386 | it’s recommended that you fix the following: 387 |

388 |
    389 | 390 |
  1. getTestMessage() ?> 391 |

    getHelpHtml() ?>

    392 |
  2. 393 | 394 |
395 | 396 | 397 | hasPhpIniConfigIssue()): ?> 398 |

* 399 | getPhpIniConfigPath()): ?> 400 | Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". 401 | 402 | To change settings, create a "php.ini". 403 | 404 |

405 | 406 | 407 | 408 |

All checks passed successfully. Your system is ready to run Symfony applications.

409 | 410 | 411 | 416 |
417 |
418 |
419 |
Symfony Standard Edition
420 |
421 | 422 | 423 | -------------------------------------------------------------------------------- /Resources/skeleton/app/SymfonyRequirements.php: -------------------------------------------------------------------------------- 1 | 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 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 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 %s to %s in php.ini*.', 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 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) 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) 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) 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) 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 378 | * @author Fabien Potencier 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 composer install 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 "%s", but Symfony needs at least PHP "%s" 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 http://getcomposer.org/. '. 423 | 'Then run "php composer.phar install" 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 "app/cache/" or "var/cache/" 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 "app/logs/" or "var/logs/" 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 "date.timezone" setting in php.ini* (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 php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' 455 | ); 456 | } 457 | 458 | $this->addRequirement( 459 | function_exists('iconv'), 460 | 'iconv() must be available', 461 | 'Install and enable the iconv extension.' 462 | ); 463 | 464 | $this->addRequirement( 465 | function_exists('json_encode'), 466 | 'json_encode() must be available', 467 | 'Install and enable the JSON extension.' 468 | ); 469 | 470 | $this->addRequirement( 471 | function_exists('session_start'), 472 | 'session_start() must be available', 473 | 'Install and enable the session extension.' 474 | ); 475 | 476 | $this->addRequirement( 477 | function_exists('ctype_alpha'), 478 | 'ctype_alpha() must be available', 479 | 'Install and enable the ctype extension.' 480 | ); 481 | 482 | $this->addRequirement( 483 | function_exists('token_get_all'), 484 | 'token_get_all() must be available', 485 | 'Install and enable the Tokenizer extension.' 486 | ); 487 | 488 | $this->addRequirement( 489 | function_exists('simplexml_import_dom'), 490 | 'simplexml_import_dom() must be available', 491 | 'Install and enable the SimpleXML 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 APC 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 APC 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 "phar" to suhosin.executor.include.whitelist in php.ini*.' 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 "xdebug.max_nesting_level" to e.g. "250" in php.ini* 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 PCRE 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 "mbstring.func_overload" to 0 in php.ini* 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 | 'PCRE 8.0+ 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 PHP-DOM and the PHP-XML modules.' 621 | ); 622 | 623 | $this->addRecommendation( 624 | function_exists('mb_strlen'), 625 | 'mb_strlen() should be available', 626 | 'Install and enable the mbstring extension.' 627 | ); 628 | 629 | $this->addRecommendation( 630 | function_exists('utf8_decode'), 631 | 'utf8_decode() should be available', 632 | 'Install and enable the XML extension.' 633 | ); 634 | 635 | $this->addRecommendation( 636 | function_exists('filter_var'), 637 | 'filter_var() should be available', 638 | 'Install and enable the filter 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 php_posix 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 intl 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 intl 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 "intl.error_level" to "0" in php.ini* 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 PHP accelerator (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 "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* 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 PDO (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 PDO drivers (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 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 | --------------------------------------------------------------------------------