From adff65a60246817685de0c1a68998364c9d6ffcf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 16 Aug 2017 10:13:36 +0200 Subject: [PATCH] [DI] Fix reading env vars from fastcgi params --- .../Compiler/ServiceLocatorTagPass.php | 7 ++--- .../DependencyInjection/Container.php | 5 +++- .../DependencyInjection/ContainerBuilder.php | 15 ++++++----- .../EnvPlaceholderParameterBag.php | 26 +++++++++++++++++++ .../Tests/ContainerBuilderTest.php | 24 +++++++++++------ 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index bf9f83bbe80d..59c5e390223c 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -54,20 +54,17 @@ protected function processValue($value, $isRoot = false) $value->setArguments($arguments); - if ($public = $value->isPublic()) { - $value->setPublic(false); - } $id = 'service_locator.'.md5(serialize($value)); if ($isRoot) { if ($id !== $this->currentId) { - $this->container->setAlias($id, new Alias($this->currentId, $public)); + $this->container->setAlias($id, new Alias($this->currentId, false)); } return $value; } - $this->container->setDefinition($id, $value); + $this->container->setDefinition($id, $value->setPublic(false)); return new Reference($id); } diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 3b0a82d80ea1..81241e3415cc 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -429,7 +429,7 @@ public static function underscore($id) * * @param string $name The name of the environment variable * - * @return scalar The value to use for the provided environment variable name + * @return mixed The value to use for the provided environment variable name * * @throws EnvNotFoundException When the environment variable is not found and has no default value */ @@ -438,6 +438,9 @@ protected function getEnv($name) if (isset($this->envCache[$name]) || array_key_exists($name, $this->envCache)) { return $this->envCache[$name]; } + if (0 !== strpos($name, 'HTTP_') && isset($_SERVER[$name])) { + return $this->envCache[$name] = $_SERVER[$name]; + } if (isset($_ENV[$name])) { return $this->envCache[$name] = $_ENV[$name]; } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 555c3b09734b..4f86cd046868 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -729,9 +729,10 @@ public function compile(/*$resolveEnvPlaceholders = false*/) $bag = $this->getParameterBag(); if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) { - $this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true)); + $bag->resolveEnvReferences(); + $this->parameterBag = new ParameterBag($bag->all()); $this->envPlaceholders = $bag->getEnvPlaceholders(); - $this->parameterBag = $bag = new ParameterBag($this->resolveEnvPlaceholders($this->parameterBag->all())); + $this->parameterBag = $bag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true)); } $compiler->compile($this); @@ -746,7 +747,9 @@ public function compile(/*$resolveEnvPlaceholders = false*/) parent::compile(); - $this->envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : array(); + if ($bag instanceof EnvPlaceholderParameterBag) { + $this->envPlaceholders = $bag->getEnvPlaceholders(); + } } /** @@ -1311,10 +1314,10 @@ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs foreach ($envPlaceholders as $env => $placeholders) { foreach ($placeholders as $placeholder) { if (false !== stripos($value, $placeholder)) { - if (true === $format) { - $resolved = $bag->escapeValue($this->getEnv($env)); - } else { + if (true !== $format) { $resolved = sprintf($format, $env); + } elseif ($placeholder === $resolved = $bag->escapeValue($this->getEnv($env))) { + $resolved = $bag->all()[strtolower("env($env)")]; } $value = str_ireplace($placeholder, $resolved, $value); $usedEnvs[$env] = $env; diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php index d20e53531aa3..34f79477fa03 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php @@ -20,6 +20,7 @@ class EnvPlaceholderParameterBag extends ParameterBag { private $envPlaceholders = array(); + private $resolveEnvReferences = false; /** * {@inheritdoc} @@ -101,4 +102,29 @@ public function resolve() } } } + + /** + * Replaces "%env(FOO)%" references by their placeholder, keeping regular "%parameters%" references as is. + */ + public function resolveEnvReferences() + { + $this->resolveEnvReferences = true; + try { + $this->resolve(); + } finally { + $this->resolveEnvReferences = false; + } + } + + /** + * {@inheritdoc} + */ + public function resolveString($value, array $resolving = array()) + { + if ($this->resolveEnvReferences) { + return preg_replace_callback('/%%|%(env\([^%\s]+\))%/', function ($match) { return isset($match[1]) ? $this->get($match[1]) : '%%'; }, $value); + } + + return parent::resolveString($value, $resolving); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 51397309b7dc..7ab2e7c6f6c3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -603,29 +603,37 @@ public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitio public function testResolveEnvValues() { $_ENV['DUMMY_ENV_VAR'] = 'du%%y'; + $_SERVER['DUMMY_SERVER_VAR'] = 'ABC'; + $_SERVER['HTTP_DUMMY_VAR'] = 'DEF'; $container = new ContainerBuilder(); - $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)%'); + $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%'); + $container->setParameter('env(HTTP_DUMMY_VAR)', '123'); - $this->assertSame('%% du%%%%y', $container->resolveEnvPlaceholders('%bar%', true)); + $this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true)); - unset($_ENV['DUMMY_ENV_VAR']); + unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']); } public function testCompileWithResolveEnv() { - $_ENV['DUMMY_ENV_VAR'] = 'du%%y'; + putenv('DUMMY_ENV_VAR=du%%y'); + $_SERVER['DUMMY_SERVER_VAR'] = 'ABC'; + $_SERVER['HTTP_DUMMY_VAR'] = 'DEF'; $container = new ContainerBuilder(); $container->setParameter('env(FOO)', 'Foo'); - $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)%'); + $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%'); $container->setParameter('foo', '%env(FOO)%'); + $container->setParameter('baz', '%foo%'); + $container->setParameter('env(HTTP_DUMMY_VAR)', '123'); $container->compile(true); - $this->assertSame('% du%%y', $container->getParameter('bar')); - $this->assertSame('Foo', $container->getParameter('foo')); + $this->assertSame('% du%%y ABC 123', $container->getParameter('bar')); + $this->assertSame('Foo', $container->getParameter('baz')); - unset($_ENV['DUMMY_ENV_VAR']); + unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']); + putenv('DUMMY_ENV_VAR'); } /**