AboutCommand.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Command;
  11. use Symfony\Component\Console\Command\Command;
  12. use Symfony\Component\Console\Helper\Helper;
  13. use Symfony\Component\Console\Helper\TableSeparator;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. use Symfony\Component\Console\Style\SymfonyStyle;
  17. use Symfony\Component\HttpKernel\Kernel;
  18. use Symfony\Component\HttpKernel\KernelInterface;
  19. /**
  20. * A console command to display information about the current installation.
  21. *
  22. * @author Roland Franssen <franssen.roland@gmail.com>
  23. *
  24. * @final
  25. */
  26. class AboutCommand extends Command
  27. {
  28. protected static $defaultName = 'about';
  29. /**
  30. * {@inheritdoc}
  31. */
  32. protected function configure()
  33. {
  34. $this
  35. ->setDescription('Display information about the current project')
  36. ->setHelp(<<<'EOT'
  37. The <info>%command.name%</info> command displays information about the current Symfony project.
  38. The <info>PHP</info> section displays important configuration that could affect your application. The values might
  39. be different between web and CLI.
  40. The <info>Environment</info> section displays the current environment variables managed by Symfony Dotenv. It will not
  41. be shown if no variables were found. The values might be different between web and CLI.
  42. EOT
  43. )
  44. ;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. protected function execute(InputInterface $input, OutputInterface $output): int
  50. {
  51. $io = new SymfonyStyle($input, $output);
  52. /** @var KernelInterface $kernel */
  53. $kernel = $this->getApplication()->getKernel();
  54. if (method_exists($kernel, 'getBuildDir')) {
  55. $buildDir = $kernel->getBuildDir();
  56. } else {
  57. $buildDir = $kernel->getCacheDir();
  58. }
  59. $rows = [
  60. ['<info>Symfony</>'],
  61. new TableSeparator(),
  62. ['Version', Kernel::VERSION],
  63. ['Long-Term Support', 4 === Kernel::MINOR_VERSION ? 'Yes' : 'No'],
  64. ['End of maintenance', Kernel::END_OF_MAINTENANCE.(self::isExpired(Kernel::END_OF_MAINTENANCE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_MAINTENANCE).'</>)')],
  65. ['End of life', Kernel::END_OF_LIFE.(self::isExpired(Kernel::END_OF_LIFE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_LIFE).'</>)')],
  66. new TableSeparator(),
  67. ['<info>Kernel</>'],
  68. new TableSeparator(),
  69. ['Type', \get_class($kernel)],
  70. ['Environment', $kernel->getEnvironment()],
  71. ['Debug', $kernel->isDebug() ? 'true' : 'false'],
  72. ['Charset', $kernel->getCharset()],
  73. ['Cache directory', self::formatPath($kernel->getCacheDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getCacheDir()).'</>)'],
  74. ['Build directory', self::formatPath($buildDir, $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($buildDir).'</>)'],
  75. ['Log directory', self::formatPath($kernel->getLogDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getLogDir()).'</>)'],
  76. new TableSeparator(),
  77. ['<info>PHP</>'],
  78. new TableSeparator(),
  79. ['Version', \PHP_VERSION],
  80. ['Architecture', (\PHP_INT_SIZE * 8).' bits'],
  81. ['Intl locale', class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a'],
  82. ['Timezone', date_default_timezone_get().' (<comment>'.(new \DateTime())->format(\DateTime::W3C).'</>)'],
  83. ['OPcache', \extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false'],
  84. ['APCu', \extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false'],
  85. ['Xdebug', \extension_loaded('xdebug') ? 'true' : 'false'],
  86. ];
  87. $io->table([], $rows);
  88. return 0;
  89. }
  90. private static function formatPath(string $path, string $baseDir): string
  91. {
  92. return preg_replace('~^'.preg_quote($baseDir, '~').'~', '.', $path);
  93. }
  94. private static function formatFileSize(string $path): string
  95. {
  96. if (is_file($path)) {
  97. $size = filesize($path) ?: 0;
  98. } else {
  99. $size = 0;
  100. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)) as $file) {
  101. if ($file->isReadable()) {
  102. $size += $file->getSize();
  103. }
  104. }
  105. }
  106. return Helper::formatMemory($size);
  107. }
  108. private static function isExpired(string $date): bool
  109. {
  110. $date = \DateTime::createFromFormat('d/m/Y', '01/'.$date);
  111. return false !== $date && new \DateTime() > $date->modify('last day of this month 23:59:59');
  112. }
  113. private static function daysBeforeExpiration(string $date): string
  114. {
  115. $date = \DateTime::createFromFormat('d/m/Y', '01/'.$date);
  116. return (new \DateTime())->diff($date->modify('last day of this month 23:59:59'))->format('in %R%a days');
  117. }
  118. }