ConfigDataCollector.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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\Component\HttpKernel\DataCollector;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\HttpKernel\Kernel;
  14. use Symfony\Component\HttpKernel\KernelInterface;
  15. use Symfony\Component\Runtime\RunnerInterface;
  16. use Symfony\Component\VarDumper\Caster\ClassStub;
  17. use Symfony\Component\VarDumper\Cloner\Data;
  18. /**
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. *
  21. * @final
  22. */
  23. class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
  24. {
  25. private KernelInterface $kernel;
  26. /**
  27. * Sets the Kernel associated with this Request.
  28. */
  29. public function setKernel(KernelInterface $kernel): void
  30. {
  31. $this->kernel = $kernel;
  32. }
  33. public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
  34. {
  35. $eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
  36. $eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
  37. $xdebugMode = getenv('XDEBUG_MODE') ?: \ini_get('xdebug.mode');
  38. $this->data = [
  39. 'token' => $response->headers->get('X-Debug-Token'),
  40. 'symfony_version' => Kernel::VERSION,
  41. 'symfony_minor_version' => \sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
  42. 'symfony_lts' => 4 === Kernel::MINOR_VERSION,
  43. 'symfony_state' => $this->determineSymfonyState(),
  44. 'symfony_eom' => $eom->format('F Y'),
  45. 'symfony_eol' => $eol->format('F Y'),
  46. 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
  47. 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
  48. 'php_version' => \PHP_VERSION,
  49. 'php_architecture' => \PHP_INT_SIZE * 8,
  50. 'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
  51. 'php_timezone' => date_default_timezone_get(),
  52. 'xdebug_enabled' => \extension_loaded('xdebug'),
  53. 'xdebug_status' => \extension_loaded('xdebug') ? ($xdebugMode && 'off' !== $xdebugMode ? 'Enabled ('.$xdebugMode.')' : 'Not enabled') : 'Not installed',
  54. 'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL),
  55. 'apcu_status' => \extension_loaded('apcu') ? (filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed',
  56. 'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL),
  57. 'zend_opcache_status' => \extension_loaded('Zend OPcache') ? (filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed',
  58. 'bundles' => [],
  59. 'sapi_name' => \PHP_SAPI,
  60. 'runner_class' => $this->determineRunnerClass(),
  61. ];
  62. if (isset($this->kernel)) {
  63. foreach ($this->kernel->getBundles() as $name => $bundle) {
  64. $this->data['bundles'][$name] = new ClassStub($bundle::class);
  65. }
  66. }
  67. if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
  68. $this->data['php_version'] = $matches[1];
  69. $this->data['php_version_extra'] = $matches[2];
  70. }
  71. }
  72. public function lateCollect(): void
  73. {
  74. $this->data = $this->cloneVar($this->data);
  75. }
  76. /**
  77. * Gets the token.
  78. */
  79. public function getToken(): ?string
  80. {
  81. return $this->data['token'];
  82. }
  83. /**
  84. * Gets the Symfony version.
  85. */
  86. public function getSymfonyVersion(): string
  87. {
  88. return $this->data['symfony_version'];
  89. }
  90. /**
  91. * Returns the state of the current Symfony release
  92. * as one of: unknown, dev, stable, eom, eol.
  93. */
  94. public function getSymfonyState(): string
  95. {
  96. return $this->data['symfony_state'];
  97. }
  98. /**
  99. * Returns the minor Symfony version used (without patch numbers of extra
  100. * suffix like "RC", "beta", etc.).
  101. */
  102. public function getSymfonyMinorVersion(): string
  103. {
  104. return $this->data['symfony_minor_version'];
  105. }
  106. public function isSymfonyLts(): bool
  107. {
  108. return $this->data['symfony_lts'];
  109. }
  110. /**
  111. * Returns the human readable date when this Symfony version ends its
  112. * maintenance period.
  113. */
  114. public function getSymfonyEom(): string
  115. {
  116. return $this->data['symfony_eom'];
  117. }
  118. /**
  119. * Returns the human readable date when this Symfony version reaches its
  120. * "end of life" and won't receive bugs or security fixes.
  121. */
  122. public function getSymfonyEol(): string
  123. {
  124. return $this->data['symfony_eol'];
  125. }
  126. /**
  127. * Gets the PHP version.
  128. */
  129. public function getPhpVersion(): string
  130. {
  131. return $this->data['php_version'];
  132. }
  133. /**
  134. * Gets the PHP version extra part.
  135. */
  136. public function getPhpVersionExtra(): ?string
  137. {
  138. return $this->data['php_version_extra'] ?? null;
  139. }
  140. public function getPhpArchitecture(): int
  141. {
  142. return $this->data['php_architecture'];
  143. }
  144. public function getPhpIntlLocale(): string
  145. {
  146. return $this->data['php_intl_locale'];
  147. }
  148. public function getPhpTimezone(): string
  149. {
  150. return $this->data['php_timezone'];
  151. }
  152. /**
  153. * Gets the environment.
  154. */
  155. public function getEnv(): string
  156. {
  157. return $this->data['env'];
  158. }
  159. /**
  160. * Returns true if the debug is enabled.
  161. *
  162. * @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
  163. */
  164. public function isDebug(): bool|string
  165. {
  166. return $this->data['debug'];
  167. }
  168. /**
  169. * Returns true if the Xdebug is enabled.
  170. */
  171. public function hasXdebug(): bool
  172. {
  173. return $this->data['xdebug_enabled'];
  174. }
  175. public function getXdebugStatus(): string
  176. {
  177. return $this->data['xdebug_status'];
  178. }
  179. /**
  180. * Returns true if the function xdebug_info is available.
  181. */
  182. public function hasXdebugInfo(): bool
  183. {
  184. return \function_exists('xdebug_info');
  185. }
  186. /**
  187. * Returns true if APCu is enabled.
  188. */
  189. public function hasApcu(): bool
  190. {
  191. return $this->data['apcu_enabled'];
  192. }
  193. public function getApcuStatus(): string
  194. {
  195. return $this->data['apcu_status'];
  196. }
  197. /**
  198. * Returns true if Zend OPcache is enabled.
  199. */
  200. public function hasZendOpcache(): bool
  201. {
  202. return $this->data['zend_opcache_enabled'];
  203. }
  204. public function getZendOpcacheStatus(): string
  205. {
  206. return $this->data['zend_opcache_status'];
  207. }
  208. public function getBundles(): array|Data
  209. {
  210. return $this->data['bundles'];
  211. }
  212. /**
  213. * Gets the PHP SAPI name.
  214. */
  215. public function getSapiName(): string
  216. {
  217. return $this->data['sapi_name'];
  218. }
  219. public function getRunnerClass(): ?string
  220. {
  221. return $this->data['runner_class'];
  222. }
  223. public function getName(): string
  224. {
  225. return 'config';
  226. }
  227. private function determineSymfonyState(): string
  228. {
  229. $now = new \DateTimeImmutable();
  230. $eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
  231. $eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
  232. if ($now > $eol) {
  233. $versionState = 'eol';
  234. } elseif ($now > $eom) {
  235. $versionState = 'eom';
  236. } elseif ('' !== Kernel::EXTRA_VERSION) {
  237. $versionState = 'dev';
  238. } else {
  239. $versionState = 'stable';
  240. }
  241. return $versionState;
  242. }
  243. private function determineRunnerClass(): ?string
  244. {
  245. $stack = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
  246. for ($frame = end($stack); $frame; $frame = prev($stack)) {
  247. if (!$class = $frame['class'] ?? null) {
  248. continue;
  249. }
  250. if (is_a($class, RunnerInterface::class, true)) {
  251. return $class;
  252. }
  253. }
  254. return null;
  255. }
  256. }