N°9319 increase php min. version to 8.2 (#887)

* Update minimum PHP version to 8.2
* Fix previous wrong resolution of merge conflict
This commit is contained in:
jf-cbd
2026-04-20 14:47:44 +02:00
committed by GitHub
parent f439490bfc
commit 805087a01b
171 changed files with 5629 additions and 1446 deletions

31
lib/autoload_runtime.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
// autoload_runtime.php @generated by Symfony Runtime
if (true === (require_once __DIR__.'/autoload.php') || empty($_SERVER['SCRIPT_FILENAME'])) {
return;
}
$app = require $_SERVER['SCRIPT_FILENAME'];
if (!is_object($app)) {
throw new TypeError(sprintf('Invalid return value: callable object expected, "%s" returned from "%s".', get_debug_type($app), $_SERVER['SCRIPT_FILENAME']));
}
$runtime = $_SERVER['APP_RUNTIME'] ?? $_ENV['APP_RUNTIME'] ?? 'Symfony\\Component\\Runtime\\SymfonyRuntime';
$runtime = new $runtime(($_SERVER['APP_RUNTIME_OPTIONS'] ?? $_ENV['APP_RUNTIME_OPTIONS'] ?? []) + [
'dotenv_path' => 'resources/symfony/.env',
'project_dir' => dirname(__DIR__, 1),
]);
[$app, $args] = $runtime
->getResolver($app)
->resolve();
$app = $app(...$args);
exit(
$runtime
->getRunner($app)
->run()
);

View File

@@ -960,6 +960,7 @@ return array(
'IntervalExpression' => $baseDir . '/core/oql/expression.class.inc.php',
'IntervalOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
'IntlDateFormatter' => $vendorDir . '/symfony/polyfill-intl-icu/Resources/stubs/IntlDateFormatter.php',
'IntlListFormatter' => $vendorDir . '/symfony/polyfill-intl-icu/Resources/stubs/IntlListFormatter.php',
'Introspection' => $baseDir . '/core/introspection.class.inc.php',
'InvalidConfigParamException' => $baseDir . '/application/exceptions/InvalidConfigParamException.php',
'InvalidExternalKeyValueException' => $baseDir . '/application/exceptions/InvalidExternalKeyValueException.php',
@@ -1606,6 +1607,11 @@ return array(
'Symfony\\Bridge\\Twig\\TokenParser\\TransTokenParser' => $vendorDir . '/symfony/twig-bridge/TokenParser/TransTokenParser.php',
'Symfony\\Bridge\\Twig\\Translation\\TwigExtractor' => $vendorDir . '/symfony/twig-bridge/Translation/TwigExtractor.php',
'Symfony\\Bridge\\Twig\\UndefinedCallableHandler' => $vendorDir . '/symfony/twig-bridge/UndefinedCallableHandler.php',
'Symfony\\Bundle\\DebugBundle\\Command\\ServerDumpPlaceholderCommand' => $vendorDir . '/symfony/debug-bundle/Command/ServerDumpPlaceholderCommand.php',
'Symfony\\Bundle\\DebugBundle\\DebugBundle' => $vendorDir . '/symfony/debug-bundle/DebugBundle.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\Compiler\\DumpDataCollectorPass' => $vendorDir . '/symfony/debug-bundle/DependencyInjection/Compiler/DumpDataCollectorPass.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\Configuration' => $vendorDir . '/symfony/debug-bundle/DependencyInjection/Configuration.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\DebugExtension' => $vendorDir . '/symfony/debug-bundle/DependencyInjection/DebugExtension.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\AbstractPhpFileCacheWarmer' => $vendorDir . '/symfony/framework-bundle/CacheWarmer/AbstractPhpFileCacheWarmer.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\AnnotationsCacheWarmer' => $vendorDir . '/symfony/framework-bundle/CacheWarmer/AnnotationsCacheWarmer.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\CachePoolClearerCacheWarmer' => $vendorDir . '/symfony/framework-bundle/CacheWarmer/CachePoolClearerCacheWarmer.php',
@@ -1809,6 +1815,7 @@ return array(
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay121Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay12Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay20Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay21Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay21Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => $vendorDir . '/symfony/cache/Traits/Relay/SwapdbTrait.php',
'Symfony\\Component\\Config\\Builder\\ClassBuilder' => $vendorDir . '/symfony/config/Builder/ClassBuilder.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => $vendorDir . '/symfony/config/Builder/ConfigBuilderGenerator.php',
@@ -2257,6 +2264,7 @@ return array(
'Symfony\\Component\\Dotenv\\Exception\\FormatException' => $vendorDir . '/symfony/dotenv/Exception/FormatException.php',
'Symfony\\Component\\Dotenv\\Exception\\FormatExceptionContext' => $vendorDir . '/symfony/dotenv/Exception/FormatExceptionContext.php',
'Symfony\\Component\\Dotenv\\Exception\\PathException' => $vendorDir . '/symfony/dotenv/Exception/PathException.php',
'Symfony\\Component\\Dotenv\\Exception\\VariableCircularReferenceException' => $vendorDir . '/symfony/dotenv/Exception/VariableCircularReferenceException.php',
'Symfony\\Component\\ErrorHandler\\BufferingLogger' => $vendorDir . '/symfony/error-handler/BufferingLogger.php',
'Symfony\\Component\\ErrorHandler\\Debug' => $vendorDir . '/symfony/error-handler/Debug.php',
'Symfony\\Component\\ErrorHandler\\DebugClassLoader' => $vendorDir . '/symfony/error-handler/DebugClassLoader.php',
@@ -3074,6 +3082,21 @@ return array(
'Symfony\\Component\\Routing\\RouteCompilerInterface' => $vendorDir . '/symfony/routing/RouteCompilerInterface.php',
'Symfony\\Component\\Routing\\Router' => $vendorDir . '/symfony/routing/Router.php',
'Symfony\\Component\\Routing\\RouterInterface' => $vendorDir . '/symfony/routing/RouterInterface.php',
'Symfony\\Component\\Runtime\\GenericRuntime' => $vendorDir . '/symfony/runtime/GenericRuntime.php',
'Symfony\\Component\\Runtime\\Internal\\BasicErrorHandler' => $vendorDir . '/symfony/runtime/Internal/BasicErrorHandler.php',
'Symfony\\Component\\Runtime\\Internal\\ComposerPlugin' => $vendorDir . '/symfony/runtime/Internal/ComposerPlugin.php',
'Symfony\\Component\\Runtime\\Internal\\MissingDotenv' => $vendorDir . '/symfony/runtime/Internal/MissingDotenv.php',
'Symfony\\Component\\Runtime\\Internal\\SymfonyErrorHandler' => $vendorDir . '/symfony/runtime/Internal/SymfonyErrorHandler.php',
'Symfony\\Component\\Runtime\\ResolverInterface' => $vendorDir . '/symfony/runtime/ResolverInterface.php',
'Symfony\\Component\\Runtime\\Resolver\\ClosureResolver' => $vendorDir . '/symfony/runtime/Resolver/ClosureResolver.php',
'Symfony\\Component\\Runtime\\Resolver\\DebugClosureResolver' => $vendorDir . '/symfony/runtime/Resolver/DebugClosureResolver.php',
'Symfony\\Component\\Runtime\\RunnerInterface' => $vendorDir . '/symfony/runtime/RunnerInterface.php',
'Symfony\\Component\\Runtime\\Runner\\ClosureRunner' => $vendorDir . '/symfony/runtime/Runner/ClosureRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\ConsoleApplicationRunner' => $vendorDir . '/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner' => $vendorDir . '/symfony/runtime/Runner/Symfony/HttpKernelRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\ResponseRunner' => $vendorDir . '/symfony/runtime/Runner/Symfony/ResponseRunner.php',
'Symfony\\Component\\Runtime\\RuntimeInterface' => $vendorDir . '/symfony/runtime/RuntimeInterface.php',
'Symfony\\Component\\Runtime\\SymfonyRuntime' => $vendorDir . '/symfony/runtime/SymfonyRuntime.php',
'Symfony\\Component\\Security\\Core\\AuthenticationEvents' => $vendorDir . '/symfony/security-core/AuthenticationEvents.php',
'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolver' => $vendorDir . '/symfony/security-core/Authentication/AuthenticationTrustResolver.php',
'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolverInterface' => $vendorDir . '/symfony/security-core/Authentication/AuthenticationTrustResolverInterface.php',
@@ -3565,6 +3588,7 @@ return array(
'Symfony\\Polyfill\\Intl\\Icu\\Exception\\RuntimeException' => $vendorDir . '/symfony/polyfill-intl-icu/Exception/RuntimeException.php',
'Symfony\\Polyfill\\Intl\\Icu\\Icu' => $vendorDir . '/symfony/polyfill-intl-icu/Icu.php',
'Symfony\\Polyfill\\Intl\\Icu\\IntlDateFormatter' => $vendorDir . '/symfony/polyfill-intl-icu/IntlDateFormatter.php',
'Symfony\\Polyfill\\Intl\\Icu\\IntlListFormatter' => $vendorDir . '/symfony/polyfill-intl-icu/IntlListFormatter.php',
'Symfony\\Polyfill\\Intl\\Icu\\Locale' => $vendorDir . '/symfony/polyfill-intl-icu/Locale.php',
'Symfony\\Polyfill\\Intl\\Icu\\NumberFormatter' => $vendorDir . '/symfony/polyfill-intl-icu/NumberFormatter.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php',
@@ -3574,6 +3598,13 @@ return array(
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
'Symfony\\Polyfill\\Php83\\Php83' => $vendorDir . '/symfony/polyfill-php83/Php83.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\ApplicationRuntime' => $vendorDir . '/symfony/runtime/Internal/Console/ApplicationRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Command\\CommandRuntime' => $vendorDir . '/symfony/runtime/Internal/Console/Command/CommandRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Input\\InputInterfaceRuntime' => $vendorDir . '/symfony/runtime/Internal/Console/Input/InputInterfaceRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Output\\OutputInterfaceRuntime' => $vendorDir . '/symfony/runtime/Internal/Console/Output/OutputInterfaceRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpFoundation\\RequestRuntime' => $vendorDir . '/symfony/runtime/Internal/HttpFoundation/RequestRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpFoundation\\ResponseRuntime' => $vendorDir . '/symfony/runtime/Internal/HttpFoundation/ResponseRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpKernel\\HttpKernelInterfaceRuntime' => $vendorDir . '/symfony/runtime/Internal/HttpKernel/HttpKernelInterfaceRuntime.php',
'SynchroExceptionNotStarted' => $baseDir . '/application/exceptions/SynchroExceptionNotStarted.php',
'System' => $vendorDir . '/pear/pear-core-minimal/src/System.php',
'TCPDF' => $vendorDir . '/tecnickcom/tcpdf/tcpdf.php',

View File

@@ -10,8 +10,8 @@ return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php',
'c7baa00073ee9c61edf148c51917cfb4' => $vendorDir . '/twig/twig/src/Resources/escaper.php',

View File

@@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir);
return array(
'Twig\\' => array($vendorDir . '/twig/twig/src'),
'TheNetworg\\OAuth2\\Client\\' => array($vendorDir . '/thenetworg/oauth2-azure/src'),
'Symfony\\Runtime\\Symfony\\Component\\' => array($vendorDir . '/symfony/runtime/Internal'),
'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
@@ -27,6 +28,7 @@ return array(
'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
'Symfony\\Component\\Security\\Csrf\\' => array($vendorDir . '/symfony/security-csrf'),
'Symfony\\Component\\Security\\Core\\' => array($vendorDir . '/symfony/security-core'),
'Symfony\\Component\\Runtime\\' => array($vendorDir . '/symfony/runtime'),
'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
'Symfony\\Component\\PropertyInfo\\' => array($vendorDir . '/symfony/property-info'),
'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
@@ -50,6 +52,7 @@ return array(
'Symfony\\Bundle\\WebProfilerBundle\\' => array($vendorDir . '/symfony/web-profiler-bundle'),
'Symfony\\Bundle\\TwigBundle\\' => array($vendorDir . '/symfony/twig-bundle'),
'Symfony\\Bundle\\FrameworkBundle\\' => array($vendorDir . '/symfony/framework-bundle'),
'Symfony\\Bundle\\DebugBundle\\' => array($vendorDir . '/symfony/debug-bundle'),
'Symfony\\Bridge\\Twig\\' => array($vendorDir . '/symfony/twig-bridge'),
'Soundasleep\\' => array($vendorDir . '/soundasleep/html2text/src'),
'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'),

View File

@@ -11,8 +11,8 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'89efb1254ef2d1c5d80096acd12c4098' => __DIR__ . '/..' . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => __DIR__ . '/..' . '/twig/twig/src/Resources/debug.php',
'c7baa00073ee9c61edf148c51917cfb4' => __DIR__ . '/..' . '/twig/twig/src/Resources/escaper.php',
@@ -35,6 +35,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
),
'S' =>
array (
'Symfony\\Runtime\\Symfony\\Component\\' => 34,
'Symfony\\Polyfill\\Php83\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
@@ -54,6 +55,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Component\\Stopwatch\\' => 28,
'Symfony\\Component\\Security\\Csrf\\' => 32,
'Symfony\\Component\\Security\\Core\\' => 32,
'Symfony\\Component\\Runtime\\' => 26,
'Symfony\\Component\\Routing\\' => 26,
'Symfony\\Component\\PropertyInfo\\' => 31,
'Symfony\\Component\\PropertyAccess\\' => 33,
@@ -77,6 +79,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Bundle\\WebProfilerBundle\\' => 33,
'Symfony\\Bundle\\TwigBundle\\' => 26,
'Symfony\\Bundle\\FrameworkBundle\\' => 31,
'Symfony\\Bundle\\DebugBundle\\' => 27,
'Symfony\\Bridge\\Twig\\' => 20,
'Soundasleep\\' => 12,
'ScssPhp\\ScssPhp\\' => 16,
@@ -126,6 +129,10 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
array (
0 => __DIR__ . '/..' . '/thenetworg/oauth2-azure/src',
),
'Symfony\\Runtime\\Symfony\\Component\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/runtime/Internal',
),
'Symfony\\Polyfill\\Php83\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
@@ -202,6 +209,10 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
array (
0 => __DIR__ . '/..' . '/symfony/security-core',
),
'Symfony\\Component\\Runtime\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/runtime',
),
'Symfony\\Component\\Routing\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/routing',
@@ -294,6 +305,10 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
array (
0 => __DIR__ . '/..' . '/symfony/framework-bundle',
),
'Symfony\\Bundle\\DebugBundle\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/debug-bundle',
),
'Symfony\\Bridge\\Twig\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/twig-bridge',
@@ -1346,6 +1361,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'IntervalExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
'IntervalOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
'IntlDateFormatter' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Resources/stubs/IntlDateFormatter.php',
'IntlListFormatter' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Resources/stubs/IntlListFormatter.php',
'Introspection' => __DIR__ . '/../..' . '/core/introspection.class.inc.php',
'InvalidConfigParamException' => __DIR__ . '/../..' . '/application/exceptions/InvalidConfigParamException.php',
'InvalidExternalKeyValueException' => __DIR__ . '/../..' . '/application/exceptions/InvalidExternalKeyValueException.php',
@@ -1992,6 +2008,11 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Bridge\\Twig\\TokenParser\\TransTokenParser' => __DIR__ . '/..' . '/symfony/twig-bridge/TokenParser/TransTokenParser.php',
'Symfony\\Bridge\\Twig\\Translation\\TwigExtractor' => __DIR__ . '/..' . '/symfony/twig-bridge/Translation/TwigExtractor.php',
'Symfony\\Bridge\\Twig\\UndefinedCallableHandler' => __DIR__ . '/..' . '/symfony/twig-bridge/UndefinedCallableHandler.php',
'Symfony\\Bundle\\DebugBundle\\Command\\ServerDumpPlaceholderCommand' => __DIR__ . '/..' . '/symfony/debug-bundle/Command/ServerDumpPlaceholderCommand.php',
'Symfony\\Bundle\\DebugBundle\\DebugBundle' => __DIR__ . '/..' . '/symfony/debug-bundle/DebugBundle.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\Compiler\\DumpDataCollectorPass' => __DIR__ . '/..' . '/symfony/debug-bundle/DependencyInjection/Compiler/DumpDataCollectorPass.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\Configuration' => __DIR__ . '/..' . '/symfony/debug-bundle/DependencyInjection/Configuration.php',
'Symfony\\Bundle\\DebugBundle\\DependencyInjection\\DebugExtension' => __DIR__ . '/..' . '/symfony/debug-bundle/DependencyInjection/DebugExtension.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\AbstractPhpFileCacheWarmer' => __DIR__ . '/..' . '/symfony/framework-bundle/CacheWarmer/AbstractPhpFileCacheWarmer.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\AnnotationsCacheWarmer' => __DIR__ . '/..' . '/symfony/framework-bundle/CacheWarmer/AnnotationsCacheWarmer.php',
'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\CachePoolClearerCacheWarmer' => __DIR__ . '/..' . '/symfony/framework-bundle/CacheWarmer/CachePoolClearerCacheWarmer.php',
@@ -2195,6 +2216,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay121Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay12Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay20Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay21Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay21Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/SwapdbTrait.php',
'Symfony\\Component\\Config\\Builder\\ClassBuilder' => __DIR__ . '/..' . '/symfony/config/Builder/ClassBuilder.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => __DIR__ . '/..' . '/symfony/config/Builder/ConfigBuilderGenerator.php',
@@ -2643,6 +2665,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Component\\Dotenv\\Exception\\FormatException' => __DIR__ . '/..' . '/symfony/dotenv/Exception/FormatException.php',
'Symfony\\Component\\Dotenv\\Exception\\FormatExceptionContext' => __DIR__ . '/..' . '/symfony/dotenv/Exception/FormatExceptionContext.php',
'Symfony\\Component\\Dotenv\\Exception\\PathException' => __DIR__ . '/..' . '/symfony/dotenv/Exception/PathException.php',
'Symfony\\Component\\Dotenv\\Exception\\VariableCircularReferenceException' => __DIR__ . '/..' . '/symfony/dotenv/Exception/VariableCircularReferenceException.php',
'Symfony\\Component\\ErrorHandler\\BufferingLogger' => __DIR__ . '/..' . '/symfony/error-handler/BufferingLogger.php',
'Symfony\\Component\\ErrorHandler\\Debug' => __DIR__ . '/..' . '/symfony/error-handler/Debug.php',
'Symfony\\Component\\ErrorHandler\\DebugClassLoader' => __DIR__ . '/..' . '/symfony/error-handler/DebugClassLoader.php',
@@ -3460,6 +3483,21 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Component\\Routing\\RouteCompilerInterface' => __DIR__ . '/..' . '/symfony/routing/RouteCompilerInterface.php',
'Symfony\\Component\\Routing\\Router' => __DIR__ . '/..' . '/symfony/routing/Router.php',
'Symfony\\Component\\Routing\\RouterInterface' => __DIR__ . '/..' . '/symfony/routing/RouterInterface.php',
'Symfony\\Component\\Runtime\\GenericRuntime' => __DIR__ . '/..' . '/symfony/runtime/GenericRuntime.php',
'Symfony\\Component\\Runtime\\Internal\\BasicErrorHandler' => __DIR__ . '/..' . '/symfony/runtime/Internal/BasicErrorHandler.php',
'Symfony\\Component\\Runtime\\Internal\\ComposerPlugin' => __DIR__ . '/..' . '/symfony/runtime/Internal/ComposerPlugin.php',
'Symfony\\Component\\Runtime\\Internal\\MissingDotenv' => __DIR__ . '/..' . '/symfony/runtime/Internal/MissingDotenv.php',
'Symfony\\Component\\Runtime\\Internal\\SymfonyErrorHandler' => __DIR__ . '/..' . '/symfony/runtime/Internal/SymfonyErrorHandler.php',
'Symfony\\Component\\Runtime\\ResolverInterface' => __DIR__ . '/..' . '/symfony/runtime/ResolverInterface.php',
'Symfony\\Component\\Runtime\\Resolver\\ClosureResolver' => __DIR__ . '/..' . '/symfony/runtime/Resolver/ClosureResolver.php',
'Symfony\\Component\\Runtime\\Resolver\\DebugClosureResolver' => __DIR__ . '/..' . '/symfony/runtime/Resolver/DebugClosureResolver.php',
'Symfony\\Component\\Runtime\\RunnerInterface' => __DIR__ . '/..' . '/symfony/runtime/RunnerInterface.php',
'Symfony\\Component\\Runtime\\Runner\\ClosureRunner' => __DIR__ . '/..' . '/symfony/runtime/Runner/ClosureRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\ConsoleApplicationRunner' => __DIR__ . '/..' . '/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner' => __DIR__ . '/..' . '/symfony/runtime/Runner/Symfony/HttpKernelRunner.php',
'Symfony\\Component\\Runtime\\Runner\\Symfony\\ResponseRunner' => __DIR__ . '/..' . '/symfony/runtime/Runner/Symfony/ResponseRunner.php',
'Symfony\\Component\\Runtime\\RuntimeInterface' => __DIR__ . '/..' . '/symfony/runtime/RuntimeInterface.php',
'Symfony\\Component\\Runtime\\SymfonyRuntime' => __DIR__ . '/..' . '/symfony/runtime/SymfonyRuntime.php',
'Symfony\\Component\\Security\\Core\\AuthenticationEvents' => __DIR__ . '/..' . '/symfony/security-core/AuthenticationEvents.php',
'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolver' => __DIR__ . '/..' . '/symfony/security-core/Authentication/AuthenticationTrustResolver.php',
'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolverInterface' => __DIR__ . '/..' . '/symfony/security-core/Authentication/AuthenticationTrustResolverInterface.php',
@@ -3951,6 +3989,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Polyfill\\Intl\\Icu\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Exception/RuntimeException.php',
'Symfony\\Polyfill\\Intl\\Icu\\Icu' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Icu.php',
'Symfony\\Polyfill\\Intl\\Icu\\IntlDateFormatter' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/IntlDateFormatter.php',
'Symfony\\Polyfill\\Intl\\Icu\\IntlListFormatter' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/IntlListFormatter.php',
'Symfony\\Polyfill\\Intl\\Icu\\Locale' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Locale.php',
'Symfony\\Polyfill\\Intl\\Icu\\NumberFormatter' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/NumberFormatter.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Idn.php',
@@ -3960,6 +3999,13 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
'Symfony\\Polyfill\\Php83\\Php83' => __DIR__ . '/..' . '/symfony/polyfill-php83/Php83.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\ApplicationRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/Console/ApplicationRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Command\\CommandRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/Console/Command/CommandRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Input\\InputInterfaceRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/Console/Input/InputInterfaceRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\Console\\Output\\OutputInterfaceRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/Console/Output/OutputInterfaceRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpFoundation\\RequestRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/HttpFoundation/RequestRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpFoundation\\ResponseRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/HttpFoundation/ResponseRuntime.php',
'Symfony\\Runtime\\Symfony\\Component\\HttpKernel\\HttpKernelInterfaceRuntime' => __DIR__ . '/..' . '/symfony/runtime/Internal/HttpKernel/HttpKernelInterfaceRuntime.php',
'SynchroExceptionNotStarted' => __DIR__ . '/../..' . '/application/exceptions/SynchroExceptionNotStarted.php',
'System' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/System.php',
'TCPDF' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf.php',

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '3ccbfb2b130419fec9d1158836395a13baa0ec4b',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -22,9 +22,9 @@
'dev_requirement' => false,
),
'combodo/itop' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '3ccbfb2b130419fec9d1158836395a13baa0ec4b',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -49,9 +49,9 @@
'dev_requirement' => false,
),
'firebase/php-jwt' => array(
'pretty_version' => 'v7.0.3',
'version' => '7.0.3.0',
'reference' => '28aa0694bcfdfa5e2959c394d5a1ee7a5083629e',
'pretty_version' => 'v7.0.5',
'version' => '7.0.5.0',
'reference' => '47ad26bab5e7c70ae8a6f08ed25ff83631121380',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
@@ -76,9 +76,9 @@
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.8.0',
'version' => '2.8.0.0',
'reference' => '21dc724a0583619cd1652f673303492272778051',
'pretty_version' => '2.9.0',
'version' => '2.9.0.0',
'reference' => '7d0ed42f28e42d61352a7a79de682e5e67fec884',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
@@ -94,9 +94,9 @@
'dev_requirement' => false,
),
'league/oauth2-google' => array(
'pretty_version' => '4.1.0',
'version' => '4.1.0.0',
'reference' => '8b9bb43740ac6d994aca881a35f7bacbe98c0ffb',
'pretty_version' => '4.2.0',
'version' => '4.2.0.0',
'reference' => '72be69505f890ea8b6d4e716f619b3c10a1f5010',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-google',
'aliases' => array(),
@@ -105,7 +105,7 @@
'nikic/php-parser' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb',
'reference' => 'b27e577f70d2114b8ba96105e403017919a8611b',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(
@@ -312,9 +312,9 @@
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'a0a1690543329685c044362c873b78c6de9d4faa',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '5b94fba945d1f9e7929cffd50e7a17f1ac36f10b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
@@ -345,9 +345,9 @@
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '7b1f1c37eff5910ddda2831345467e593a5120ad',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '9f481cfb580db8bcecc9b2d4c63f3e13df022ad5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
@@ -362,10 +362,19 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/debug-bundle' => array(
'pretty_version' => 'v6.4.35',
'version' => '6.4.35.0',
'reference' => 'eb79084c2c9778559b21f61cb1507cbd580cc6e1',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/debug-bundle',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/dependency-injection' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '91e49958b8a6092e48e4711894a1aeb1b151c62a',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => 'cd7881a6dc84b780411199cd0584e1a53a3b9ba7',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dependency-injection',
'aliases' => array(),
@@ -381,27 +390,27 @@
'dev_requirement' => false,
),
'symfony/dotenv' => array(
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '924edbc9631b75302def0258ed1697948b17baf6',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => 'cae019cc92a46fe9e498ea011107f26bdf5d897f',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dotenv',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/error-handler' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '8c18400784fcb014dc73c8d5601a9576af7f8ad4',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '2ea68f0e1835ad6a126f93bbc14cd236c10ab361',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/error-handler',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '99d7e101826e6610606b9433248f80c1997cd20b',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => 'fc828863e26ceec86e2513b5e46aa0b149d76b69',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
@@ -441,36 +450,36 @@
'dev_requirement' => false,
),
'symfony/form' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'ed9275a133809bb48d949ba6dfdc808a819ebea2',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '3a38a81150400f0a486f8963e21a195311b30b27',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/form',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/framework-bundle' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5b5d19473f22d699811a41b01cef2462bc42b238',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '147b02cfa45dcc74a290462551f5ee5c7fa8ab17',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/framework-bundle',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-foundation' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5bb346d1b4b2a616e5c3d99b3ee4d5810735c535',
'pretty_version' => 'v6.4.35',
'version' => '6.4.35.0',
'reference' => 'cffffd0a2c037117b742b4f8b379a22a2a33f6d2',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-kernel' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '006a49fc4f41ee21a6ca61e69caed1c30b29f07c',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '4087ec02119de450e9ebb60806d69c6bb8c6e468',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-kernel',
'aliases' => array(),
@@ -486,9 +495,9 @@
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '2b32fbbe10b36a8379efab6e702ad8b917151839',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '9c31726137c70798f815fb98293ffb8a2a47694c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
@@ -513,35 +522,35 @@
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '141046a8f9477948ff284fa65be2095baafb94f2',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => 'ad1b7b9092976d6c948b8a187cec9faaea9ec1df',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-icu' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => 'bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '3510b63d07376b04e57e27e82607d468bb134f78',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-icu',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
@@ -549,8 +558,8 @@
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '3833d7255cc303546435cb650316bff708a1c75c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
@@ -558,18 +567,18 @@
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '6a21eb99c6973357967f6ce3708cd55a6bec6315',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php83' => array(
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => '17f6f9a6b1735c0f163024d959f700cfbc5155e5',
'pretty_version' => 'v1.36.0',
'version' => '1.36.0.0',
'reference' => '3600c2cb22399e25bb226e4a135ce91eeb2a6149',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php83',
'aliases' => array(),
@@ -602,10 +611,19 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/runtime' => array(
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => 'fb3149ee85d3b639dd3e49ea9dda05656f0537e3',
'type' => 'composer-plugin',
'install_path' => __DIR__ . '/../symfony/runtime',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/security-core' => array(
'pretty_version' => 'v6.4.31',
'version' => '6.4.31.0',
'reference' => 'fa269ad61a021cc54329dc96e57bed78ba720bfe',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '1b7db28bcc3655543abfe58764025aef563705cd',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/security-core',
'aliases' => array(),
@@ -663,9 +681,9 @@
'dev_requirement' => false,
),
'symfony/twig-bridge' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5169074f4a88dfb02eeccddaba78edfdf212a9b2',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '3ae963a108fd6fc14d09a7fe5e41fe64d8ac11ba',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/twig-bridge',
'aliases' => array(),
@@ -681,36 +699,36 @@
'dev_requirement' => false,
),
'symfony/validator' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '7c3897b7f739d4ab913481e680405ca82d08084d',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '14921e87b2bd69dfbd9757cdb1c6974a1316aac5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/validator',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '131fc9915e0343052af5ed5040401b481ca192aa',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '7c8ad9ce4faf6c8a99948e70ce02b601a0439782',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-exporter' => array(
'pretty_version' => 'v6.4.26',
'version' => '6.4.26.0',
'reference' => '466fcac5fa2e871f83d31173f80e9c2684743bfc',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => 'f9c4a9695a9e2bbc65c920e147d8d7ae28f8d79a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-exporter',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/web-profiler-bundle' => array(
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '848bc5d5745500f855bb201d57ae066fd7e67448',
'pretty_version' => 'v6.4.36',
'version' => '6.4.36.0',
'reference' => '6f75b4c748886c8e04a3674225d00eaa51f3842d',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/web-profiler-bundle',
'aliases' => array(),
@@ -726,9 +744,9 @@
'dev_requirement' => false,
),
'tecnickcom/tcpdf' => array(
'pretty_version' => '6.11.0',
'version' => '6.11.0.0',
'reference' => '81172e58edb1cfae4019ef150ccbdc0e9a8c85c9',
'pretty_version' => '6.11.2',
'version' => '6.11.2.0',
'reference' => 'e1e2ade18e574e963473f53271591edd8c0033ec',
'type' => 'library',
'install_path' => __DIR__ . '/../tecnickcom/tcpdf',
'aliases' => array(),
@@ -744,9 +762,9 @@
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v3.23.0',
'version' => '3.23.0.0',
'reference' => 'a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9',
'pretty_version' => 'v3.24.0',
'version' => '3.24.0.0',
'reference' => 'a6769aefb305efef849dc25c9fd1653358c148f0',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),

View File

@@ -4,8 +4,8 @@
$issues = array();
if (!(PHP_VERSION_ID >= 80100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
if (!(PHP_VERSION_ID >= 80200)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
}
$missingExtensions = array();

View File

@@ -1,5 +1,20 @@
# Changelog
## [7.0.5](https://github.com/firebase/php-jwt/compare/v7.0.4...v7.0.5) (2026-03-31)
### Bug Fixes
* RSA from JWK sometimes returns empty Instance ([#628](https://github.com/firebase/php-jwt/issues/628)) ([b4c78aa](https://github.com/firebase/php-jwt/commit/b4c78aa731664122198ad36c0033aa29e807397a))
## [7.0.4](https://github.com/firebase/php-jwt/compare/v7.0.3...v7.0.4) (2026-03-27)
### Bug Fixes
* readme examples, add tests for all examples ([#626](https://github.com/firebase/php-jwt/issues/626)) ([510a00c](https://github.com/firebase/php-jwt/commit/510a00c0e6353bc7d68412fab67e57a13954cb46))
* use urlsafeB64Decode everywhere ([#627](https://github.com/firebase/php-jwt/issues/627)) ([b889495](https://github.com/firebase/php-jwt/commit/b889495c83ddc3f3885ca3f0b65b41b1cb37a3b1))
## [7.0.3](https://github.com/firebase/php-jwt/compare/v7.0.2...v7.0.3) (2026-02-18)

View File

@@ -23,16 +23,16 @@ php env does not have libsodium installed:
composer require paragonie/sodium_compat
```
Example
-------
## Example
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$key = 'example_key';
$key = 'example_key_of_sufficient_length';
$payload = [
'iss' => 'http://example.org',
'aud' => 'http://example.com',
'iss' => 'example.org',
'aud' => 'example.com',
'iat' => 1356999524,
'nbf' => 1357000000
];
@@ -69,8 +69,9 @@ $decoded_array = (array) $decoded;
JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
```
Example encode/decode headers
-------
## Example encode/decode headers
Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by
this library. This is because without verifying the JWT, the header values could have been tampered with.
Any value pulled from an unverified header should be treated as if it could be any string sent in from an
@@ -80,10 +81,10 @@ header part:
```php
use Firebase\JWT\JWT;
$key = 'example_key';
$key = 'example_key_of_sufficient_length';
$payload = [
'iss' => 'http://example.org',
'aud' => 'http://example.com',
'iss' => 'example.org',
'aud' => 'example.com',
'iat' => 1356999524,
'nbf' => 1357000000
];
@@ -103,8 +104,9 @@ $decoded = json_decode(base64_decode($headersB64), true);
print_r($decoded);
```
Example with RS256 (openssl)
----------------------------
## Example with RS256 (openssl)
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
@@ -172,8 +174,7 @@ $decoded_array = (array) $decoded;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
```
Example with a passphrase
-------------------------
## Example with a passphrase
```php
use Firebase\JWT\JWT;
@@ -209,8 +210,8 @@ $decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
```
Example with EdDSA (libsodium and Ed25519 signature)
----------------------------
## Example with EdDSA (libsodium and Ed25519 signature)
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
@@ -238,21 +239,21 @@ echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
````
```
## Example with multiple keys
Example with multiple keys
--------------------------
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// Example RSA keys from previous example
// $privateKey1 = '...';
// $publicKey1 = '...';
// $privateRsKey = '...';
// $publicRsKey = '...';
// Example EdDSA keys from previous example
// $privateKey2 = '...';
// $publicKey2 = '...';
// $privateEcKey = '...';
// $publicEcKey = '...';
$payload = [
'iss' => 'example.org',
@@ -261,14 +262,14 @@ $payload = [
'nbf' => 1357000000
];
$jwt1 = JWT::encode($payload, $privateKey1, 'RS256', 'kid1');
$jwt2 = JWT::encode($payload, $privateKey2, 'EdDSA', 'kid2');
$jwt1 = JWT::encode($payload, $privateRsKey, 'RS256', 'kid1');
$jwt2 = JWT::encode($payload, $privateEcKey, 'EdDSA', 'kid2');
echo "Encode 1:\n" . print_r($jwt1, true) . "\n";
echo "Encode 2:\n" . print_r($jwt2, true) . "\n";
$keys = [
'kid1' => new Key($publicKey1, 'RS256'),
'kid2' => new Key($publicKey2, 'EdDSA'),
'kid1' => new Key($publicRsKey, 'RS256'),
'kid2' => new Key($publicEcKey, 'EdDSA'),
];
$decoded1 = JWT::decode($jwt1, $keys);
@@ -278,8 +279,7 @@ echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n";
echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n";
```
Using JWKs
----------
## Using JWKs
```php
use Firebase\JWT\JWK;
@@ -291,11 +291,11 @@ $jwks = ['keys' => []];
// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
// objects. Pass this as the second parameter to JWT::decode.
JWT::decode($jwt, JWK::parseKeySet($jwks));
$decoded = JWT::decode($jwt, JWK::parseKeySet($jwks));
print_r($decoded);
```
Using Cached Key Sets
---------------------
## Using Cached Key Sets
The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI.
This has the following advantages:
@@ -315,7 +315,7 @@ $jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk';
$httpClient = new GuzzleHttp\Client();
// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory)
$httpFactory = new GuzzleHttp\Psr\HttpFactory();
$httpFactory = new GuzzleHttp\Psr7\HttpFactory();
// Create a cache item pool (can be any PSR-6 compatible cache item pool)
$cacheItemPool = Phpfastcache\CacheManager::getInstance('files');
@@ -406,8 +406,8 @@ Tests
Run the tests using phpunit:
```bash
$ pear install PHPUnit
$ phpunit --configuration phpunit.xml.dist
$ composer update
$ vendor/bin/phpunit -c phpunit.xml.dist
PHPUnit 3.7.10 by Sebastian Bergmann.
.....
Time: 0 seconds, Memory: 2.50Mb

View File

@@ -37,6 +37,7 @@
"phpunit/phpunit": "^9.5",
"psr/cache": "^2.0||^3.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
"psr/http-factory": "^1.0",
"phpfastcache/phpfastcache": "^9.2"
}
}

View File

@@ -180,7 +180,8 @@ class CachedKeySet implements ArrayAccess
$jwksResponse = $this->httpClient->sendRequest($request);
if ($jwksResponse->getStatusCode() !== 200) {
throw new UnexpectedValueException(
\sprintf('HTTP Error: %d %s for URI "%s"',
\sprintf(
'HTTP Error: %d %s for URI "%s"',
$jwksResponse->getStatusCode(),
$jwksResponse->getReasonPhrase(),
$this->jwksUri,

View File

@@ -240,6 +240,14 @@ class JWK
): string {
$mod = JWT::urlsafeB64Decode($n);
$exp = JWT::urlsafeB64Decode($e);
// Correct encoding for ASN1, as ints are represented as unsigned in jwk
// but signed in ASN1. Prepending null byte makes it unsigned.
if (\strlen($mod) > 0 && \ord($mod[0]) >= 128) {
$mod = \chr(0) . $mod;
}
if (\strlen($exp) > 0 && \ord($exp[0]) >= 128) {
$exp = \chr(0) . $exp;
}
$modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
$publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);

View File

@@ -31,7 +31,7 @@ class JWT
private const ASN1_SEQUENCE = 0x10;
private const ASN1_BIT_STRING = 0x03;
private const RSA_KEY_MIN_LENGTH=2048;
private const RSA_KEY_MIN_LENGTH = 2048;
/**
* When checking nbf, iat or expiration times,
@@ -284,20 +284,8 @@ class JWT
}
return $signature;
case 'sodium_crypto':
if (!\function_exists('sodium_crypto_sign_detached')) {
throw new DomainException('libsodium is not available');
}
if (!\is_string($key)) {
throw new InvalidArgumentException('key must be a string when using EdDSA');
}
try {
// The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $key));
$key = base64_decode((string) end($lines));
if (\strlen($key) === 0) {
throw new DomainException('Key cannot be empty string');
}
return sodium_crypto_sign_detached($msg, $key);
return sodium_crypto_sign_detached($msg, self::validateEdDSAKey($key));
} catch (Exception $e) {
throw new DomainException($e->getMessage(), 0, $e);
}
@@ -352,19 +340,8 @@ class JWT
'OpenSSL error: ' . \openssl_error_string()
);
case 'sodium_crypto':
if (!\function_exists('sodium_crypto_sign_verify_detached')) {
throw new DomainException('libsodium is not available');
}
if (!\is_string($keyMaterial)) {
throw new InvalidArgumentException('key must be a string when using EdDSA');
}
try {
// The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $keyMaterial));
$key = base64_decode((string) end($lines));
if (\strlen($key) === 0) {
throw new DomainException('Key cannot be empty string');
}
$key = self::validateEdDSAKey($keyMaterial);
if (\strlen($signature) === 0) {
throw new DomainException('Signature cannot be empty string');
}
@@ -473,7 +450,6 @@ class JWT
return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
}
/**
* Determine if an algorithm has been provided for each Key
*
@@ -745,4 +721,25 @@ class JWT
throw new DomainException('Provided key is too short');
}
}
/**
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @return non-empty-string
*/
private static function validateEdDSAKey(#[\SensitiveParameter] $keyMaterial): string
{
if (!\function_exists('sodium_crypto_sign_verify_detached')) {
throw new DomainException('libsodium is not available');
}
if (!\is_string($keyMaterial)) {
throw new InvalidArgumentException('key must be a string when using EdDSA');
}
// The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $keyMaterial));
$key = self::urlsafeB64Decode((string) end($lines));
if (\strlen($key) === 0) {
throw new DomainException('Key cannot be empty string');
}
return $key;
}
}

View File

@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 2.9.0 - 2026-03-10
### Added
- Added nested array expansion support to `MultipartStream`
- Added `@return static` to `MessageTrait` methods
### Changed
- Updated MIME type mappings
## 2.8.1 - 2026-03-10
### Fixed
- Encode `+` signs in `Uri::withQueryValue()` and `Uri::withQueryValues()` to prevent them being interpreted as spaces
## 2.8.0 - 2025-08-23
### Added

View File

@@ -49,6 +49,19 @@
"homepage": "https://sagikazarmark.hu"
}
],
"repositories": [
{
"type": "package",
"package": {
"name": "jshttp/mime-db",
"version": "1.54.0.1",
"dist": {
"url": "https://codeload.github.com/jshttp/mime-db/zip/0a9fd0bfbc87a725ff638495839114e7807b7177",
"type": "zip"
}
}
}
],
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
@@ -62,6 +75,7 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"jshttp/mime-db": "1.54.0.1",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {

View File

@@ -63,9 +63,9 @@ final class LimitStream implements StreamInterface
return null;
} elseif ($this->limit === -1) {
return $length - $this->offset;
} else {
return min($this->limit, $length - $this->offset);
}
return min($this->limit, $length - $this->offset);
}
/**

View File

@@ -29,6 +29,9 @@ trait MessageTrait
return $this->protocol;
}
/**
* @return static
*/
public function withProtocolVersion($version): MessageInterface
{
if ($this->protocol === $version) {
@@ -69,6 +72,9 @@ trait MessageTrait
return implode(', ', $this->getHeader($header));
}
/**
* @return static
*/
public function withHeader($header, $value): MessageInterface
{
$this->assertHeader($header);
@@ -85,6 +91,9 @@ trait MessageTrait
return $new;
}
/**
* @return static
*/
public function withAddedHeader($header, $value): MessageInterface
{
$this->assertHeader($header);
@@ -103,6 +112,9 @@ trait MessageTrait
return $new;
}
/**
* @return static
*/
public function withoutHeader($header): MessageInterface
{
$normalized = strtolower($header);
@@ -128,6 +140,9 @@ trait MessageTrait
return $this->stream;
}
/**
* @return static
*/
public function withBody(StreamInterface $body): MessageInterface
{
if ($body === $this->stream) {

View File

@@ -7,22 +7,23 @@ namespace GuzzleHttp\Psr7;
final class MimeType
{
private const MIME_TYPES = [
'123' => 'application/vnd.lotus-1-2-3',
'1km' => 'application/vnd.1000minds.decision-model+xml',
'210' => 'model/step',
'3dml' => 'text/vnd.in3d.3dml',
'3ds' => 'image/x-3ds',
'3g2' => 'video/3gpp2',
'3gp' => 'video/3gp',
'3gp' => 'video/3gpp',
'3gpp' => 'video/3gpp',
'3mf' => 'model/3mf',
'7z' => 'application/x-7z-compressed',
'7zip' => 'application/x-7z-compressed',
'123' => 'application/vnd.lotus-1-2-3',
'aab' => 'application/x-authorware-bin',
'aac' => 'audio/aac',
'aam' => 'application/x-authorware-map',
'aas' => 'application/x-authorware-seg',
'abw' => 'application/x-abiword',
'ac' => 'application/vnd.nokia.n-gage.ac+xml',
'ac' => 'application/pkix-attr-cert',
'ac3' => 'audio/ac3',
'acc' => 'application/vnd.americandynamics.acc',
'ace' => 'application/x-ace-compressed',
@@ -35,7 +36,7 @@ final class MimeType
'afp' => 'application/vnd.ibm.modcap',
'age' => 'application/vnd.age',
'ahead' => 'application/vnd.ahead.space',
'ai' => 'application/pdf',
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
@@ -55,7 +56,7 @@ final class MimeType
'apr' => 'application/vnd.lotus-approach',
'arc' => 'application/x-freearc',
'arj' => 'application/x-arj',
'asc' => 'application/pgp-signature',
'asc' => 'application/pgp-keys',
'asf' => 'video/x-ms-asf',
'asm' => 'text/x-asm',
'aso' => 'application/vnd.accpac.simply.aso',
@@ -66,7 +67,7 @@ final class MimeType
'atomdeleted' => 'application/atomdeleted+xml',
'atomsvc' => 'application/atomsvc+xml',
'atx' => 'application/vnd.antix.game-component',
'au' => 'audio/x-au',
'au' => 'audio/basic',
'avci' => 'image/avci',
'avcs' => 'image/avcs',
'avi' => 'video/x-msvideo',
@@ -77,15 +78,18 @@ final class MimeType
'azv' => 'image/vnd.airzip.accelerator.azv',
'azw' => 'application/vnd.amazon.ebook',
'b16' => 'image/vnd.pco.b16',
'bary' => 'model/vnd.bary',
'bat' => 'application/x-msdownload',
'bcpio' => 'application/x-bcpio',
'bdf' => 'application/x-font-bdf',
'bdm' => 'application/vnd.syncml.dm+wbxml',
'bdoc' => 'application/x-bdoc',
'bdo' => 'application/vnd.nato.bindingdataobject+xml',
'bdoc' => 'application/bdoc',
'bed' => 'application/vnd.realvnc.bed',
'bh2' => 'application/vnd.fujitsu.oasysprs',
'bin' => 'application/octet-stream',
'blb' => 'application/x-blorb',
'blend' => 'application/x-blender',
'blorb' => 'application/x-blorb',
'bmi' => 'application/vnd.bmi',
'bmml' => 'application/vnd.balsamiq.bmml+xml',
@@ -95,6 +99,8 @@ final class MimeType
'boz' => 'application/x-bzip2',
'bpk' => 'application/octet-stream',
'bpmn' => 'application/octet-stream',
'brush' => 'application/vnd.procreate.brush',
'brushset' => 'application/vnd.procreate.brushset',
'bsp' => 'model/vnd.valve.source.compiled-map',
'btf' => 'image/prs.btif',
'btif' => 'image/prs.btif',
@@ -102,13 +108,13 @@ final class MimeType
'bz' => 'application/x-bzip',
'bz2' => 'application/x-bzip2',
'c' => 'text/x-c',
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
'c4d' => 'application/vnd.clonk.c4group',
'c4f' => 'application/vnd.clonk.c4group',
'c4g' => 'application/vnd.clonk.c4group',
'c4p' => 'application/vnd.clonk.c4group',
'c4u' => 'application/vnd.clonk.c4group',
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
'cab' => 'application/vnd.ms-cab-compressed',
'caf' => 'audio/x-caf',
'cap' => 'application/vnd.tcpdump.pcap',
@@ -132,7 +138,6 @@ final class MimeType
'cdmid' => 'application/cdmi-domain',
'cdmio' => 'application/cdmi-object',
'cdmiq' => 'application/cdmi-queue',
'cdr' => 'application/cdr',
'cdx' => 'chemical/x-cdx',
'cdxml' => 'application/vnd.chemdraw+xml',
'cdy' => 'application/vnd.cinderella',
@@ -147,7 +152,7 @@ final class MimeType
'cil' => 'application/vnd.ms-artgalry',
'cjs' => 'application/node',
'cla' => 'application/vnd.claymore',
'class' => 'application/octet-stream',
'class' => 'application/java-vm',
'cld' => 'model/vnd.cld',
'clkk' => 'application/vnd.crick.clicker.keyboard',
'clkp' => 'application/vnd.crick.clicker.palette',
@@ -194,6 +199,8 @@ final class MimeType
'davmount' => 'application/davmount+xml',
'dbf' => 'application/vnd.dbf',
'dbk' => 'application/docbook+xml',
'dcm' => 'application/dicom',
'dcmp' => 'application/vnd.dcmp+xml',
'dcr' => 'application/x-director',
'dcurl' => 'text/vnd.curl.dcurl',
'dd2' => 'application/vnd.oma.dd2+xml',
@@ -221,19 +228,22 @@ final class MimeType
'dmp' => 'application/vnd.tcpdump.pcap',
'dms' => 'application/octet-stream',
'dna' => 'application/vnd.dna',
'dng' => 'image/x-adobe-dng',
'doc' => 'application/msword',
'docm' => 'application/vnd.ms-word.template.macroEnabled.12',
'docm' => 'application/vnd.ms-word.document.macroenabled.12',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dot' => 'application/msword',
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dp' => 'application/vnd.osgi.dp',
'dpg' => 'application/vnd.dpgraph',
'dpx' => 'image/dpx',
'dra' => 'audio/vnd.dra',
'drle' => 'image/dicom-rle',
'drm' => 'application/vnd.procreate.dream',
'dsc' => 'text/prs.lines.tag',
'dssc' => 'application/dssc+der',
'dst' => 'application/octet-stream',
'dtb' => 'application/x-dtbook+xml',
'dtd' => 'application/xml-dtd',
'dts' => 'audio/vnd.dts',
@@ -285,10 +295,12 @@ final class MimeType
'f4v' => 'video/mp4',
'f77' => 'text/x-fortran',
'f90' => 'text/x-fortran',
'facti' => 'image/vnd.blockfact.facti',
'fbs' => 'image/vnd.fastbidsheet',
'fbx' => 'application/vnd.autodesk.fbx',
'fcdt' => 'application/vnd.adobe.formscentral.fcdt',
'fcs' => 'application/vnd.isac.fcs',
'fdf' => 'application/vnd.fdf',
'fdf' => 'application/fdf',
'fdt' => 'application/fdt+xml',
'fe_launch' => 'application/vnd.denovo.fcselayout-link',
'fg5' => 'application/vnd.fujitsu.oasysgp',
@@ -330,21 +342,25 @@ final class MimeType
'gca' => 'application/x-gca-compressed',
'gdl' => 'model/vnd.gdl',
'gdoc' => 'application/vnd.google-apps.document',
'gdraw' => 'application/vnd.google-apps.drawing',
'ged' => 'text/vnd.familysearch.gedcom',
'geo' => 'application/vnd.dynageo',
'geojson' => 'application/geo+json',
'gex' => 'application/vnd.geometry-explorer',
'gform' => 'application/vnd.google-apps.form',
'ggb' => 'application/vnd.geogebra.file',
'ggs' => 'application/vnd.geogebra.slides',
'ggt' => 'application/vnd.geogebra.tool',
'ghf' => 'application/vnd.groove-help',
'gif' => 'image/gif',
'gim' => 'application/vnd.groove-identity-message',
'gjam' => 'application/vnd.google-apps.jam',
'glb' => 'model/gltf-binary',
'gltf' => 'model/gltf+json',
'gmap' => 'application/vnd.google-apps.map',
'gml' => 'application/gml+xml',
'gmx' => 'application/vnd.gmx',
'gnumeric' => 'application/x-gnumeric',
'gpg' => 'application/gpg-keys',
'gph' => 'application/vnd.flographit',
'gpx' => 'application/gpx+xml',
'gqf' => 'application/vnd.grafeq',
@@ -354,8 +370,10 @@ final class MimeType
'gre' => 'application/vnd.geometry-explorer',
'grv' => 'application/vnd.groove-injector',
'grxml' => 'application/srgs+xml',
'gscript' => 'application/vnd.google-apps.script',
'gsf' => 'application/x-font-ghostscript',
'gsheet' => 'application/vnd.google-apps.spreadsheet',
'gsite' => 'application/vnd.google-apps.site',
'gslides' => 'application/vnd.google-apps.presentation',
'gtar' => 'application/x-gtar',
'gtm' => 'application/vnd.groove-tool-message',
@@ -387,7 +405,6 @@ final class MimeType
'hpid' => 'application/vnd.hp-hpid',
'hps' => 'application/vnd.hp-hps',
'hqx' => 'application/mac-binhex40',
'hsj2' => 'image/hsj2',
'htc' => 'text/x-component',
'htke' => 'application/vnd.kenameaapp',
'htm' => 'text/html',
@@ -399,7 +416,7 @@ final class MimeType
'icc' => 'application/vnd.iccprofile',
'ice' => 'x-conference/x-cooltalk',
'icm' => 'application/vnd.iccprofile',
'ico' => 'image/x-icon',
'ico' => 'image/vnd.microsoft.icon',
'ics' => 'text/calendar',
'ief' => 'image/ief',
'ifb' => 'text/calendar',
@@ -414,6 +431,7 @@ final class MimeType
'imp' => 'application/vnd.accpac.simply.imp',
'ims' => 'application/vnd.ms-ims',
'in' => 'text/plain',
'indd' => 'application/x-indesign',
'ini' => 'text/plain',
'ink' => 'application/inkml+xml',
'inkml' => 'application/inkml+xml',
@@ -421,6 +439,7 @@ final class MimeType
'iota' => 'application/vnd.astraea-software.iota',
'ipfix' => 'application/ipfix',
'ipk' => 'application/vnd.shana.informed.package',
'ipynb' => 'application/x-ipynb+json',
'irm' => 'application/vnd.ibm.rights-management',
'irp' => 'application/vnd.irepository.package+xml',
'iso' => 'application/x-iso9660-image',
@@ -430,10 +449,13 @@ final class MimeType
'ivu' => 'application/vnd.immervision-ivu',
'jad' => 'text/vnd.sun.j2me.app-descriptor',
'jade' => 'text/jade',
'jaii' => 'image/jaii',
'jais' => 'image/jais',
'jam' => 'application/vnd.jam',
'jar' => 'application/java-archive',
'jardiff' => 'application/x-java-archive-diff',
'java' => 'text/x-java-source',
'jfif' => 'image/jpeg',
'jhc' => 'image/jphc',
'jisp' => 'application/vnd.jisp',
'jls' => 'image/jls',
@@ -447,18 +469,19 @@ final class MimeType
'jpf' => 'image/jpx',
'jpg' => 'image/jpeg',
'jpg2' => 'image/jp2',
'jpgm' => 'video/jpm',
'jpgm' => 'image/jpm',
'jpgv' => 'video/jpeg',
'jph' => 'image/jph',
'jpm' => 'video/jpm',
'jpm' => 'image/jpm',
'jpx' => 'image/jpx',
'js' => 'application/javascript',
'js' => 'text/javascript',
'json' => 'application/json',
'json5' => 'application/json5',
'jsonld' => 'application/ld+json',
'jsonml' => 'application/jsonml+json',
'jsx' => 'text/jsx',
'jt' => 'model/jt',
'jxl' => 'image/jxl',
'jxr' => 'image/jxr',
'jxra' => 'image/jxra',
'jxrs' => 'image/jxrs',
@@ -468,9 +491,10 @@ final class MimeType
'jxss' => 'image/jxss',
'kar' => 'audio/midi',
'karbon' => 'application/vnd.kde.karbon',
'kbl' => 'application/kbl+xml',
'kdb' => 'application/octet-stream',
'kdbx' => 'application/x-keepass2',
'key' => 'application/x-iwork-keynote-sffkey',
'key' => 'application/vnd.apple.keynote',
'kfo' => 'application/vnd.kde.kformula',
'kia' => 'application/vnd.kidspiration',
'kml' => 'application/vnd.google-earth.kml+xml',
@@ -495,7 +519,7 @@ final class MimeType
'les' => 'application/vnd.hhe.lesson-player',
'less' => 'text/less',
'lgr' => 'application/lgr+xml',
'lha' => 'application/octet-stream',
'lha' => 'application/x-lzh-compressed',
'link66' => 'application/vnd.route66.link66+xml',
'list' => 'text/plain',
'list3820' => 'application/vnd.ibm.modcap',
@@ -504,6 +528,7 @@ final class MimeType
'lnk' => 'application/x-ms-shortcut',
'log' => 'text/plain',
'lostxml' => 'application/lost+xml',
'lottie' => 'application/zip+dotlottie',
'lrf' => 'application/octet-stream',
'lrm' => 'application/vnd.ms-lrm',
'ltf' => 'application/vnd.frogans.ltf',
@@ -511,21 +536,24 @@ final class MimeType
'luac' => 'application/x-lua-bytecode',
'lvp' => 'audio/vnd.lucent.voice',
'lwp' => 'application/vnd.lotus-wordpro',
'lzh' => 'application/octet-stream',
'm1v' => 'video/mpeg',
'm2a' => 'audio/mpeg',
'm2v' => 'video/mpeg',
'm3a' => 'audio/mpeg',
'm3u' => 'text/plain',
'm3u8' => 'application/vnd.apple.mpegurl',
'm4a' => 'audio/x-m4a',
'm4p' => 'application/mp4',
'm4s' => 'video/iso.segment',
'm4u' => 'application/vnd.mpegurl',
'm4v' => 'video/x-m4v',
'lzh' => 'application/x-lzh-compressed',
'm13' => 'application/x-msmediaview',
'm14' => 'application/x-msmediaview',
'm1v' => 'video/mpeg',
'm21' => 'application/mp21',
'm2a' => 'audio/mpeg',
'm2t' => 'video/mp2t',
'm2ts' => 'video/mp2t',
'm2v' => 'video/mpeg',
'm3a' => 'audio/mpeg',
'm3u' => 'audio/x-mpegurl',
'm3u8' => 'application/vnd.apple.mpegurl',
'm4a' => 'audio/mp4',
'm4b' => 'audio/mp4',
'm4p' => 'application/mp4',
'm4s' => 'video/iso.segment',
'm4u' => 'video/vnd.mpegurl',
'm4v' => 'video/x-m4v',
'ma' => 'application/mathematica',
'mads' => 'application/mads+xml',
'maei' => 'application/mmt-aei+xml',
@@ -556,6 +584,8 @@ final class MimeType
'mft' => 'application/rpki-manifest',
'mgp' => 'application/vnd.osgeo.mapguide.package',
'mgz' => 'application/vnd.proteus.magazine',
'mht' => 'message/rfc822',
'mhtml' => 'message/rfc822',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mie' => 'application/x-mie',
@@ -564,11 +594,11 @@ final class MimeType
'mj2' => 'video/mj2',
'mjp2' => 'video/mj2',
'mjs' => 'text/javascript',
'mk3d' => 'video/x-matroska',
'mka' => 'audio/x-matroska',
'mk3d' => 'video/matroska-3d',
'mka' => 'audio/matroska',
'mkd' => 'text/x-markdown',
'mks' => 'video/x-matroska',
'mkv' => 'video/x-matroska',
'mkv' => 'video/matroska',
'mlp' => 'application/vnd.dolby.mlp',
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
'mmf' => 'application/vnd.smaf',
@@ -581,13 +611,13 @@ final class MimeType
'mov' => 'video/quicktime',
'movie' => 'video/x-sgi-movie',
'mp2' => 'audio/mpeg',
'mp21' => 'application/mp21',
'mp2a' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
'mp4s' => 'application/mp4',
'mp4v' => 'video/mp4',
'mp21' => 'application/mp21',
'mpc' => 'application/vnd.mophun.certificate',
'mpd' => 'application/dash+xml',
'mpe' => 'video/mpeg',
@@ -612,7 +642,7 @@ final class MimeType
'msf' => 'application/vnd.epson.msf',
'msg' => 'application/vnd.ms-outlook',
'msh' => 'model/mesh',
'msi' => 'application/x-msdownload',
'msi' => 'application/octet-stream',
'msix' => 'application/msix',
'msixbundle' => 'application/msixbundle',
'msl' => 'application/vnd.mobius.msl',
@@ -620,7 +650,7 @@ final class MimeType
'msp' => 'application/octet-stream',
'msty' => 'application/vnd.muvee.style',
'mtl' => 'model/mtl',
'mts' => 'model/vnd.mts',
'mts' => 'video/mp2t',
'mus' => 'application/vnd.musician',
'musd' => 'application/mmt-usd+xml',
'musicxml' => 'application/vnd.recordare.musicxml+xml',
@@ -639,6 +669,7 @@ final class MimeType
'nbp' => 'application/vnd.wolfram.player',
'nc' => 'application/x-netcdf',
'ncx' => 'application/x-dtbncx+xml',
'ndjson' => 'application/x-ndjson',
'nfo' => 'text/x-nfo',
'ngdat' => 'application/vnd.nokia.n-gage.data',
'nitf' => 'application/vnd.nitf',
@@ -653,7 +684,7 @@ final class MimeType
'nsf' => 'application/vnd.lotus-notes',
'nt' => 'application/n-triples',
'ntf' => 'application/vnd.nitf',
'numbers' => 'application/x-iwork-numbers-sffnumbers',
'numbers' => 'application/vnd.apple.numbers',
'nzb' => 'application/x-nzb',
'oa2' => 'application/vnd.fujitsu.oasys2',
'oa3' => 'application/vnd.fujitsu.oasys3',
@@ -678,6 +709,8 @@ final class MimeType
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'omdoc' => 'application/omdoc+xml',
'one' => 'application/onenote',
'onea' => 'application/onenote',
'onepkg' => 'application/onenote',
'onetmp' => 'application/onenote',
'onetoc' => 'application/onenote',
@@ -686,7 +719,7 @@ final class MimeType
'opml' => 'text/x-opml',
'oprc' => 'application/vnd.palm',
'opus' => 'audio/ogg',
'org' => 'text/x-org',
'org' => 'application/vnd.lotus-organizer',
'osf' => 'application/vnd.yamaha.openscoreformat',
'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
'osm' => 'application/vnd.openstreetmap.data+xml',
@@ -704,17 +737,20 @@ final class MimeType
'oxps' => 'application/oxps',
'oxt' => 'application/vnd.openofficeorg.extension',
'p' => 'text/x-pascal',
'p10' => 'application/pkcs10',
'p12' => 'application/x-pkcs12',
'p21' => 'model/step',
'p7a' => 'application/x-pkcs7-signature',
'p7b' => 'application/x-pkcs7-certificates',
'p7c' => 'application/pkcs7-mime',
'p7e' => 'application/pkcs7-mime',
'p7m' => 'application/pkcs7-mime',
'p7r' => 'application/x-pkcs7-certreqresp',
'p7s' => 'application/pkcs7-signature',
'p8' => 'application/pkcs8',
'p10' => 'application/x-pkcs10',
'p12' => 'application/x-pkcs12',
'pac' => 'application/x-ns-proxy-autoconfig',
'pages' => 'application/x-iwork-pages-sffpages',
'pages' => 'application/vnd.apple.pages',
'parquet' => 'application/vnd.apache.parquet',
'pas' => 'text/x-pascal',
'paw' => 'application/vnd.pawaafile',
'pbd' => 'application/vnd.powerbuilder6',
@@ -725,8 +761,8 @@ final class MimeType
'pclxl' => 'application/vnd.hp-pclxl',
'pct' => 'image/x-pict',
'pcurl' => 'application/vnd.curl.pcurl',
'pcx' => 'image/x-pcx',
'pdb' => 'application/x-pilot',
'pcx' => 'image/vnd.zbrush.pcx',
'pdb' => 'application/vnd.palm',
'pde' => 'text/x-processing',
'pdf' => 'application/pdf',
'pem' => 'application/x-x509-user-cert',
@@ -737,7 +773,7 @@ final class MimeType
'pfx' => 'application/x-pkcs12',
'pgm' => 'image/x-portable-graymap',
'pgn' => 'application/x-chess-pgn',
'pgp' => 'application/pgp',
'pgp' => 'application/pgp-encrypted',
'phar' => 'application/octet-stream',
'php' => 'application/x-httpd-php',
'php3' => 'application/x-httpd-php',
@@ -760,17 +796,17 @@ final class MimeType
'pnm' => 'image/x-portable-anymap',
'portpkg' => 'application/vnd.macports.portpkg',
'pot' => 'application/vnd.ms-powerpoint',
'potm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppa' => 'application/vnd.ms-powerpoint',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
'ppd' => 'application/vnd.cups-ppd',
'ppm' => 'image/x-portable-pixmap',
'pps' => 'application/vnd.ms-powerpoint',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppt' => 'application/powerpoint',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'ppt' => 'application/vnd.ms-powerpoint',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pqa' => 'application/vnd.palm',
'prc' => 'model/prc',
@@ -779,14 +815,16 @@ final class MimeType
'provx' => 'application/provenance+xml',
'ps' => 'application/postscript',
'psb' => 'application/vnd.3gpp.pic-bw-small',
'psd' => 'application/x-photoshop',
'psd' => 'image/vnd.adobe.photoshop',
'psf' => 'application/x-font-linux-psf',
'pskcxml' => 'application/pskc+xml',
'pti' => 'image/prs.pti',
'ptid' => 'application/vnd.pvi.ptid1',
'pub' => 'application/x-mspublisher',
'pv' => 'application/octet-stream',
'pvb' => 'application/vnd.3gpp.pic-bw-var',
'pwn' => 'application/vnd.3m.post-it-notes',
'pxf' => 'application/octet-stream',
'pya' => 'audio/vnd.ms-playready.media.pya',
'pyo' => 'model/vnd.pytha.pyox',
'pyox' => 'model/vnd.pytha.pyox',
@@ -806,7 +844,7 @@ final class MimeType
'ram' => 'audio/x-pn-realaudio',
'raml' => 'application/raml+yaml',
'rapd' => 'application/route-apd+xml',
'rar' => 'application/x-rar',
'rar' => 'application/vnd.rar',
'ras' => 'image/x-cmu-raster',
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
'rdf' => 'application/rdf+xml',
@@ -821,7 +859,7 @@ final class MimeType
'rl' => 'application/resource-lists+xml',
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
'rld' => 'application/resource-lists-diff+xml',
'rm' => 'audio/x-pn-realaudio',
'rm' => 'application/vnd.rn-realmedia',
'rmi' => 'audio/midi',
'rmp' => 'audio/x-pn-realaudio-plugin',
'rms' => 'application/vnd.jcp.javame.midlet-rms',
@@ -831,7 +869,7 @@ final class MimeType
'roa' => 'application/rpki-roa',
'roff' => 'text/troff',
'rp9' => 'application/vnd.cloanto.rp9',
'rpm' => 'audio/x-pn-realaudio-plugin',
'rpm' => 'application/x-redhat-package-manager',
'rpss' => 'application/vnd.nokia.radio-presets',
'rpst' => 'application/vnd.nokia.radio-preset',
'rq' => 'application/sparql-query',
@@ -865,7 +903,7 @@ final class MimeType
'sdkm' => 'application/vnd.solent.sdkm+xml',
'sdp' => 'application/sdp',
'sdw' => 'application/vnd.stardivision.writer',
'sea' => 'application/octet-stream',
'sea' => 'application/x-sea',
'see' => 'application/vnd.seemail',
'seed' => 'application/vnd.fdsn.seed',
'sema' => 'application/vnd.sema',
@@ -910,8 +948,8 @@ final class MimeType
'slt' => 'application/vnd.epson.salt',
'sm' => 'application/vnd.stepmania.stepchart',
'smf' => 'application/vnd.stardivision.math',
'smi' => 'application/smil',
'smil' => 'application/smil',
'smi' => 'application/smil+xml',
'smil' => 'application/smil+xml',
'smv' => 'video/x-smv',
'smzip' => 'application/vnd.stepmania.package',
'snd' => 'audio/basic',
@@ -925,7 +963,9 @@ final class MimeType
'spp' => 'application/scvp-vp-response',
'spq' => 'application/scvp-vp-request',
'spx' => 'audio/ogg',
'sql' => 'application/x-sql',
'sql' => 'application/sql',
'sqlite' => 'application/vnd.sqlite3',
'sqlite3' => 'application/vnd.sqlite3',
'src' => 'application/x-wais-source',
'srt' => 'application/x-subrip',
'sru' => 'application/sru+xml',
@@ -938,12 +978,13 @@ final class MimeType
'st' => 'application/vnd.sailingtracker.track',
'stc' => 'application/vnd.sun.xml.calc.template',
'std' => 'application/vnd.sun.xml.draw.template',
'step' => 'application/STEP',
'step' => 'model/step',
'stf' => 'application/vnd.wt.stf',
'sti' => 'application/vnd.sun.xml.impress.template',
'stk' => 'application/hyperstudio',
'stl' => 'model/stl',
'stp' => 'application/STEP',
'stp' => 'model/step',
'stpnc' => 'model/step',
'stpx' => 'model/step+xml',
'stpxz' => 'model/step-xml+zip',
'stpz' => 'model/step+zip',
@@ -951,7 +992,7 @@ final class MimeType
'stw' => 'application/vnd.sun.xml.writer.template',
'styl' => 'text/stylus',
'stylus' => 'text/stylus',
'sub' => 'text/vnd.dvb.subtitle',
'sub' => 'image/vnd.dvb.subtitle',
'sus' => 'application/vnd.sus-calendar',
'susp' => 'application/vnd.sus-calendar',
'sv4cpio' => 'application/x-sv4cpio',
@@ -970,6 +1011,7 @@ final class MimeType
'sxi' => 'application/vnd.sun.xml.impress',
'sxm' => 'application/vnd.sun.xml.math',
'sxw' => 'application/vnd.sun.xml.writer',
'systemverify' => 'application/vnd.pp.systemverify+xml',
't' => 'text/troff',
't3' => 'application/x-t3vm-image',
't38' => 'image/t38',
@@ -991,7 +1033,7 @@ final class MimeType
'tfm' => 'application/x-tex-tfm',
'tfx' => 'image/tiff-fx',
'tga' => 'image/x-tga',
'tgz' => 'application/x-tar',
'tgz' => 'application/gzip',
'thmx' => 'application/vnd.ms-officetheme',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
@@ -1017,12 +1059,12 @@ final class MimeType
'txd' => 'application/vnd.genomatix.tuxedo',
'txf' => 'application/vnd.mobius.txf',
'txt' => 'text/plain',
'u32' => 'application/x-authorware-bin',
'u3d' => 'model/u3d',
'u8dsn' => 'message/global-delivery-status',
'u8hdr' => 'message/global-headers',
'u8mdn' => 'message/global-disposition-notification',
'u8msg' => 'message/global',
'u32' => 'application/x-authorware-bin',
'ubj' => 'application/ubjson',
'udeb' => 'application/x-debian-package',
'ufd' => 'application/vnd.ufdl',
@@ -1078,16 +1120,18 @@ final class MimeType
'vcx' => 'application/vnd.vcx',
'vdi' => 'application/x-virtualbox-vdi',
'vds' => 'model/vnd.sap.vds',
'vdx' => 'application/vnd.ms-visio.viewer',
'vec' => 'application/vec+xml',
'vhd' => 'application/x-virtualbox-vhd',
'vis' => 'application/vnd.visionary',
'viv' => 'video/vnd.vivo',
'vlc' => 'application/videolan',
'vmdk' => 'application/x-virtualbox-vmdk',
'vob' => 'video/x-ms-vob',
'vor' => 'application/vnd.stardivision.writer',
'vox' => 'application/x-authorware-bin',
'vrml' => 'model/vrml',
'vsd' => 'application/vnd.visio',
'vsdx' => 'application/vnd.visio',
'vsf' => 'application/vnd.vsf',
'vss' => 'application/vnd.visio',
'vst' => 'application/vnd.visio',
@@ -1095,17 +1139,18 @@ final class MimeType
'vtf' => 'image/vnd.valve.source.texture',
'vtt' => 'text/vtt',
'vtu' => 'model/vnd.vtu',
'vtx' => 'application/vnd.visio',
'vxml' => 'application/voicexml+xml',
'w3d' => 'application/x-director',
'wad' => 'application/x-doom',
'wadl' => 'application/vnd.sun.wadl+xml',
'war' => 'application/java-archive',
'wasm' => 'application/wasm',
'wav' => 'audio/x-wav',
'wav' => 'audio/wav',
'wax' => 'audio/x-ms-wax',
'wbmp' => 'image/vnd.wap.wbmp',
'wbs' => 'application/vnd.criticaltools.wbs+xml',
'wbxml' => 'application/wbxml',
'wbxml' => 'application/vnd.wap.wbxml',
'wcm' => 'application/vnd.ms-works',
'wdb' => 'application/vnd.ms-works',
'wdp' => 'image/vnd.ms-photo',
@@ -1124,12 +1169,12 @@ final class MimeType
'wmd' => 'application/x-ms-wmd',
'wmf' => 'image/wmf',
'wml' => 'text/vnd.wap.wml',
'wmlc' => 'application/wmlc',
'wmlc' => 'application/vnd.wap.wmlc',
'wmls' => 'text/vnd.wap.wmlscript',
'wmlsc' => 'application/vnd.wap.wmlscriptc',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'wmz' => 'application/x-msmetafile',
'wmz' => 'application/x-ms-wmz',
'woff' => 'font/woff',
'woff2' => 'font/woff2',
'word' => 'application/msword',
@@ -1144,13 +1189,13 @@ final class MimeType
'wspolicy' => 'application/wspolicy+xml',
'wtb' => 'application/vnd.webturbo',
'wvx' => 'video/x-ms-wvx',
'x32' => 'application/x-authorware-bin',
'x3d' => 'model/x3d+xml',
'x3db' => 'model/x3d+fastinfoset',
'x3dbz' => 'model/x3d+binary',
'x3dv' => 'model/x3d-vrml',
'x3dvz' => 'model/x3d+vrml',
'x3dz' => 'model/x3d+xml',
'x32' => 'application/x-authorware-bin',
'x_b' => 'model/vnd.parasolid.transmit.binary',
'x_t' => 'model/vnd.parasolid.transmit.text',
'xaml' => 'application/xaml+xml',
@@ -1162,6 +1207,7 @@ final class MimeType
'xbm' => 'image/x-xbitmap',
'xca' => 'application/xcap-caps+xml',
'xcs' => 'application/calendar+xml',
'xdcf' => 'application/vnd.gov.sk.xmldatacontainer+xml',
'xdf' => 'application/xcap-diff+xml',
'xdm' => 'application/vnd.syncml.dm+xml',
'xdp' => 'application/vnd.adobe.xdp+xml',
@@ -1177,18 +1223,18 @@ final class MimeType
'xhtml' => 'application/xhtml+xml',
'xhvml' => 'application/xv+xml',
'xif' => 'image/vnd.xiff',
'xl' => 'application/excel',
'xl' => 'application/vnd.ms-excel',
'xla' => 'application/vnd.ms-excel',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
'xlc' => 'application/vnd.ms-excel',
'xlf' => 'application/xliff+xml',
'xlm' => 'application/vnd.ms-excel',
'xls' => 'application/vnd.ms-excel',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlt' => 'application/vnd.ms-excel',
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xlw' => 'application/vnd.ms-excel',
'xm' => 'audio/xm',
@@ -1205,7 +1251,7 @@ final class MimeType
'xpx' => 'application/vnd.intercon.formnet',
'xsd' => 'application/xml',
'xsf' => 'application/prs.xsf+xml',
'xsl' => 'application/xml',
'xsl' => 'application/xslt+xml',
'xslt' => 'application/xslt+xml',
'xsm' => 'application/vnd.syncml+xml',
'xspf' => 'application/xspf+xml',

View File

@@ -23,11 +23,18 @@ final class MultipartStream implements StreamInterface
/**
* @param array $elements Array of associative arrays, each containing a
* required "name" key mapping to the form field,
* name, a required "contents" key mapping to a
* StreamInterface/resource/string, an optional
* "headers" associative array of custom headers,
* and an optional "filename" key mapping to a
* string to send as the filename in the part.
* name, a required "contents" key mapping to any
* value accepted by Utils::streamFor() (scalar,
* null, resource, StreamInterface, Iterator, or
* callable), or an array for nested expansion.
* Optional keys include "headers" (associative
* array of custom headers) and "filename" (string
* to send as the filename in the part).
* When "contents" is an array, it is recursively
* expanded into multiple fields using bracket notation
* (e.g., name[0][key]). Empty arrays produce no fields.
* The "filename" and "headers" options cannot be used
* with array contents.
* @param string $boundary You can optionally provide a specific boundary
*
* @throws \InvalidArgumentException
@@ -91,6 +98,22 @@ final class MultipartStream implements StreamInterface
}
}
if (!is_string($element['name']) && !is_int($element['name'])) {
throw new \InvalidArgumentException("The 'name' key must be a string or integer");
}
if (is_array($element['contents'])) {
if (array_key_exists('filename', $element) || array_key_exists('headers', $element)) {
throw new \InvalidArgumentException(
"The 'filename' and 'headers' options cannot be used when 'contents' is an array"
);
}
$this->addNestedElements($stream, $element['contents'], (string) $element['name']);
return;
}
$element['contents'] = Utils::streamFor($element['contents']);
if (empty($element['filename'])) {
@@ -101,7 +124,7 @@ final class MultipartStream implements StreamInterface
}
[$body, $headers] = $this->createElement(
$element['name'],
(string) $element['name'],
$element['contents'],
$element['filename'] ?? null,
$element['headers'] ?? []
@@ -112,6 +135,24 @@ final class MultipartStream implements StreamInterface
$stream->addStream(Utils::streamFor("\r\n"));
}
/**
* Recursively expand array contents into multiple form fields.
*
* @param array<array-key, mixed> $contents
*/
private function addNestedElements(AppendStream $stream, array $contents, string $root): void
{
foreach ($contents as $key => $value) {
$fieldName = $root === '' ? sprintf('[%s]', (string) $key) : sprintf('%s[%s]', $root, (string) $key);
if (is_array($value)) {
$this->addNestedElements($stream, $value, $fieldName);
} else {
$this->addElement($stream, ['name' => $fieldName, 'contents' => $value]);
}
}
}
/**
* @param string[] $headers
*

View File

@@ -40,7 +40,7 @@ class Request implements RequestInterface
string $version = '1.1'
) {
$this->assertMethod($method);
if (!($uri instanceof UriInterface)) {
if (!$uri instanceof UriInterface) {
$uri = new Uri($uri);
}

View File

@@ -51,7 +51,7 @@ class Uri implements UriInterface, \JsonSerializable
* @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
*/
private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];
private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26', '+' => '%2B'];
/** @var string Uri scheme. */
private $scheme = '';
@@ -661,7 +661,8 @@ class Uri implements UriInterface, \JsonSerializable
private static function generateQueryString(string $key, ?string $value): string
{
// Query string separators ("=", "&") within the key or value need to be encoded
// Query string separators ("=", "&") and literal plus signs ("+") within the
// key or value need to be encoded
// (while preventing double-encoding) before setting the query string. All other
// chars that need percent-encoding will be encoded by withQuery().
$queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);

View File

@@ -1,6 +1,12 @@
OAuth 2.0 Google Provider Changelog
## 4.2.0 - 2026-03-09
### Added
- Allow `oauth2-client` version 2 or 3, #140 by @garak
## 4.1.0 - 2025-12-15
### Added

View File

@@ -20,7 +20,7 @@
"minimum-stability": "stable",
"require": {
"php": "^7.3 || ^8.0",
"league/oauth2-client": "^2.0"
"league/oauth2-client": "^2.0 || ^3.0"
},
"require-dev": {
"eloquent/phony-phpunit": "^6.0 || ^7.1",

View File

@@ -192,8 +192,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
if (\is_array($e) || 1 === \count($values)) {
foreach (\is_array($e) ? $e : array_keys($values) as $id) {
$ok = false;
$v = $values[$id];
$type = get_debug_type($v);
$type = \array_key_exists($id, $values) ? get_debug_type($values[$id]) : 'unknown';
$message = \sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]);
}

View File

@@ -34,6 +34,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
private array $values = [];
private array $tags = [];
private array $expiries = [];
private array $explicitExpiries = [];
private int $defaultLifetime;
private float $maxLifetime;
private int $maxItems;
@@ -58,7 +59,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
$this->maxLifetime = $maxLifetime;
$this->maxItems = $maxItems;
self::$createCacheItem ??= \Closure::bind(
static function ($key, $value, $isHit, $tags) {
static function ($key, $value, $isHit, $tags, $expiry = null) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
@@ -66,6 +67,9 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
if (null !== $tags) {
$item->metadata[CacheItem::METADATA_TAGS] = $tags;
}
if (null !== $expiry) {
$item->metadata[CacheItem::METADATA_EXPIRY] = $expiry;
}
return $item;
},
@@ -126,7 +130,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
}
return (self::$createCacheItem)($key, $value, $isHit, $this->tags[$key] ?? null);
return (self::$createCacheItem)($key, $value, $isHit, $this->tags[$key] ?? null, $this->explicitExpiries[$key] ?? null);
}
public function getItems(array $keys = []): iterable
@@ -139,7 +143,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
public function deleteItem(mixed $key): bool
{
\assert('' !== CacheItem::validateKey($key));
unset($this->values[$key], $this->tags[$key], $this->expiries[$key]);
unset($this->values[$key], $this->tags[$key], $this->expiries[$key], $this->explicitExpiries[$key]);
return true;
}
@@ -193,13 +197,19 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
break;
}
unset($this->values[$k], $this->tags[$k], $this->expiries[$k]);
unset($this->values[$k], $this->tags[$k], $this->expiries[$k], $this->explicitExpiries[$k]);
}
}
$this->values[$key] = $value;
$this->expiries[$key] = $expiry ?? \PHP_INT_MAX;
if (null !== $item["\0*\0expiry"] && \PHP_INT_MAX !== $this->expiries[$key]) {
$this->explicitExpiries[$key] = $this->expiries[$key];
} else {
unset($this->explicitExpiries[$key]);
}
if (null === $this->tags[$key] = $item["\0*\0newMetadata"][CacheItem::METADATA_TAGS] ?? null) {
unset($this->tags[$key]);
}
@@ -224,7 +234,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
foreach ($this->values as $key => $value) {
if (!isset($this->expiries[$key]) || $this->expiries[$key] <= $now || str_starts_with($key, $prefix)) {
unset($this->values[$key], $this->tags[$key], $this->expiries[$key]);
unset($this->values[$key], $this->tags[$key], $this->expiries[$key], $this->explicitExpiries[$key]);
}
}
@@ -233,7 +243,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
}
}
$this->values = $this->tags = $this->expiries = [];
$this->values = $this->tags = $this->expiries = $this->explicitExpiries = [];
return true;
}
@@ -290,7 +300,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
}
unset($keys[$i]);
yield $key => $f($key, $value, $isHit, $this->tags[$key] ?? null);
yield $key => $f($key, $value, $isHit, $this->tags[$key] ?? null, $this->explicitExpiries[$key] ?? null);
}
foreach ($keys as $key) {

View File

@@ -79,6 +79,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$item->expiresAt(\DateTimeImmutable::createFromFormat('U.u', \sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY])));
} elseif (0 < $defaultLifetime) {
$item->expiresAfter($defaultLifetime);
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
}
return $item;

View File

@@ -170,6 +170,10 @@ final class CacheItem implements ItemInterface
}
$valueWrapper = self::VALUE_WRAPPER;
if ($this->value instanceof $valueWrapper) {
return new $valueWrapper($this->value->value, $m + ['expiry' => $this->expiry] + $this->value->metadata);
}
return new $valueWrapper($this->value, $m + ['expiry' => $this->expiry]);
}

View File

@@ -65,12 +65,14 @@ final class LockRegistry
/**
* Defines a set of existing files that will be used as keys to acquire locks.
*
* @return array The previously defined set of files
* @param list<string> $files A list of existing files
*
* @return list<string> The previously defined set of files
*/
public static function setFiles(array $files): array
{
$previousFiles = self::$files;
self::$files = $files;
self::$files = array_values($files);
foreach (self::$openedFiles as $file) {
if ($file) {
@@ -97,7 +99,7 @@ final class LockRegistry
}
self::$signalingException ??= unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
self::$signalingCallback ??= fn () => throw self::$signalingException;
self::$signalingCallback ??= static fn () => throw self::$signalingException;
while (true) {
try {
@@ -123,14 +125,33 @@ final class LockRegistry
}
// if we failed the race, retry locking in blocking mode to wait for the winner
$logger?->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
flock($lock, \LOCK_SH);
$deadline = microtime(true) + 30.0;
$acquired = false;
do {
if ($acquired = flock($lock, \LOCK_SH | \LOCK_NB)) {
break;
}
usleep(100_000);
} while (microtime(true) < $deadline);
if (!$acquired) {
$logger?->warning('Lock on item "{key}" timed out, evicting slot', ['key' => $item->getKey()]);
unset(self::$files[$key]);
self::setFiles(self::$files);
$lock = null;
return self::compute($callback, $item, $save, $pool, $setMetadata, $logger, $beta);
}
if (\INF === $beta) {
$logger?->info('Force-recomputing item "{key}"', ['key' => $item->getKey()]);
continue;
}
} finally {
flock($lock, \LOCK_UN);
if ($lock) {
flock($lock, \LOCK_UN);
}
unset(self::$lockedFiles[$key]);
}

View File

@@ -18,6 +18,7 @@ use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Traits\ProxyTrait;
use Symfony\Contracts\Cache\ItemInterface;
/**
* Turns a PSR-6 cache into a PSR-16 one.
@@ -68,6 +69,12 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
};
self::$packCacheItem ??= \Closure::bind(
static function (CacheItem $item) {
// Only re-pack if there's timing metadata (for Psr16Adapter compatibility)
// Don't re-pack if only tags metadata exists (TagAwareAdapter direct use case)
if (!isset($item->metadata[ItemInterface::METADATA_CTIME]) && !isset($item->metadata[ItemInterface::METADATA_EXPIRY])) {
return $item->value;
}
$item->newMetadata = $item->metadata;
return $item->pack();

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits\Relay;
if (version_compare(phpversion('relay'), '0.21.0', '>=')) {
/**
* @internal
*/
trait Relay21Trait
{
public function gcra($key, $maxBurst, $requestsPerPeriod, $period, $numRequests = 0): \Relay\Relay|array|false
{
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->gcra(...\func_get_args());
}
public function hotkeys($subcmd, $args = null): \Relay\Relay|array|bool
{
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hotkeys(...\func_get_args());
}
}
} else {
/**
* @internal
*/
trait Relay21Trait
{
}
}

View File

@@ -26,6 +26,7 @@ use Symfony\Component\Cache\Traits\Relay\Relay11Trait;
use Symfony\Component\Cache\Traits\Relay\Relay121Trait;
use Symfony\Component\Cache\Traits\Relay\Relay12Trait;
use Symfony\Component\Cache\Traits\Relay\Relay20Trait;
use Symfony\Component\Cache\Traits\Relay\Relay21Trait;
use Symfony\Component\Cache\Traits\Relay\SwapdbTrait;
use Symfony\Component\VarExporter\LazyObjectInterface;
use Symfony\Component\VarExporter\LazyProxyTrait;
@@ -60,6 +61,7 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter
use Relay12Trait;
use Relay121Trait;
use Relay20Trait;
use Relay21Trait;
use SwapdbTrait;
private const LAZY_OBJECT_PROPERTY_SCOPES = [];

View File

@@ -133,6 +133,10 @@ class OutputFormatter implements WrappableOutputFormatterInterface
return '';
}
// For ASCII-only strings, byte positions equal character positions,
// so we can use native strlen/substr which is much faster than Helper::length/substr.
$isAscii = !preg_match('/[\x80-\xFF]/', $message);
$offset = 0;
$output = '';
$openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
@@ -147,11 +151,17 @@ class OutputFormatter implements WrappableOutputFormatterInterface
continue;
}
// convert byte position to character position.
$pos = Helper::length(substr($message, 0, $pos));
// add the text up to the next tag
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + Helper::length($text);
if ($isAscii) {
// For ASCII, byte position = character position, no conversion needed
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + \strlen($text);
} else {
// convert byte position to character position.
$pos = Helper::length(substr($message, 0, $pos));
// add the text up to the next tag
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + Helper::length($text);
}
// opening tag?
if ($open = '/' !== $text[1]) {
@@ -172,7 +182,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
}
}
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength);
$output .= $this->applyCurrentStyle($isAscii ? substr($message, $offset) : Helper::substr($message, $offset), $output, $width, $currentLineLength);
return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
}

View File

@@ -142,12 +142,27 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
*/
private function openOutputStream()
{
static $stdout;
if ($stdout) {
return $stdout;
}
if (!$this->hasStdoutSupport()) {
return fopen('php://output', 'w');
return $stdout = fopen('php://output', 'w');
}
// Use STDOUT when possible to prevent from opening too many file descriptors
return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));
if (!\defined('STDOUT')) {
return $stdout = @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
}
// On Windows, STDOUT is opened in text mode; reopen in binary mode to prevent \n to \r\n conversion
if ('\\' === \DIRECTORY_SEPARATOR) {
return $stdout = @fopen('php://stdout', 'w') ?: \STDOUT;
}
return $stdout = \STDOUT;
}
/**
@@ -155,11 +170,26 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
*/
private function openErrorStream()
{
static $stderr;
if ($stderr) {
return $stderr;
}
if (!$this->hasStderrSupport()) {
return fopen('php://output', 'w');
return $stderr = fopen('php://output', 'w');
}
// Use STDERR when possible to prevent from opening too many file descriptors
return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));
if (!\defined('STDERR')) {
return $stderr = @fopen('php://stderr', 'w') ?: fopen('php://output', 'w');
}
// On Windows, STDERR is opened in text mode; reopen in binary mode to prevent \n → \r\n conversion
if ('\\' === \DIRECTORY_SEPARATOR) {
return $stderr = @fopen('php://stderr', 'w') ?: \STDERR;
}
return $stderr ??= \STDERR;
}
}

View File

@@ -49,7 +49,7 @@ class ApplicationTester
*/
public function run(array $input, array $options = []): int
{
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
$prevShellVerbosity = [getenv('SHELL_VERBOSITY'), $_ENV['SHELL_VERBOSITY'] ?? false, $_SERVER['SHELL_VERBOSITY'] ?? false];
try {
$this->input = new ArrayInput($input);
@@ -63,22 +63,35 @@ class ApplicationTester
$this->initOutput($options);
// Temporarily clear SHELL_VERBOSITY to prevent Application::configureIO
// from overriding the interactive and verbosity settings set above
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY');
}
unset($_ENV['SHELL_VERBOSITY'], $_SERVER['SHELL_VERBOSITY']);
return $this->statusCode = $this->application->run($this->input, $this->output);
} finally {
// SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
// to its previous value to avoid one test's verbosity to spread to the following tests
if (false === $prevShellVerbosity) {
if (false === $prevShellVerbosity[0]) {
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY');
}
unset($_ENV['SHELL_VERBOSITY']);
unset($_SERVER['SHELL_VERBOSITY']);
} else {
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity[0]);
}
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
}
if (false === $prevShellVerbosity[1]) {
unset($_ENV['SHELL_VERBOSITY']);
} else {
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity[1];
}
if (false === $prevShellVerbosity[2]) {
unset($_SERVER['SHELL_VERBOSITY']);
} else {
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity[2];
}
}
}

View File

@@ -0,0 +1,8 @@
CHANGELOG
=========
4.1.0
-----
* Added the `server:dump` command to run a server collecting and displaying
dumps on a single place with multiple formats support

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\DebugBundle\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\VarDumper\Command\ServerDumpCommand;
use Symfony\Component\VarDumper\Server\DumpServer;
/**
* A placeholder command easing VarDumper server discovery.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @internal
*/
#[AsCommand(name: 'server:dump', description: 'Start a dump server that collects and displays dumps in a single place')]
class ServerDumpPlaceholderCommand extends Command
{
private ServerDumpCommand $replacedCommand;
public function __construct(?DumpServer $server = null, array $descriptors = [])
{
$this->replacedCommand = new ServerDumpCommand((new \ReflectionClass(DumpServer::class))->newInstanceWithoutConstructor(), $descriptors);
parent::__construct();
}
protected function configure(): void
{
$this->setDefinition($this->replacedCommand->getDefinition());
$this->setHelp($this->replacedCommand->getHelp());
$this->setDescription($this->replacedCommand->getDescription());
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
(new SymfonyStyle($input, $output))->getErrorStyle()->warning('In order to use the VarDumper server, set the "debug.dump_destination" config option to "tcp://%env(VAR_DUMPER_SERVER)%"');
return 8;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\DebugBundle;
use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\DumpDataCollectorPass;
use Symfony\Component\Console\Application;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\VarDumper\VarDumper;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DebugBundle extends Bundle
{
/**
* @return void
*/
public function boot()
{
if ($this->container->getParameter('kernel.debug')) {
$container = $this->container;
// This code is here to lazy load the dump stack. This default
// configuration is overridden in CLI mode on 'console.command' event.
// The dump data collector is used by default, so dump output is sent to
// the WDT. In a CLI context, if dump is used too soon, the data collector
// will buffer it, and release it at the end of the script.
VarDumper::setHandler(function ($var, ?string $label = null) use ($container) {
$dumper = $container->get('data_collector.dump');
$cloner = $container->get('var_dumper.cloner');
$handler = function ($var, ?string $label = null) use ($dumper, $cloner) {
$var = $cloner->cloneVar($var);
if (null !== $label) {
$var = $var->withContext(['label' => $label]);
}
$dumper->dump($var);
};
VarDumper::setHandler($handler);
$handler($var, $label);
});
}
}
/**
* @return void
*/
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new DumpDataCollectorPass());
}
/**
* @return void
*/
public function registerCommands(Application $application)
{
// noop
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\DebugBundle\DependencyInjection\Compiler;
use Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers the file link format for the {@link \Symfony\Component\HttpKernel\DataCollector\DumpDataCollector}.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/
class DumpDataCollectorPass implements CompilerPassInterface
{
/**
* @return void
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('data_collector.dump')) {
return;
}
$definition = $container->getDefinition('data_collector.dump');
if (!$container->has('.virtual_request_stack')) {
$definition->replaceArgument(3, new Reference('request_stack'));
}
if (!$container->hasParameter('web_profiler.debug_toolbar.mode') || WebDebugToolbarListener::DISABLED === $container->getParameter('web_profiler.debug_toolbar.mode')) {
$definition->replaceArgument(3, null);
}
if (!$container->hasParameter('kernel.runtime_mode.web')) {
$definition->replaceArgument(5, null);
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\DebugBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* DebugExtension configuration structure.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('debug');
$rootNode = $treeBuilder->getRootNode();
$rootNode->children()
->integerNode('max_items')
->info('Max number of displayed items past the first level, -1 means no limit')
->min(-1)
->defaultValue(2500)
->end()
->integerNode('min_depth')
->info('Minimum tree depth to clone all the items, 1 is default')
->min(0)
->defaultValue(1)
->end()
->integerNode('max_string_length')
->info('Max length of displayed strings, -1 means no limit')
->min(-1)
->defaultValue(-1)
->end()
->scalarNode('dump_destination')
->info('A stream URL where dumps should be written to')
->example('php://stderr, or tcp://%env(VAR_DUMPER_SERVER)% when using the "server:dump" command')
->defaultNull()
->end()
->enumNode('theme')
->info('Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light"')
->example('dark')
->values(['dark', 'light'])
->defaultValue('dark')
->end()
;
return $treeBuilder;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\DebugBundle\DependencyInjection;
use Symfony\Bridge\Monolog\Command\ServerLogCommand;
use Symfony\Bundle\DebugBundle\Command\ServerDumpPlaceholderCommand;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
/**
* DebugExtension.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class DebugExtension extends Extension
{
/**
* @return void
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.php');
$container->getDefinition('var_dumper.cloner')
->addMethodCall('setMaxItems', [$config['max_items']])
->addMethodCall('setMinDepth', [$config['min_depth']])
->addMethodCall('setMaxString', [$config['max_string_length']])
->addMethodCall('addCasters', [ReflectionCaster::UNSET_CLOSURE_FILE_INFO]);
if ('dark' !== $config['theme']) {
$container->getDefinition('var_dumper.html_dumper')
->addMethodCall('setTheme', [$config['theme']]);
}
if (null === $config['dump_destination']) {
$container->getDefinition('var_dumper.command.server_dump')
->setClass(ServerDumpPlaceholderCommand::class)
;
} elseif (str_starts_with($config['dump_destination'], 'tcp://')) {
$container->getDefinition('debug.dump_listener')
->replaceArgument(2, new Reference('var_dumper.server_connection'))
;
$container->getDefinition('data_collector.dump')
->replaceArgument(4, new Reference('var_dumper.server_connection'))
;
$container->getDefinition('var_dumper.dump_server')
->replaceArgument(0, $config['dump_destination'])
;
$container->getDefinition('var_dumper.server_connection')
->replaceArgument(0, $config['dump_destination'])
;
} else {
$container->getDefinition('var_dumper.cli_dumper')
->replaceArgument(0, $config['dump_destination'])
;
$container->getDefinition('data_collector.dump')
->replaceArgument(4, new Reference('var_dumper.cli_dumper'))
;
$container->getDefinition('var_dumper.command.server_dump')
->setClass(ServerDumpPlaceholderCommand::class)
;
}
$container->getDefinition('var_dumper.cli_dumper')
->addMethodCall('setDisplayOptions', [[
'fileLinkFormat' => new Reference('debug.file_link_formatter', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE),
]])
;
if (!class_exists(Command::class) || !class_exists(ServerLogCommand::class)) {
$container->removeDefinition('monolog.command.server_log');
}
}
public function getXsdValidationBasePath(): string|false
{
return __DIR__.'/../Resources/config/schema';
}
public function getNamespace(): string
{
return 'http://symfony.com/schema/dic/debug';
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2014-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,13 @@
DebugBundle
===========
DebugBundle provides a tight integration of the Symfony VarDumper component and
the ServerLogCommand from MonologBridge into the Symfony full-stack framework.
Resources
---------
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://symfony.com/schema/dic/debug"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema/dic/debug"
elementFormDefault="qualified">
<xsd:element name="config" type="config" />
<xsd:complexType name="config">
<xsd:attribute name="max-items" type="xsd:integer" />
<xsd:attribute name="min-depth" type="xsd:integer" />
<xsd:attribute name="max-string-length" type="xsd:integer" />
<xsd:attribute name="dump-destination" type="xsd:string" />
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,141 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Monolog\Formatter\FormatterInterface;
use Symfony\Bridge\Monolog\Command\ServerLogCommand;
use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter;
use Symfony\Bridge\Twig\Extension\DumpExtension;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\EventListener\DumpListener;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor;
use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor;
use Symfony\Component\VarDumper\Command\ServerDumpCommand;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextProvider\RequestContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextualizedDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Server\Connection;
use Symfony\Component\VarDumper\Server\DumpServer;
return static function (ContainerConfigurator $container) {
$container->parameters()
->set('env(VAR_DUMPER_SERVER)', '127.0.0.1:9912')
;
$container->services()
->set('twig.extension.dump', DumpExtension::class)
->args([
service('var_dumper.cloner'),
service('var_dumper.html_dumper'),
])
->tag('twig.extension')
->set('data_collector.dump', DumpDataCollector::class)
->public()
->args([
service('debug.stopwatch')->ignoreOnInvalid(),
service('debug.file_link_formatter')->ignoreOnInvalid(),
param('kernel.charset'),
service('.virtual_request_stack'),
null, // var_dumper.cli_dumper or var_dumper.server_connection when debug.dump_destination is set
param('kernel.runtime_mode.web'),
])
->tag('data_collector', [
'id' => 'dump',
'template' => '@Debug/Profiler/dump.html.twig',
'priority' => 240,
])
->set('debug.dump_listener', DumpListener::class)
->args([
service('var_dumper.cloner'),
service('var_dumper.cli_dumper'),
null,
])
->tag('kernel.event_subscriber')
->set('var_dumper.cloner', VarCloner::class)
->public()
->set('var_dumper.cli_dumper', CliDumper::class)
->args([
null, // debug.dump_destination,
param('kernel.charset'),
0, // flags
])
->set('var_dumper.contextualized_cli_dumper', ContextualizedDumper::class)
->decorate('var_dumper.cli_dumper')
->args([
service('var_dumper.contextualized_cli_dumper.inner'),
[
'source' => inline_service(SourceContextProvider::class)->args([
param('kernel.charset'),
param('kernel.project_dir'),
service('debug.file_link_formatter')->nullOnInvalid(),
]),
],
])
->set('var_dumper.html_dumper', HtmlDumper::class)
->args([
null,
param('kernel.charset'),
0, // flags
])
->call('setDisplayOptions', [
['fileLinkFormat' => service('debug.file_link_formatter')->ignoreOnInvalid()],
])
->set('var_dumper.server_connection', Connection::class)
->args([
'', // server host
[
'source' => inline_service(SourceContextProvider::class)->args([
param('kernel.charset'),
param('kernel.project_dir'),
service('debug.file_link_formatter')->nullOnInvalid(),
]),
'request' => inline_service(RequestContextProvider::class)->args([service('request_stack')]),
'cli' => inline_service(CliContextProvider::class),
],
])
->set('var_dumper.dump_server', DumpServer::class)
->args([
'', // server host
service('logger')->nullOnInvalid(),
])
->tag('monolog.logger', ['channel' => 'debug'])
->set('var_dumper.command.server_dump', ServerDumpCommand::class)
->args([
service('var_dumper.dump_server'),
[
'cli' => inline_service(CliDescriptor::class)->args([service('var_dumper.contextualized_cli_dumper.inner')]),
'html' => inline_service(HtmlDescriptor::class)->args([service('var_dumper.html_dumper')]),
],
])
->tag('console.command')
->set('monolog.command.server_log', ServerLogCommand::class)
;
if (class_exists(ConsoleFormatter::class) && interface_exists(FormatterInterface::class)) {
$container->services()->get('monolog.command.server_log')->tag('console.command');
}
};

View File

@@ -0,0 +1,83 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block toolbar %}
{% if collector.dumpsCount %}
{% set icon %}
{{ source('@Debug/Profiler/icon.svg') }}
<span class="sf-toolbar-value">{{ collector.dumpsCount }}</span>
{% endset %}
{% set text %}
{% for dump in collector.getDumps('html') %}
<div class="sf-toolbar-info-piece">
<span>
{% if dump.label is defined and '' != dump.label %}
<span class="sf-toolbar-file-line"><strong>{{ dump.label }}</strong> in </span>
{% endif %}
{% if dump.file %}
{% set link = dump.file|file_link(dump.line) %}
{% if link %}
<a href="{{ link }}" title="{{ dump.file }}">{{ dump.name }}</a>
{% else %}
<abbr title="{{ dump.file }}">{{ dump.name }}</abbr>
{% endif %}
{% else %}
{{ dump.name }}
{% endif %}
</span>
<span class="sf-toolbar-file-line">line {{ dump.line }}</span>
{{ dump.data|raw }}
</div>
{% endfor %}
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
{% endif %}
{% endblock %}
{% block menu %}
<span class="label {{ collector.dumpsCount == 0 ? 'disabled' }}">
<span class="icon">{{ source('@Debug/Profiler/icon.svg') }}</span>
<strong>Debug</strong>
</span>
{% endblock %}
{% block panel %}
<h2>Dumped Contents</h2>
{% for dump in collector.getDumps('html') %}
<div class="sf-dump sf-reset">
<span class="metadata">
{% if dump.label is defined and '' != dump.label %}
<strong>{{ dump.label }}</strong> in
{% else %}
In
{% endif %}
{% if dump.line %}
{% set link = dump.file|file_link(dump.line) %}
{% if link %}
<a href="{{ link }}" title="{{ dump.file }}">{{ dump.name }}</a>
{% else %}
<abbr title="{{ dump.file }}">{{ dump.name }}</abbr>
{% endif %}
{% else %}
{{ dump.name }}
{% endif %}
line <a class="text-small sf-toggle" data-toggle-selector="#sf-trace-{{ loop.index0 }}">{{ dump.line }}</a>:
</span>
<div class="sf-dump-compact hidden" id="sf-trace-{{ loop.index0 }}">
<div class="trace">
{{ dump.fileExcerpt ? dump.fileExcerpt|raw : dump.file|file_excerpt(dump.line) }}
</div>
</div>
{{ dump.data|raw }}
</div>
{% else %}
<div class="empty empty-panel">
<p>No content was dumped.</p>
</div>
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" data-icon-name="icon-tabler-viewfinder" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="12" cy="12" r="9"></circle>
<line x1="12" y1="3" x2="12" y2="7"></line>
<line x1="12" y1="21" x2="12" y2="18"></line>
<line x1="3" y1="12" x2="7" y2="12"></line>
<line x1="21" y1="12" x2="18" y2="12"></line>
<line x1="12" y1="12" x2="12" y2="12.01"></line>
</svg>

After

Width:  |  Height:  |  Size: 586 B

View File

@@ -0,0 +1,41 @@
{
"name": "symfony/debug-bundle",
"type": "symfony-bundle",
"description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=8.1",
"ext-xml": "*",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/twig-bridge": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
},
"require-dev": {
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/web-profiler-bundle": "^5.4|^6.0|^7.0"
},
"conflict": {
"symfony/config": "<5.4",
"symfony/dependency-injection": "<5.4"
},
"autoload": {
"psr-4": { "Symfony\\Bundle\\DebugBundle\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev"
}

View File

@@ -1295,16 +1295,9 @@ EOF;
}
}
if (Container::class !== $this->baseClass) {
$r = $this->container->getReflectionClass($this->baseClass, false);
if (null !== $r
&& (null !== $constructor = $r->getConstructor())
&& 0 === $constructor->getNumberOfRequiredParameters()
&& Container::class !== $constructor->getDeclaringClass()->name
) {
$code .= " parent::__construct();\n";
$code .= " \$this->parameterBag = null;\n\n";
}
if ($this->needsUnsetParameterBag()) {
$code .= " parent::__construct();\n";
$code .= " unset(\$this->parameterBag);\n\n";
}
if ($this->container->getParameterBag()->all()) {
@@ -1582,9 +1575,22 @@ EOF;
return $code ? \sprintf("\n \$this->privates['service_container'] = static function (\$container) {%s\n };\n", $code) : '';
}
private function needsUnsetParameterBag(): bool
{
if (Container::class === $this->baseClass) {
return false;
}
$r = $this->container->getReflectionClass($this->baseClass, false);
return null !== $r
&& (null !== $constructor = $r->getConstructor())
&& 0 === $constructor->getNumberOfRequiredParameters()
&& Container::class !== $constructor->getDeclaringClass()->name;
}
private function addDefaultParametersMethod(): string
{
if (!$this->container->getParameterBag()->all()) {
if (!$this->container->getParameterBag()->all() && !$this->needsUnsetParameterBag()) {
return '';
}

View File

@@ -77,6 +77,18 @@ abstract class AbstractConfigurator
$value = (self::$valuePreProcessor)($value, $allowServices);
}
if ($value instanceof ParamConfigurator) {
return (string) $value;
}
if (\is_scalar($value ?? '') || $value instanceof \UnitEnum) {
return $value;
}
if (!$allowServices) {
throw new InvalidArgumentException(\sprintf('Cannot use values of type "%s" in service configuration files.', get_debug_type($value)));
}
if ($value instanceof ReferenceConfigurator) {
$reference = new Reference($value->id, $value->invalidBehavior);
@@ -90,29 +102,18 @@ abstract class AbstractConfigurator
return $def;
}
if ($value instanceof ParamConfigurator) {
return (string) $value;
}
if ($value instanceof self) {
throw new InvalidArgumentException(\sprintf('"%s()" can be used only at the root of service configuration files.', $value::FACTORY));
}
switch (true) {
case null === $value:
case \is_scalar($value):
case $value instanceof \UnitEnum:
return $value;
case $value instanceof ArgumentInterface:
case $value instanceof Definition:
case $value instanceof Expression:
case $value instanceof Parameter:
case $value instanceof AbstractArgument:
case $value instanceof Reference:
if ($allowServices) {
return $value;
}
return $value;
}
throw new InvalidArgumentException(\sprintf('Cannot use values of type "%s" in service configuration files.', get_debug_type($value)));

View File

@@ -14,6 +14,7 @@ namespace Symfony\Component\Dotenv;
use Symfony\Component\Dotenv\Exception\FormatException;
use Symfony\Component\Dotenv\Exception\FormatExceptionContext;
use Symfony\Component\Dotenv\Exception\PathException;
use Symfony\Component\Dotenv\Exception\VariableCircularReferenceException;
use Symfony\Component\Process\Exception\ExceptionInterface as ProcessException;
use Symfony\Component\Process\Process;
@@ -81,6 +82,7 @@ final class Dotenv
public function load(string $path, string ...$extraPaths): void
{
$this->doLoad(false, \func_get_args());
$this->resolveLoadedVars();
}
/**
@@ -100,33 +102,42 @@ final class Dotenv
*/
public function loadEnv(string $path, ?string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
{
$k = $envKey ?? $this->envKey;
try {
$k = $envKey ?? $this->envKey;
if (is_file($path) || !is_file($p = "$path.dist")) {
$this->doLoad($overrideExistingVars, [$path]);
} else {
$this->doLoad($overrideExistingVars, [$p]);
}
if (is_file($path) || !is_file($p = "$path.dist")) {
$this->doLoad($overrideExistingVars, [$path]);
} else {
$this->doLoad($overrideExistingVars, [$p]);
}
if (null === $env = $_SERVER[$k] ?? $_ENV[$k] ?? null) {
$this->populate([$k => $env = $defaultEnv], $overrideExistingVars);
}
if (null === $env = $_SERVER[$k] ?? $_ENV[$k] ?? null) {
$this->populate([$k => $env = $defaultEnv], $overrideExistingVars);
} elseif (str_contains($env, '$') || str_contains($env, "\x00") || str_contains($env, '\\')) {
$env = $this->resolveEnvKey($env, $k);
}
if (!\in_array($env, $testEnvs, true) && is_file($p = "$path.local")) {
$this->doLoad($overrideExistingVars, [$p]);
$env = $_SERVER[$k] ?? $_ENV[$k] ?? $env;
}
if (!\in_array($env, $testEnvs, true) && is_file($p = "$path.local")) {
$this->doLoad($overrideExistingVars, [$p]);
$env = $_SERVER[$k] ?? $_ENV[$k] ?? $env;
if (str_contains($env, '$') || str_contains($env, "\x00") || str_contains($env, '\\')) {
$env = $this->resolveEnvKey($env, $k);
}
}
if ('local' === $env) {
return;
}
if ('local' === $env) {
return;
}
if (is_file($p = "$path.$env")) {
$this->doLoad($overrideExistingVars, [$p]);
}
if (is_file($p = "$path.$env")) {
$this->doLoad($overrideExistingVars, [$p]);
}
if (is_file($p = "$path.$env.local")) {
$this->doLoad($overrideExistingVars, [$p]);
if (is_file($p = "$path.$env.local")) {
$this->doLoad($overrideExistingVars, [$p]);
}
} finally {
$this->resolveLoadedVars();
}
}
@@ -168,6 +179,7 @@ final class Dotenv
public function overload(string $path, string ...$extraPaths): void
{
$this->doLoad(true, \func_get_args());
$this->resolveLoadedVars();
}
/**
@@ -236,6 +248,48 @@ final class Dotenv
$this->values = [];
$name = '';
$loadedVars = array_flip(explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? ''));
unset($loadedVars['']);
$this->skipEmptyLines();
while ($this->cursor < $this->end) {
switch ($state) {
case self::STATE_VARNAME:
$name = $this->lexVarname();
$state = self::STATE_VALUE;
break;
case self::STATE_VALUE:
$this->values[$name] = $this->resolveValue($this->lexValue(), $loadedVars);
$state = self::STATE_VARNAME;
break;
}
}
if (self::STATE_VALUE === $state) {
$this->values[$name] = '';
}
try {
return $this->values;
} finally {
$this->values = [];
unset($this->path, $this->cursor, $this->lineno, $this->data, $this->end);
}
}
private function parseRaw(string $data, string $path = '.env'): array
{
$this->path = $path;
$this->data = str_replace(["\r\n", "\r"], "\n", $data);
$this->lineno = 1;
$this->cursor = 0;
$this->end = \strlen($this->data);
$state = self::STATE_VARNAME;
$this->values = [];
$name = '';
$this->skipEmptyLines();
while ($this->cursor < $this->end) {
@@ -260,10 +314,22 @@ final class Dotenv
return $this->values;
} finally {
$this->values = [];
unset($this->path, $this->cursor, $this->lineno, $this->data, $this->end);
}
}
/**
* Resolves a raw value by expanding commands, variables, backslash escapes,
* and restoring literal $ markers.
*/
private function resolveValue(string $value, array $loadedVars): string
{
$resolved = $this->resolveCommands($value, $loadedVars);
$resolved = $this->resolveVariables($resolved, $loadedVars);
$resolved = str_replace('\\\\', '\\', $resolved);
return str_replace("\x00", '$', $resolved);
}
private function lexVarname(): string
{
// var name + optional export
@@ -305,8 +371,6 @@ final class Dotenv
throw $this->createFormatException('Whitespace are not supported before the value');
}
$loadedVars = array_flip(explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? ''));
unset($loadedVars['']);
$v = '';
do {
@@ -321,7 +385,10 @@ final class Dotenv
}
} while ("'" !== $this->data[$this->cursor + $len]);
$v .= substr($this->data, 1 + $this->cursor, $len - 1);
// In single-quoted strings, $ is literal and \ has no special meaning.
// Double backslashes so they survive the unescape in resolveValue(),
// and mark $ as \x00 so it's not treated as a variable reference.
$v .= str_replace(['\\', '$'], ['\\\\', "\x00"], substr($this->data, 1 + $this->cursor, $len - 1));
$this->cursor += 1 + $len;
} elseif ('"' === $this->data[$this->cursor]) {
$value = '';
@@ -340,11 +407,8 @@ final class Dotenv
}
++$this->cursor;
$value = str_replace(['\\"', '\r', '\n'], ['"', "\r", "\n"], $value);
$resolvedValue = $value;
$resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars);
$resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars);
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
$v .= $resolvedValue;
// Mark escaped $ (\$) as \x00 so it's treated as literal
$v .= $this->protectEscapedDollars($value);
} else {
$value = '';
$prevChr = $this->data[$this->cursor - 1];
@@ -363,12 +427,9 @@ final class Dotenv
++$this->cursor;
}
$value = rtrim($value);
$resolvedValue = $value;
$resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars);
$resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars);
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
$resolvedValue = $this->protectEscapedDollars($value);
if ($resolvedValue === $value && preg_match('/\s+/', $value)) {
if ($resolvedValue === $value && preg_match('/\s+/', $value) && !str_contains($value, '$')) {
throw $this->createFormatException('A value containing spaces must be surrounded by quotes');
}
@@ -385,6 +446,26 @@ final class Dotenv
return $v;
}
/**
* Converts \$ (escaped dollar) to \x00 (literal marker), handling
* even/odd backslash counts correctly: \$ → \x00, \\$ → \\$ (unchanged).
*/
private function protectEscapedDollars(string $value): string
{
if (!str_contains($value, '$')) {
return $value;
}
return preg_replace_callback('/\\\\+\$/', static function ($m) {
$bs = substr($m[0], 0, -1);
if (1 === \strlen($bs) % 2) {
return substr($bs, 0, -1)."\x00";
}
return $m[0];
}, $value);
}
private function lexNestedExpression(): string
{
++$this->cursor;
@@ -559,7 +640,148 @@ final class Dotenv
throw new FormatException('Loading files starting with a byte-order-mark (BOM) is not supported.', new FormatExceptionContext($data, $path, 1, 0));
}
$this->populate($this->parse($data, $path), $overrideExistingVars);
if (str_contains($data, "\0")) {
throw new FormatException('Loading files containing NUL bytes is not supported.', new FormatExceptionContext($data, $path, 1, 0));
}
$this->populate($this->parseRaw($data, $path), $overrideExistingVars);
}
}
/**
* Eagerly resolves a raw env key value so that loadEnv() can determine
* which additional .env files to load before full deferred resolution.
*/
private function resolveEnvKey(string $value, string $name): string
{
$loadedVars = array_flip(explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? ''));
unset($loadedVars['']);
// Save and clear own value so self-referencing defaults work
$envBackup = $_ENV[$name] ?? null;
$serverBackup = $_SERVER[$name] ?? null;
unset($_ENV[$name], $_SERVER[$name]);
if ($this->usePutenv) {
$getenvBackup = (string) getenv($name);
putenv($name);
}
$this->values = [];
$this->path = '';
$this->data = '';
$this->lineno = 0;
$this->cursor = 0;
$this->end = 0;
$resolved = $this->resolveCommands($value, $loadedVars);
$resolved = $this->resolveVariables($resolved, $loadedVars);
$resolved = str_replace(["\x00", '\\\\'], ['$', '\\'], $resolved);
if (null !== $envBackup) {
$_ENV[$name] = $envBackup;
}
if (null !== $serverBackup) {
$_SERVER[$name] = $serverBackup;
}
if ($this->usePutenv) {
putenv("$name=$getenvBackup");
}
$this->values = [];
return $resolved;
}
private function resolveLoadedVars(): void
{
$loadedVars = array_flip(explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? ''));
unset($loadedVars['']);
$this->values = [];
$this->path = '';
$this->data = '';
$this->lineno = 0;
$this->cursor = 0;
$this->end = 0;
// Detect variables that were originally defined as self-referencing
// (e.g. MY_VAR="${MY_VAR:-default}") so their own raw value is hidden
// during resolution, allowing the default to trigger correctly.
$selfReferencingVars = [];
foreach ($loadedVars as $name => $_) {
if ('SYMFONY_DOTENV_VARS' === $name) {
continue;
}
$value = $_ENV[$name] ?? '';
if (str_contains($value, '$') && preg_match('/\$\{?'.preg_quote($name, '/').'(?![A-Za-z0-9_])/', $value)) {
$selfReferencingVars[$name] = true;
}
}
for ($pass = 0; $pass < 5; ++$pass) {
$resolved = [];
foreach ($loadedVars as $name => $_) {
if ('SYMFONY_DOTENV_VARS' === $name) {
continue;
}
if (!str_contains($value = $_ENV[$name] ?? '', '$')) {
continue;
}
if (isset($selfReferencingVars[$name])) {
$envBackup = $_ENV[$name] ?? null;
$serverBackup = $_SERVER[$name] ?? null;
unset($_ENV[$name], $_SERVER[$name]);
if ($this->usePutenv) {
$getenvBackup = $this->usePutenv ? (string) getenv($name) : null;
putenv($name);
}
}
$resolvedValue = $this->resolveCommands($value, $loadedVars);
$resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars);
if (isset($selfReferencingVars[$name])) {
if (null !== $envBackup) {
$_ENV[$name] = $envBackup;
}
if (null !== $serverBackup) {
$_SERVER[$name] = $serverBackup;
}
if ($this->usePutenv) {
putenv("$name=$getenvBackup");
}
}
if ($value !== $resolvedValue) {
$resolved[$name] = $resolvedValue;
}
}
if (!$resolved) {
break;
}
$this->populate($resolved, true);
}
if (5 === $pass && $resolved) {
throw new VariableCircularReferenceException('Too many levels of variable indirection in env vars: '.implode(', ', array_keys($resolved)).'.');
}
// Restore literal $ signs and unescape backslashes
$restored = [];
foreach ($loadedVars as $name => $_) {
if ('SYMFONY_DOTENV_VARS' === $name) {
continue;
}
$value = $_ENV[$name] ?? '';
if ($value !== $newValue = str_replace(["\x00", '\\\\'], ['$', '\\'], $value)) {
$restored[$name] = $newValue;
}
}
if ($restored) {
$this->populate($restored, true);
}
$this->values = [];
unset($this->path, $this->data, $this->lineno, $this->cursor, $this->end);
}
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Dotenv\Exception;
/**
* Thrown when there are too many levels of variable indirection in env vars.
*
* @author Pascal CESCON <pascal.cescon@gmail.com>
*/
final class VariableCircularReferenceException extends \LogicException implements ExceptionInterface
{
}

View File

@@ -127,6 +127,21 @@ class DebugClassLoader
private static array $internalMethods = [];
private static array $annotatedParameters = [];
private static array $darwinCache = ['/' => ['/', []]];
/**
* @var array<string, list<array{0: string, 1: bool, 2: string, 3: string, 4: string|null}>>
*
* Maps an interface FQCN (or an abstract class accumulating entries from its interfaces) to the list of
* "@method" annotations declared on it. For interfaces, the entry is populated directly by parsing the
* annotations from the interface's docblock. For abstract classes, the information from all implemented
* interfaces is merged together, so that the check can later be applied to the first concrete subclass.
*
* Each entry is a tuple of:
* [0] string $interface - FQCN of the interface that carries the "@method" annotation
* [1] bool $static - whether the method is declared static
* [2] string $returnType - return type from the annotation, or '' if absent
* [3] string $name - method name plus its parameter signature, e.g. "foo($arg, int $n)"
* [4] string|null $description - description text (period-normalised), or null if absent
*/
private static array $method = [];
private static array $returnTypes = [];
private static array $methodTraits = [];
@@ -398,6 +413,14 @@ class DebugClassLoader
if ($refl->isInterface() && isset($doc['method'])) {
foreach ($doc['method'] as $name => [$static, $returnType, $signature, $description]) {
if ($refl->hasMethod($static ? '__callStatic' : '__call')) {
// When the interface has "virtual" @method declarations but at the same time contains a __call/__callStatic magic method,
// do not trigger a deprecation notice. This is to address special use cases like in Predis' ClientInterface where the
// "@method" annotations never intend to actually add the method to the interface, but are used to document the "virtual"
// API provided by the interface through the technical implementation of magic calls. This might cause false negatives
// (missing notices) in the case that such interfaces are later amended with actual (real) methods.
continue;
}
self::$method[$class][] = [$class, $static, $returnType, $name.$signature, $description];
if ('' !== $returnType) {
@@ -420,6 +443,15 @@ class DebugClassLoader
}
}
// When the parent is a concrete class, we will trigger deprecation notices to make it aware that it needs
// to add the new methods announced with @method. The parent will have to provide all those methods.
// For child classes this means they will not need to deal with @method coming from any of the interfaces
// the parent implements.
// Put those interfaces that we can ignore into $parentInterfaces.
// The ternary makes use of the fact that abstract parent classes will accumulate the methods in self::$method,
// so !isset(self::$method[$parent]) indicates a concrete parent class.
$parentInterfaces = ($parent && !isset(self::$method[$parent])) ? class_implements($parent, false) : [];
// Detect if the parent is annotated
foreach ($parentAndOwnInterfaces + class_uses($class, false) as $use) {
if (!isset(self::$checkedClasses[$use])) {
@@ -435,13 +467,15 @@ class DebugClassLoader
$deprecations[] = \sprintf('The "%s" %s is considered internal%s It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $className);
}
if (isset(self::$method[$use])) {
if ($refl->isAbstract()) {
if ($refl->isAbstract() || $refl->isInterface()) {
// Abstract classes and interfaces inherit @method from interfaces they
// implement directly or through inheritance.
if (isset(self::$method[$class])) {
self::$method[$class] = array_merge(self::$method[$class], self::$method[$use]);
} else {
self::$method[$class] = self::$method[$use];
}
} elseif (!$refl->isInterface()) {
} else {
if (!strncmp($vendor, str_replace('_', '\\', $use), $vendorLen)
&& str_starts_with($className, 'Symfony\\')
&& (!class_exists(InstalledVersions::class)
@@ -450,14 +484,14 @@ class DebugClassLoader
// skip "same vendor" @method deprecations for Symfony\* classes unless symfony/symfony is being tested
continue;
}
$hasCall = $refl->hasMethod('__call');
$hasStaticCall = $refl->hasMethod('__callStatic');
foreach (self::$method[$use] as [$interface, $static, $returnType, $name, $description]) {
if ($static ? $hasStaticCall : $hasCall) {
if (isset($parentInterfaces[$interface])) {
// The @method annotation comes from an interface that has already been implemented by a concrete parent class,
// so we can ignore it here.
continue;
}
$realName = substr($name, 0, strpos($name, '('));
if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static && !$methodRefl->isStatic()) || (!$static && $methodRefl->isStatic())) {
if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static xor $methodRefl->isStatic())) {
$deprecations[] = \sprintf('Class "%s" should implement method "%s::%s%s"%s', $className, ($static ? 'static ' : '').$interface, $name, $returnType ? ': '.$returnType : '', null === $description ? '.' : ': '.$description);
}
}

View File

@@ -40,6 +40,9 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
private EventDispatcherInterface $dispatcher;
private array $wrappedListeners = [];
private array $orphanedEvents = [];
private array $dispatchDepth = [];
private array $calledListenerInfos = [];
private array $calledOriginalListeners = [];
private ?RequestStack $requestStack;
private string $currentRequestHash = '';
@@ -155,20 +158,20 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
public function getCalledListeners(?Request $request = null): array
{
if (null === $this->callStack) {
if (!$this->calledListenerInfos) {
return [];
}
$hash = $request ? spl_object_hash($request) : null;
$called = [];
foreach ($this->callStack as $listener) {
[$eventName, $requestHash] = $this->callStack->getInfo();
foreach ($this->calledListenerInfos as $requestHash => $infos) {
if (null === $hash || $hash === $requestHash) {
$called[] = $listener->getInfo($eventName);
$called[] = $infos;
}
}
return $called;
return $called ? array_merge(...$called) : [];
}
public function getNotCalledListeners(?Request $request = null): array
@@ -185,16 +188,14 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
$hash = $request ? spl_object_hash($request) : null;
$calledListeners = [];
if (null !== $this->callStack) {
foreach ($this->callStack as $calledListener) {
[, $requestHash] = $this->callStack->getInfo();
if (null === $hash || $hash === $requestHash) {
$calledListeners[] = $calledListener->getWrappedListener();
}
foreach ($this->calledOriginalListeners as $requestHash => $eventListeners) {
if (null === $hash || $hash === $requestHash) {
$calledListeners[] = array_merge(...array_values($eventListeners));
}
}
$calledListeners = $calledListeners ? array_merge(...$calledListeners) : [];
$notCalled = [];
foreach ($allListeners as $eventName => $listeners) {
@@ -234,6 +235,9 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
$this->callStack = null;
$this->orphanedEvents = [];
$this->currentRequestHash = '';
$this->dispatchDepth = [];
$this->calledListenerInfos = [];
$this->calledOriginalListeners = [];
}
/**
@@ -267,6 +271,8 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
private function preProcess(string $eventName): void
{
$this->dispatchDepth[$eventName] = ($this->dispatchDepth[$eventName] ?? 0) + 1;
if (!$this->dispatcher->hasListeners($eventName)) {
$this->orphanedEvents[$this->currentRequestHash][] = $eventName;
@@ -285,6 +291,8 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
private function postProcess(string $eventName): void
{
--$this->dispatchDepth[$eventName];
unset($this->wrappedListeners[$eventName]);
$skipped = false;
foreach ($this->dispatcher->getListeners($eventName) as $listener) {
@@ -302,10 +310,16 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
if ($listener->wasCalled()) {
$this->logger?->debug('Notified event "{event}" to listener "{listener}".', $context);
} else {
unset($this->callStack[$listener]);
$original = $listener->getWrappedListener();
if (!\in_array($original, $this->calledOriginalListeners[$this->currentRequestHash][$eventName] ?? [], true)) {
$this->calledOriginalListeners[$this->currentRequestHash][$eventName][] = $original;
$this->calledListenerInfos[$this->currentRequestHash][] = $listener->getInfo($eventName);
}
}
unset($this->callStack[$listener]);
if (null !== $this->logger && $skipped) {
$this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
}
@@ -316,6 +330,28 @@ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterfa
$skipped = true;
}
}
if (0 < $this->dispatchDepth[$eventName]) {
return;
}
// Clean up stale callStack entries left by nested same-event dispatches
$stale = [];
foreach ($this->callStack as $listener) {
if ($this->callStack->getInfo()[0] === $eventName) {
$stale[] = $listener;
}
}
foreach ($stale as $listener) {
if ($listener->wasCalled()) {
$original = $listener->getWrappedListener();
if (!\in_array($original, $this->calledOriginalListeners[$this->currentRequestHash][$eventName] ?? [], true)) {
$this->calledOriginalListeners[$this->currentRequestHash][$eventName][] = $original;
$this->calledListenerInfos[$this->currentRequestHash][] = $listener->getInfo($eventName);
}
}
unset($this->callStack[$listener]);
}
}
private function sortNotCalledListeners(array $a, array $b): int

View File

@@ -39,17 +39,23 @@ class ValidatorExtension extends AbstractExtension
/** @var ClassMetadata $metadata */
$metadata = $validator->getMetadataFor(\Symfony\Component\Form\Form::class);
$this->validator = $validator;
$this->formRenderer = $formRenderer;
$this->translator = $translator;
// Register the form constraints in the validator programmatically.
// This functionality is required when using the Form component without
// the DIC, where the XML file is loaded automatically. Thus the following
// code must be kept synchronized with validation.xml
foreach ($metadata->getConstraints() as $constraint) {
if ($constraint instanceof Form) {
return;
}
}
$metadata->addConstraint(new Form());
$metadata->addConstraint(new Traverse(false));
$this->validator = $validator;
$this->formRenderer = $formRenderer;
$this->translator = $translator;
}
public function loadTypeGuesser(): ?FormTypeGuesserInterface

View File

@@ -1233,8 +1233,7 @@ class FrameworkExtension extends Extension
$container->setParameter('request_listener.https_port', $config['https_port']);
if (null !== $config['default_uri']) {
$container->getDefinition('router.request_context')
->replaceArgument(0, $config['default_uri']);
$container->setParameter('router.request_context.base_url', $config['default_uri']);
}
if ($this->isInitializedConfigEnabled('annotations') && (new \ReflectionClass(AttributeClassLoader::class))->hasProperty('reader')) {
@@ -1265,6 +1264,7 @@ class FrameworkExtension extends Extension
}
$container->setParameter('session.storage.options', $options);
$container->setParameter('session.metadata.cookie_lifetime', $options['cookie_lifetime'] ?? null);
// session handler (the internal callback registered with PHP session management)
if (null === $config['handler_id']) {

View File

@@ -43,6 +43,7 @@ return static function (ContainerConfigurator $container) {
->args([
param('session.metadata.storage_key'),
param('session.metadata.update_threshold'),
param('session.metadata.cookie_lifetime'),
]),
false,
])
@@ -53,6 +54,7 @@ return static function (ContainerConfigurator $container) {
->args([
param('session.metadata.storage_key'),
param('session.metadata.update_threshold'),
param('session.metadata.cookie_lifetime'),
]),
false,
])
@@ -64,6 +66,7 @@ return static function (ContainerConfigurator $container) {
->args([
param('session.metadata.storage_key'),
param('session.metadata.update_threshold'),
param('session.metadata.cookie_lifetime'),
]),
])

View File

@@ -12,10 +12,12 @@
namespace Symfony\Bundle\FrameworkBundle\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Service\ResetInterface;
@@ -38,6 +40,8 @@ abstract class KernelTestCase extends TestCase
protected static $booted = false;
private static bool $kernelHasBeenRebooted = false;
protected function tearDown(): void
{
static::ensureKernelShutdown();
@@ -88,6 +92,7 @@ abstract class KernelTestCase extends TestCase
// reboot a fresh one.
if ($kernel->getContainer()->initialized('cache_warmer')) {
static::ensureKernelShutdown();
self::$kernelHasBeenRebooted = true;
$kernel = static::createKernel($options);
$kernel->boot();
@@ -161,6 +166,20 @@ abstract class KernelTestCase extends TestCase
static::$kernel->shutdown();
static::$booted = false;
if (self::$kernelHasBeenRebooted) {
self::$kernelHasBeenRebooted = false;
try {
(new \ReflectionProperty(Kernel::class, 'freshCache'))->setValue(null, []);
} catch (\ReflectionException) {
// ignore if the property doesn't exist
}
try {
(new \ReflectionProperty(SelfCheckingResourceChecker::class, 'cache'))->setValue(null, []);
} catch (\ReflectionException) {
// ignore if the property doesn't exist
}
}
if ($container instanceof ResetInterface) {
$container->reset();
}

View File

@@ -41,14 +41,18 @@ class MetadataBag implements SessionBagInterface
private int $updateThreshold;
private ?int $cookieLifetime;
/**
* @param string $storageKey The key used to store bag in the session
* @param int $updateThreshold The time to wait between two UPDATED updates
* @param string $storageKey The key used to store bag in the session
* @param int $updateThreshold The time to wait between two UPDATED updates
* @param int|null $cookieLifetime The configured cookie lifetime; null to read from php.ini
*/
public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0)
public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0, ?int $cookieLifetime = null)
{
$this->storageKey = $storageKey;
$this->updateThreshold = $updateThreshold;
$this->cookieLifetime = $cookieLifetime;
}
/**
@@ -143,6 +147,6 @@ class MetadataBag implements SessionBagInterface
{
$timeStamp = time();
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
$this->meta[self::LIFETIME] = $lifetime ?? (int) \ini_get('session.cookie_lifetime');
$this->meta[self::LIFETIME] = $lifetime ?? $this->cookieLifetime ?? (int) \ini_get('session.cookie_lifetime');
}
}

View File

@@ -105,7 +105,7 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscr
try {
$payload = $this->$payloadMapper($request, $type, $argument);
} catch (PartialDenormalizationException $e) {
$trans = $this->translator ? $this->translator->trans(...) : fn ($m, $p) => strtr($m, $p);
$trans = $this->translator ? $this->translator->trans(...) : static fn ($m, $p) => strtr($m, $p);
foreach ($e->getErrors() as $error) {
$parameters = [];
$template = 'This value was of an unexpected type.';
@@ -187,7 +187,7 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscr
}
if (\is_array($data)) {
return $this->serializer->denormalize($data, $type, 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE);
return $this->serializer->denormalize($data, $type, self::hasNonStringScalar($data) ? $format : 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE);
}
if ('form' === $format) {
@@ -202,4 +202,21 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscr
throw new HttpException(Response::HTTP_BAD_REQUEST, \sprintf('Request payload contains invalid "%s" data.', $format), $e);
}
}
private static function hasNonStringScalar(array $data): bool
{
$stack = [$data];
while ($stack) {
foreach (array_pop($stack) as $v) {
if (\is_array($v)) {
$stack[] = $v;
} elseif (!\is_string($v)) {
return true;
}
}
}
return false;
}
}

View File

@@ -171,6 +171,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
if ($autowireAttributes) {
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
$attribute = $autowireAttributes[0]->newInstance();
$value = $parameterBag->resolveValue($attribute->value);

View File

@@ -47,6 +47,7 @@ class LocaleListener implements EventSubscriberInterface
public function setDefaultLocale(KernelEvent $event): void
{
$event->getRequest()->setDefaultLocale($this->defaultLocale);
$this->setRouterLocale($this->defaultLocale);
}
public function onKernelRequest(RequestEvent $event): void
@@ -54,14 +55,12 @@ class LocaleListener implements EventSubscriberInterface
$request = $event->getRequest();
$this->setLocale($request);
$this->setRouterContext($request);
$this->setRouterLocale($request->getLocale());
}
public function onKernelFinishRequest(FinishRequestEvent $event): void
{
if (null !== $parentRequest = $this->requestStack->getParentRequest()) {
$this->setRouterContext($parentRequest);
}
$this->setRouterLocale($this->requestStack->getParentRequest()?->getLocale() ?? $this->defaultLocale);
}
private function setLocale(Request $request): void
@@ -76,9 +75,9 @@ class LocaleListener implements EventSubscriberInterface
}
}
private function setRouterContext(Request $request): void
private function setRouterLocale(string $locale): void
{
$this->router?->getContext()->setParameter('_locale', $request->getLocale());
$this->router?->getContext()->setParameter('_locale', $locale);
}
public static function getSubscribedEvents(): array

View File

@@ -77,11 +77,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
*/
private static array $freshCache = [];
public const VERSION = '6.4.34';
public const VERSION_ID = 60434;
public const VERSION = '6.4.36';
public const VERSION_ID = 60436;
public const MAJOR_VERSION = 6;
public const MINOR_VERSION = 4;
public const RELEASE_VERSION = 34;
public const RELEASE_VERSION = 36;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2026';

View File

@@ -44,15 +44,11 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
return $supported;
}
if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) {
if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('shell_exec') || !\function_exists('escapeshellarg')) {
return $supported = false;
}
ob_start();
passthru('command -v file', $exitStatus);
$binPath = trim(ob_get_clean());
return $supported = 0 === $exitStatus && '' !== $binPath;
return $supported = '' !== trim(shell_exec('command -v file') ?: '');
}
public function guessMimeType(string $path): ?string
@@ -65,17 +61,8 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
throw new LogicException(\sprintf('The "%s" guesser is not supported.', __CLASS__));
}
ob_start();
// need to use --mime instead of -i. see #6641
passthru(\sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return);
if ($return > 0) {
ob_end_clean();
return null;
}
$type = trim(ob_get_clean());
$type = trim(shell_exec(\sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path))) ?: '');
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) {
// it's not a type, but an error message

View File

@@ -141,7 +141,7 @@ class DataPart extends TextPart
}
$this->_headers = $this->getHeaders();
return ['_headers', '_parent', 'filename', 'mediaType'];
return ['_headers', '_parent', 'filename', 'mediaType', 'cid'];
}
/**

View File

@@ -211,6 +211,10 @@ final class Ctype
*/
private static function convert_int_to_char_for_ctype($int, $function)
{
if (\PHP_VERSION_ID >= 80100 && !\is_string($int)) {
@trigger_error($function.'(): Argument of type '.get_debug_type($int).' will be interpreted as string in the future', \E_USER_DEPRECATED);
}
if (!\is_int($int)) {
return $int;
}
@@ -219,10 +223,6 @@ final class Ctype
return (string) $int;
}
if (\PHP_VERSION_ID >= 80100) {
@trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
}
if ($int < 0) {
$int += 256;
}

View File

@@ -27,6 +27,7 @@ namespace Symfony\Polyfill\Intl\Grapheme;
* - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack
* - grapheme_substr - Return part of a string
* - grapheme_str_split - Splits a string into an array of individual or chunks of graphemes
* - grapheme_levenshtein - Calculate the grapheme-unit Levenshtein distance between two strings
*
* @author Nicolas Grekas <p@tchwork.com>
*
@@ -51,7 +52,7 @@ final class Grapheme
if (!\is_scalar($s)) {
$hasError = false;
set_error_handler(function () use (&$hasError) { $hasError = true; });
set_error_handler(static function () use (&$hasError) { $hasError = true; });
$next = substr($s, $start);
restore_error_handler();
if ($hasError) {
@@ -223,6 +224,54 @@ final class Grapheme
return $chunks;
}
public static function grapheme_levenshtein($s1, $s2, $insertion_cost = 1, $replacement_cost = 1, $deletion_cost = 1)
{
if (!preg_match('//u', $s1) || !preg_match('//u', $s2)) {
return false;
}
if (0 > $insertion_cost || 0 > $replacement_cost || 0 > $deletion_cost) {
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError('grapheme_levenshtein(): Argument #3 ($insertion_cost), #4 ($replacement_cost), and #5 ($deletion_cost) must be greater than or equal to 0');
}
preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s1, $s1);
preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s2, $s2);
$s1 = $s1[0];
$s2 = $s2[0];
$l1 = \count($s1);
$l2 = \count($s2);
if (0 === $l1) {
return $l2 * $insertion_cost;
}
if (0 === $l2) {
return $l1 * $deletion_cost;
}
$dp = array_fill(0, $l1 + 1, array_fill(0, $l2 + 1, 0));
for ($i = 1; $i <= $l1; ++$i) {
$dp[$i][0] = $dp[$i - 1][0] + $deletion_cost;
}
for ($j = 1; $j <= $l2; ++$j) {
$dp[0][$j] = $dp[0][$j - 1] + $insertion_cost;
}
for ($i = 1; $i <= $l1; ++$i) {
for ($j = 1; $j <= $l2; ++$j) {
$cost = ($s1[$i - 1] === $s2[$j - 1]) ? 0 : $replacement_cost;
$dp[$i][$j] = min($dp[$i - 1][$j] + $deletion_cost, $dp[$i][$j - 1] + $insertion_cost, $dp[$i - 1][$j - 1] + $cost);
}
}
return $dp[$l1][$l2];
}
private static function grapheme_position($s, $needle, $offset, $mode)
{
$needle = (string) $needle;

View File

@@ -53,5 +53,8 @@ if (!function_exists('grapheme_substr')) {
function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); }
}
if (!function_exists('grapheme_str_split')) {
function grapheme_str_split($string, $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); }
function grapheme_str_split(string $string, int $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); }
}
if (!function_exists('grapheme_levenshtein')) {
function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1, string $locale = '') { return p\Php85::grapheme_levenshtein($string1, $string2, $insertion_cost, $replacement_cost, $deletion_cost); }
}

View File

@@ -14,6 +14,9 @@ use Symfony\Polyfill\Intl\Grapheme as p;
if (!function_exists('grapheme_str_split')) {
function grapheme_str_split(string $string, int $length = 1): array|false { return p\Grapheme::grapheme_str_split($string, $length); }
}
if (!function_exists('grapheme_levenshtein')) {
function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1, string $locale = ''): int|false { return p\Grapheme::grapheme_levenshtein($string1, $string2, $insertion_cost, $replacement_cost, $deletion_cost); }
}
if (extension_loaded('intl')) {
return;

View File

@@ -118,17 +118,15 @@ abstract class Collator
}
/**
* Not supported. Compare two Unicode strings.
* Compare two Unicode strings.
*
* @return int|false
*
* @see https://php.net/collator.compare
*
* @throws MethodNotImplementedException
*/
public function compare(string $string1, string $string2)
{
throw new MethodNotImplementedException(__METHOD__);
return strcasecmp($string1, $string2) ?: $string2 <=> $string1;
}
/**

View File

@@ -104,7 +104,7 @@ class FullTransformer
// handle unimplemented characters
if (false !== strpos($this->notImplementedChars, $dateChars[0])) {
throw new NotImplementedException(sprintf('Unimplemented date character "%s" in format "%s".', $dateChars[0], $this->pattern));
throw new NotImplementedException(\sprintf('Unimplemented date character "%s" in format "%s".', $dateChars[0], $this->pattern));
}
return '';
@@ -212,7 +212,7 @@ class FullTransformer
{
$specialCharsArray = str_split($specialChars);
$specialCharsMatch = implode('|', array_map(function ($char) {
$specialCharsMatch = implode('|', array_map(static function ($char) {
return $char.'+';
}, $specialCharsArray));

View File

@@ -53,7 +53,7 @@ class MonthTransformer extends Transformer
public function __construct()
{
if (0 === \count(self::$shortMonths)) {
self::$shortMonths = array_map(function ($month) {
self::$shortMonths = array_map(static function ($month) {
return substr($month, 0, 3);
}, self::$months);

View File

@@ -39,9 +39,9 @@ class QuarterTransformer extends Transformer
$map = [1 => '1st quarter', 2 => '2nd quarter', 3 => '3rd quarter', 4 => '4th quarter'];
return $map[$quarter];
} else {
return $quarter;
}
return $quarter;
}
}

View File

@@ -55,7 +55,7 @@ class TimezoneTransformer extends Transformer
return $dateTime->format('\G\M\TP');
}
return sprintf('GMT%s%d', $offset >= 0 ? '+' : '', $offset / 100);
return \sprintf('GMT%s%d', $offset >= 0 ? '+' : '', $offset / 100);
}
public function getReverseMatchingRegExp(int $length): string
@@ -97,12 +97,12 @@ class TimezoneTransformer extends Transformer
$signal = '-' === $matches['signal'] ? '+' : '-';
if (0 < $minutes) {
throw new NotImplementedException(sprintf('It is not possible to use a GMT time zone with minutes offset different than zero (0). GMT time zone tried: "%s".', $formattedTimeZone));
throw new NotImplementedException(\sprintf('It is not possible to use a GMT time zone with minutes offset different than zero (0). GMT time zone tried: "%s".', $formattedTimeZone));
}
return 'Etc/GMT'.(0 !== $hours ? $signal.$hours : '');
}
throw new \InvalidArgumentException(sprintf('The GMT time zone "%s" does not match with the supported formats GMT[+-]HH:MM or GMT[+-]HHMM.', $formattedTimeZone));
throw new \InvalidArgumentException(\sprintf('The GMT time zone "%s" does not match with the supported formats GMT[+-]HH:MM or GMT[+-]HHMM.', $formattedTimeZone));
}
}

View File

@@ -22,7 +22,7 @@ class MethodArgumentNotImplementedException extends NotImplementedException
*/
public function __construct(string $methodName, string $argName)
{
$message = sprintf('The %s() method\'s argument $%s behavior is not implemented.', $methodName, $argName);
$message = \sprintf('The %s() method\'s argument $%s behavior is not implemented.', $methodName, $argName);
parent::__construct($message);
}
}

View File

@@ -24,7 +24,7 @@ class MethodArgumentValueNotImplementedException extends NotImplementedException
*/
public function __construct(string $methodName, string $argName, $argValue, string $additionalMessage = '')
{
$message = sprintf(
$message = \sprintf(
'The %s() method\'s argument $%s value %s behavior is not implemented.%s',
$methodName,
$argName,

View File

@@ -21,6 +21,6 @@ class MethodNotImplementedException extends NotImplementedException
*/
public function __construct(string $methodName)
{
parent::__construct(sprintf('The %s() is not implemented.', $methodName));
parent::__construct(\sprintf('The %s() is not implemented.', $methodName));
}
}

View File

@@ -108,10 +108,10 @@ abstract class Icu
public static function setError(int $code, string $message = '')
{
if (!isset(self::$errorCodes[$code])) {
throw new \InvalidArgumentException(sprintf('No such error code: "%s".', $code));
throw new \InvalidArgumentException(\sprintf('No such error code: "%s".', $code));
}
self::$errorMessage = $message ? sprintf('%s: %s', $message, self::$errorCodes[$code]) : self::$errorCodes[$code];
self::$errorMessage = $message ? \sprintf('%s: %s', $message, self::$errorCodes[$code]) : self::$errorCodes[$code];
self::$errorCode = $code;
}
}

View File

@@ -225,7 +225,7 @@ abstract class IntlDateFormatter
// behave like the intl extension
$argumentError = null;
if (!\is_int($datetime) && !$datetime instanceof \DateTimeInterface) {
$argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $datetime);
$argumentError = \sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $datetime);
}
if (null !== $argumentError) {

View File

@@ -0,0 +1,169 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Intl\Icu;
/**
* @author Ayesh Karunaratne <ayesh@aye.sh>
*
* @internal
*/
class IntlListFormatter
{
public const TYPE_AND = 0;
public const TYPE_OR = 1;
public const TYPE_UNITS = 2;
public const WIDTH_WIDE = 0;
public const WIDTH_SHORT = 1;
public const WIDTH_NARROW = 2;
private $type;
private $width;
private const TYPE_MAP = [
self::TYPE_AND => 'standard',
self::TYPE_OR => 'or',
self::TYPE_UNITS => 'unit',
];
private const WIDTH_MAP = [
self::WIDTH_WIDE => '',
self::WIDTH_SHORT => '-short',
self::WIDTH_NARROW => '-narrow',
];
private const EN_LIST_PATTERNS = [
'listPattern-type-standard' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, and {1}',
2 => '{0} and {1}',
],
'listPattern-type-or' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, or {1}',
2 => '{0} or {1}',
],
'listPattern-type-or-narrow' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, or {1}',
2 => '{0} or {1}',
],
'listPattern-type-or-short' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, or {1}',
2 => '{0} or {1}',
],
'listPattern-type-standard-narrow' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, {1}',
2 => '{0}, {1}',
],
'listPattern-type-standard-short' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, & {1}',
2 => '{0} & {1}',
],
'listPattern-type-unit' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, {1}',
2 => '{0}, {1}',
],
'listPattern-type-unit-narrow' => [
'start' => '{0} {1}',
'middle' => '{0} {1}',
'end' => '{0} {1}',
2 => '{0} {1}',
],
'listPattern-type-unit-short' => [
'start' => '{0}, {1}',
'middle' => '{0}, {1}',
'end' => '{0}, {1}',
2 => '{0}, {1}',
],
];
public function __construct(string $locale, int $type = self::TYPE_AND, int $width = self::WIDTH_WIDE)
{
if ('en' !== $locale && 0 !== strpos($locale, 'en')) {
if (80000 > \PHP_VERSION_ID) {
throw new \InvalidArgumentException('Invalid locale, only "en" and "en-*" locales are supported.');
}
throw new \ValueError('Invalid locale, only "en" and "en-*" locales are supported.');
}
if (!isset(self::TYPE_MAP[$type])) {
if (80000 > \PHP_VERSION_ID) {
throw new \InvalidArgumentException('Argument #2 ($type) must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS.');
}
throw new \ValueError('Argument #2 ($type) must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS.');
}
if (!isset(self::WIDTH_MAP[$width])) {
if (80000 > \PHP_VERSION_ID) {
throw new \InvalidArgumentException('Argument #3 ($width) must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW.');
}
throw new \ValueError('Argument #3 ($width) must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW.');
}
$this->type = $type;
$this->width = $width;
}
public function format(array $strings): string
{
$count = \count($strings);
if (0 === $count) {
return '';
}
$strings = array_values($strings);
if (1 === $count) {
return (string) $strings[0];
}
$pattern = self::EN_LIST_PATTERNS['listPattern-type-'.self::TYPE_MAP[$this->type].self::WIDTH_MAP[$this->width]];
if (2 === $count) {
return strtr($pattern[2], ['{0}' => (string) $strings[0], '{1}' => (string) $strings[1]]);
}
$result = strtr($pattern['start'], ['{0}' => (string) $strings[0], '{1}' => (string) $strings[1]]);
for ($i = 2; $i < $count - 1; ++$i) {
$result = strtr($pattern['middle'], ['{0}' => $result, '{1}' => (string) $strings[$i]]);
}
return strtr($pattern['end'], ['{0}' => $result, '{1}' => (string) $strings[$count - 1]]);
}
public function getErrorCode(): int
{
return 0;
}
public function getErrorMessage(): string
{
return '';
}
}

View File

@@ -41,6 +41,28 @@ abstract class Locale
public const GRANDFATHERED_LANG_TAG = 'grandfathered';
public const PRIVATE_TAG = 'private';
private const RTL_SCRIPTS = [
'Adlm' => true, 'Arab' => true, 'Armi' => true, 'Hebr' => true,
'Mand' => true, 'Mani' => true, 'Mend' => true, 'Nkoo' => true,
'Orkh' => true, 'Phnx' => true, 'Rohg' => true, 'Samr' => true,
'Syrc' => true, 'Thaa' => true, 'Yezi' => true,
];
private const LANG_TO_SCRIPT = [
'ar' => 'Arab',
'ckb' => 'Arab',
'dv' => 'Thaa',
'fa' => 'Arab',
'he' => 'Hebr',
'ku' => 'Arab',
'nqo' => 'Nkoo',
'ps' => 'Arab',
'sd' => 'Arab',
'ug' => 'Arab',
'ur' => 'Arab',
'yi' => 'Hebr',
];
/**
* Not supported. Returns the best available locale based on HTTP "Accept-Language" header according to RFC 2616.
*
@@ -307,4 +329,22 @@ abstract class Locale
return true;
}
public static function isRightToLeft(string $locale): bool
{
if ('' === $locale) {
return false;
}
$parts = preg_split('/[_-]/', $locale);
$language = strtolower($parts[0]);
foreach ($parts as $part) {
if (4 === \strlen($part) && ctype_alpha($part)) {
return isset(self::RTL_SCRIPTS[ucfirst(strtolower($part))]);
}
}
return isset(self::LANG_TO_SCRIPT[$language]) && isset(self::RTL_SCRIPTS[self::LANG_TO_SCRIPT[$language]]);
}
}

View File

@@ -261,7 +261,7 @@ abstract class NumberFormatter
}
if (!\in_array($style, self::$supportedStyles)) {
$message = sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
$message = \sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'style', $style, $message);
}
@@ -352,7 +352,7 @@ abstract class NumberFormatter
// The original NumberFormatter does not support this format type
if (self::TYPE_CURRENCY === $type) {
if (\PHP_VERSION_ID >= 80000) {
throw new \ValueError(sprintf('The format type must be a NumberFormatter::TYPE_* constant (%s given).', $type));
throw new \ValueError(\sprintf('The format type must be a NumberFormatter::TYPE_* constant (%s given).', $type));
}
trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
@@ -361,7 +361,7 @@ abstract class NumberFormatter
}
if (self::CURRENCY === $this->style) {
throw new NotImplementedException(sprintf('"%s()" method does not support the formatting of currencies (instance with CURRENCY style). "%s".', __METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE));
throw new NotImplementedException(\sprintf('"%s()" method does not support the formatting of currencies (instance with CURRENCY style). "%s".', __METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE));
}
// Only the default type is supported.
@@ -496,7 +496,7 @@ abstract class NumberFormatter
{
if (self::TYPE_DEFAULT === $type || self::TYPE_CURRENCY === $type) {
if (\PHP_VERSION_ID >= 80000) {
throw new \ValueError(sprintf('The format type must be a NumberFormatter::TYPE_* constant (%d given).', $type));
throw new \ValueError(\sprintf('The format type must be a NumberFormatter::TYPE_* constant (%d given).', $type));
}
trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
@@ -553,7 +553,7 @@ abstract class NumberFormatter
public function setAttribute(int $attribute, $value)
{
if (!\in_array($attribute, self::$supportedAttributes)) {
$message = sprintf(
$message = \sprintf(
'The available attributes are: %s',
implode(', ', array_keys(self::$supportedAttributes))
);
@@ -562,7 +562,7 @@ abstract class NumberFormatter
}
if (self::$supportedAttributes['ROUNDING_MODE'] === $attribute && $this->isInvalidRoundingMode($value)) {
$message = sprintf(
$message = \sprintf(
'The supported values for ROUNDING_MODE are: %s',
implode(', ', array_keys(self::$roundingModes))
);

View File

@@ -13,6 +13,7 @@ It is limited to the "en" locale and to:
- [`NumberFormatter`](https://php.net/NumberFormatter)
- [`Locale`](https://php.net/Locale)
- [`IntlDateFormatter`](https://php.net/IntlDateFormatter)
- [`IntlListFormatter`](https://php.net/IntlListFormatter)
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Icu\IntlListFormatter as IntlListFormatterPolyfill;
/**
* Stub implementation for the IntlListFormatter class of the intl extension.
*
* @author Ayesh Karunaratne <ayesh@aye.sh>
*/
final class IntlListFormatter extends IntlListFormatterPolyfill
{
}

View File

@@ -133,7 +133,7 @@ final class Mbstring
public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
{
$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
array_walk_recursive($vars, static function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
$ok = false;
}
@@ -194,7 +194,7 @@ final class Mbstring
$convmap[$i + 1] += $convmap[$i + 2];
}
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))'.(\PHP_VERSION_ID >= 80200 ? '' : '(?!&)').';?/', static function (array $m) use ($cnt, $convmap) {
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
for ($i = 0; $i < $cnt; $i += 4) {
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
@@ -268,7 +268,7 @@ final class Mbstring
for ($j = 0; $j < $cnt; $j += 4) {
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
$result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
continue 2;
}
}
@@ -382,7 +382,7 @@ final class Mbstring
return false;
}
throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
public static function mb_language($lang = null)
@@ -403,7 +403,7 @@ final class Mbstring
return false;
}
throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
}
public static function mb_list_encodings()
@@ -834,19 +834,32 @@ final class Mbstring
return $code;
}
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
/** @return string|false */
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
if (\PHP_VERSION_ID < 80000) {
trigger_error('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH', \E_USER_WARNING);
return false;
}
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
}
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}
if (self::mb_strlen($pad_string, $encoding) <= 0) {
if (\PHP_VERSION_ID < 80000) {
trigger_error('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string', \E_USER_WARNING);
return false;
}
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
}
@@ -869,12 +882,13 @@ final class Mbstring
}
}
public static function mb_ucfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_ucfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}
$firstChar = mb_substr($string, 0, 1, $encoding);
@@ -883,12 +897,13 @@ final class Mbstring
return $firstChar.mb_substr($string, 1, null, $encoding);
}
public static function mb_lcfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_lcfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}
$firstChar = mb_substr($string, 0, 1, $encoding);
@@ -968,30 +983,42 @@ final class Mbstring
return 'UTF-8';
}
if ('UTF-32' === $encoding) {
return 'UTF-32BE';
}
if ('UTF-16' === $encoding) {
return 'UTF-16BE';
}
return $encoding;
}
public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
}
public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
}
public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
}
private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string
/** @return string|false */
private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}
if ('' === $characters) {
@@ -1020,7 +1047,7 @@ final class Mbstring
$characters = preg_quote($characters);
}
$string = preg_replace(sprintf($regex, $characters), '', $string);
$string = preg_replace(\sprintf($regex, $characters), '', $string);
if (null === $encoding) {
return $string;
@@ -1029,17 +1056,22 @@ final class Mbstring
return iconv('UTF-8', $encoding.'//IGNORE', $string);
}
private static function assertEncoding(string $encoding, string $errorFormat): void
private static function assertEncoding(string $encoding, string $errorFormat): bool
{
try {
$validEncoding = @self::mb_check_encoding('', $encoding);
} catch (\ValueError $e) {
throw new \ValueError(sprintf($errorFormat, $encoding));
throw new \ValueError(\sprintf($errorFormat, $encoding));
}
// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf($errorFormat, $encoding));
if (80000 > \PHP_VERSION_ID) {
trigger_error(\sprintf($errorFormat, $encoding), \E_USER_WARNING);
} else {
throw new \ValueError(\sprintf($errorFormat, $encoding));
}
}
return $validEncoding;
}
}

View File

@@ -133,30 +133,29 @@ if (!function_exists('mb_str_split')) {
}
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null) { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (!function_exists('mb_ucfirst')) {
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
function mb_ucfirst(string $string, ?string $encoding = null) { return p\Mbstring::mb_ucfirst($string, $encoding); }
}
if (!function_exists('mb_lcfirst')) {
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
function mb_lcfirst(string $string, ?string $encoding = null) { return p\Mbstring::mb_lcfirst($string, $encoding); }
}
if (!function_exists('mb_trim')) {
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_trim($string, $characters, $encoding); }
}
if (!function_exists('mb_ltrim')) {
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
}
if (!function_exists('mb_rtrim')) {
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}

View File

@@ -32,7 +32,7 @@ final class Php83
}
if ($depth > self::JSON_MAX_DEPTH) {
throw new \ValueError(sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH));
throw new \ValueError(\sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH));
}
json_decode($json, true, $depth, $flags);
@@ -40,7 +40,8 @@ final class Php83
return \JSON_ERROR_NONE === json_last_error();
}
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
/** @return string|false */
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
@@ -50,19 +51,27 @@ final class Php83
$encoding = mb_internal_encoding();
}
$errorToTrigger = null;
try {
$validEncoding = @mb_check_encoding('', $encoding);
if (!@mb_check_encoding('', $encoding)) {
$errorToTrigger = \sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding);
}
} catch (\ValueError $e) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
$errorToTrigger = \sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding);
}
if (mb_strlen($pad_string, $encoding) <= 0) {
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
$errorToTrigger = 'mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string';
}
if (null !== $errorToTrigger) {
if (80000 > \PHP_VERSION_ID) {
trigger_error($errorToTrigger, \E_USER_WARNING);
return false;
}
throw new \ValueError($errorToTrigger);
}
$paddingRequired = $length - mb_strlen($string, $encoding);
@@ -135,7 +144,7 @@ final class Php83
}
if (preg_match('/\A(?:0[aA0]?|[aA])\z/', $string)) {
throw new \ValueError(sprintf('str_decrement(): Argument #1 ($string) "%s" is out of decrement range', $string));
throw new \ValueError(\sprintf('str_decrement(): Argument #1 ($string) "%s" is out of decrement range', $string));
}
if (!\in_array(substr($string, -1), ['A', 'a', '0'], true)) {

View File

@@ -19,12 +19,6 @@ if (!function_exists('json_validate')) {
function json_validate(string $json, int $depth = 512, int $flags = 0): bool { return p\Php83::json_validate($json, $depth, $flags); }
}
if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}
if (!function_exists('stream_context_set_options')) {
function stream_context_set_options($context, array $options): bool { return stream_context_set_option($context, $options); }
}
@@ -37,8 +31,14 @@ if (!function_exists('str_decrement')) {
function str_decrement(string $string): string { return p\Php83::str_decrement($string); }
}
if (\PHP_VERSION_ID >= 80100) {
return require __DIR__.'/bootstrap81.php';
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null) { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}
if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Php83 as p;
if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}
if (\PHP_VERSION_ID >= 80100) {
return require __DIR__.'/bootstrap81.php';
}
if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {
function ldap_exop_sync($ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
}
if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {
function ldap_connect_wallet(?string $uri, string $wallet, string $password, int $auth_mode = \GSLC_SSL_NO_AUTH) { return ldap_connect($uri, $wallet, $password, $auth_mode); }
}

View File

@@ -0,0 +1,19 @@
CHANGELOG
=========
6.4
---
* Add argument `bool $debug = false` to `HttpKernelRunner::__construct()`
5.4
---
* The component is not experimental anymore
* Add options "env_var_name" and "debug_var_name" to `GenericRuntime` and `SymfonyRuntime`
* Add option "dotenv_overload" to `SymfonyRuntime`
5.3.0
-----
* Add the component

View File

@@ -0,0 +1,223 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Runtime;
use Symfony\Component\Runtime\Internal\BasicErrorHandler;
use Symfony\Component\Runtime\Resolver\ClosureResolver;
use Symfony\Component\Runtime\Resolver\DebugClosureResolver;
use Symfony\Component\Runtime\Runner\ClosureRunner;
// Help opcache.preload discover always-needed symbols
class_exists(ClosureResolver::class);
/**
* A runtime to do bare-metal PHP without using superglobals.
*
* It supports the following options:
* - "debug" toggles displaying errors and defaults
* to the "APP_DEBUG" environment variable;
* - "runtimes" maps types to a GenericRuntime implementation
* that knows how to deal with each of them;
* - "error_handler" defines the class to use to handle PHP errors;
* - "env_var_name" and "debug_var_name" define the name of the env
* vars that hold the Symfony env and the debug flag respectively.
*
* The app-callable can declare arguments among either:
* - "array $context" to get a local array similar to $_SERVER;
* - "array $argv" to get the command line arguments when running on the CLI;
* - "array $request" to get a local array with keys "query", "body", "files" and
* "session", which map to $_GET, $_POST, $FILES and &$_SESSION respectively.
*
* It should return a Closure():int|string|null or an instance of RunnerInterface.
*
* In debug mode, the runtime registers a strict error handler
* that throws exceptions when a PHP warning/notice is raised.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class GenericRuntime implements RuntimeInterface
{
protected $options;
/**
* @param array {
* debug?: ?bool,
* runtimes?: ?array,
* error_handler?: string|false,
* env_var_name?: string,
* debug_var_name?: string,
* } $options
*/
public function __construct(array $options = [])
{
$options['env_var_name'] ??= 'APP_ENV';
$debugKey = $options['debug_var_name'] ??= 'APP_DEBUG';
$debug = $options['debug'] ?? $_SERVER[$debugKey] ?? $_ENV[$debugKey] ?? true;
if (!\is_bool($debug)) {
$debug = filter_var($debug, \FILTER_VALIDATE_BOOL);
}
if ($debug) {
umask(0000);
$_SERVER[$debugKey] = $_ENV[$debugKey] = '1';
} else {
$_SERVER[$debugKey] = $_ENV[$debugKey] = '0';
}
if (false !== $errorHandler = ($options['error_handler'] ?? BasicErrorHandler::class)) {
$errorHandler::register($debug);
$options['error_handler'] = false;
}
$this->options = $options;
}
public function getResolver(callable $callable, ?\ReflectionFunction $reflector = null): ResolverInterface
{
$callable = $callable(...);
$parameters = ($reflector ?? new \ReflectionFunction($callable))->getParameters();
$arguments = function () use ($parameters) {
$arguments = [];
try {
foreach ($parameters as $parameter) {
$type = $parameter->getType();
$arguments[] = $this->getArgument($parameter, $type instanceof \ReflectionNamedType ? $type->getName() : null);
}
} catch (\InvalidArgumentException $e) {
if (!$parameter->isOptional()) {
throw $e;
}
}
return $arguments;
};
if ($_SERVER[$this->options['debug_var_name']]) {
return new DebugClosureResolver($callable, $arguments);
}
return new ClosureResolver($callable, $arguments);
}
public function getRunner(?object $application): RunnerInterface
{
$application ??= static fn () => 0;
if ($application instanceof RunnerInterface) {
return $application;
}
if (!$application instanceof \Closure) {
if ($runtime = $this->resolveRuntime($application::class)) {
return $runtime->getRunner($application);
}
if (!\is_callable($application)) {
throw new \LogicException(\sprintf('"%s" doesn\'t know how to handle apps of type "%s".', get_debug_type($this), get_debug_type($application)));
}
$application = $application(...);
}
if ($_SERVER[$this->options['debug_var_name']] && ($r = new \ReflectionFunction($application)) && $r->getNumberOfRequiredParameters()) {
throw new \ArgumentCountError(\sprintf('Zero argument should be required by the runner callable, but at least one is in "%s" on line "%d.', $r->getFileName(), $r->getStartLine()));
}
return new ClosureRunner($application);
}
protected function getArgument(\ReflectionParameter $parameter, ?string $type): mixed
{
if ('array' === $type) {
switch ($parameter->name) {
case 'context':
$context = $_SERVER;
if ($_ENV && !isset($_SERVER['PATH']) && !isset($_SERVER['Path'])) {
$context += $_ENV;
}
return $context;
case 'argv':
return $_SERVER['argv'] ?? [];
case 'request':
return [
'query' => $_GET,
'body' => $_POST,
'files' => $_FILES,
'session' => &$_SESSION,
];
}
}
if (RuntimeInterface::class === $type) {
return $this;
}
if (!$runtime = $this->getRuntime($type)) {
$r = $parameter->getDeclaringFunction();
throw new \InvalidArgumentException(\sprintf('Cannot resolve argument "%s $%s" in "%s" on line "%d": "%s" supports only arguments "array $context", "array $argv" and "array $request", or a runtime named "Symfony\Runtime\%1$sRuntime".', $type, $parameter->name, $r->getFileName(), $r->getStartLine(), get_debug_type($this)));
}
return $runtime->getArgument($parameter, $type);
}
protected static function register(self $runtime): self
{
return $runtime;
}
private function getRuntime(string $type): ?self
{
if (null === $runtime = ($this->options['runtimes'][$type] ?? null)) {
$runtime = 'Symfony\Runtime\\'.$type.'Runtime';
$runtime = class_exists($runtime) ? $runtime : $this->options['runtimes'][$type] = false;
}
if (\is_string($runtime)) {
$runtime = $runtime::register($this);
}
if ($this === $runtime) {
return null;
}
return $runtime ?: null;
}
private function resolveRuntime(string $class): ?self
{
if ($runtime = $this->getRuntime($class)) {
return $runtime;
}
foreach (class_parents($class) as $type) {
if ($runtime = $this->getRuntime($type)) {
return $runtime;
}
}
foreach (class_implements($class) as $type) {
if ($runtime = $this->getRuntime($type)) {
return $runtime;
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Runtime\Internal;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class BasicErrorHandler
{
public static function register(bool $debug): void
{
error_reporting(\E_ALL & ~\E_DEPRECATED & ~\E_USER_DEPRECATED);
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
ini_set('display_errors', $debug);
} elseif (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOL) || \ini_get('error_log')) {
// CLI - display errors only if they're not already logged to STDERR
ini_set('display_errors', 1);
}
if (0 <= \ini_get('zend.assertions')) {
ini_set('zend.assertions', (int) $debug);
}
ini_set('assert.active', 1);
ini_set('assert.exception', 1);
set_error_handler(new self());
}
public function __invoke(int $type, string $message, string $file, int $line): bool
{
if ((\E_DEPRECATED | \E_USER_DEPRECATED) & $type) {
return true;
}
if ((error_reporting() | \E_ERROR | \E_RECOVERABLE_ERROR | \E_PARSE | \E_CORE_ERROR | \E_COMPILE_ERROR | \E_USER_ERROR) & $type) {
throw new \ErrorException($message, 0, $type, $file, $line);
}
return false;
}
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Runtime\Internal;
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\ScriptEvents;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class ComposerPlugin implements PluginInterface, EventSubscriberInterface
{
private Composer $composer;
private IOInterface $io;
private static bool $activated = false;
public function activate(Composer $composer, IOInterface $io): void
{
self::$activated = true;
$this->composer = $composer;
$this->io = $io;
}
public function deactivate(Composer $composer, IOInterface $io): void
{
self::$activated = false;
}
public function uninstall(Composer $composer, IOInterface $io): void
{
@unlink($composer->getConfig()->get('vendor-dir').'/autoload_runtime.php');
}
public function updateAutoloadFile(): void
{
$vendorDir = realpath($this->composer->getConfig()->get('vendor-dir'));
if (!is_file($autoloadFile = $vendorDir.'/autoload.php')
|| false === $extra = $this->composer->getPackage()->getExtra()['runtime'] ?? []
) {
return;
}
$fs = new Filesystem();
$projectDir = \dirname(realpath(Factory::getComposerFile()));
if (null === $autoloadTemplate = $extra['autoload_template'] ?? null) {
$autoloadTemplate = __DIR__.'/autoload_runtime.template';
} else {
if (!$fs->isAbsolutePath($autoloadTemplate)) {
$autoloadTemplate = $projectDir.'/'.$autoloadTemplate;
}
if (!is_file($autoloadTemplate)) {
throw new \InvalidArgumentException(\sprintf('File "%s" defined under "extra.runtime.autoload_template" in your composer.json file not found.', $this->composer->getPackage()->getExtra()['runtime']['autoload_template']));
}
}
$projectDir = $fs->makePathRelative($projectDir, $vendorDir);
$nestingLevel = 0;
while (str_starts_with($projectDir, '../')) {
++$nestingLevel;
$projectDir = substr($projectDir, 3);
}
if (!$nestingLevel) {
$projectDir = '__'.'DIR__.'.var_export('/'.$projectDir, true);
} else {
$projectDir = 'dirname(__'."DIR__, $nestingLevel)".('' !== $projectDir ? '.'.var_export('/'.$projectDir, true) : '');
}
$runtimeClass = $extra['class'] ?? SymfonyRuntime::class;
unset($extra['class'], $extra['autoload_template']);
$code = strtr(file_get_contents($autoloadTemplate), [
'%project_dir%' => $projectDir,
'%runtime_class%' => var_export($runtimeClass, true),
'%runtime_options%' => '['.substr(var_export($extra, true), 7, -1)." 'project_dir' => {$projectDir},\n]",
]);
// could use Composer\Util\Filesystem::filePutContentsIfModified once Composer 1.x support is dropped for this plugin
$path = substr_replace($autoloadFile, '_runtime', -4, 0);
$currentContent = @file_exists($path) ? @file_get_contents($path) : false;
if (false === $currentContent || $currentContent !== $code) {
file_put_contents($path, $code);
}
}
public static function getSubscribedEvents(): array
{
if (!self::$activated) {
return [];
}
return [
ScriptEvents::POST_AUTOLOAD_DUMP => 'updateAutoloadFile',
];
}
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\Console;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class ApplicationRuntime extends SymfonyRuntime
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\Console\Command;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class CommandRuntime extends SymfonyRuntime
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\Console\Input;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class InputInterfaceRuntime extends SymfonyRuntime
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\Console\Output;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class OutputInterfaceRuntime extends SymfonyRuntime
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\HttpFoundation;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class RequestRuntime extends SymfonyRuntime
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Runtime\Symfony\Component\HttpFoundation;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
* @internal
*/
class ResponseRuntime extends SymfonyRuntime
{
}

Some files were not shown because too many files have changed in this diff Show More