vendor/symfony/dependency-injection/EnvVarProcessor.php line 136

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
  12. use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
  13. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  14. /**
  15.  * @author Nicolas Grekas <p@tchwork.com>
  16.  */
  17. class EnvVarProcessor implements EnvVarProcessorInterface
  18. {
  19.     private $container;
  20.     private $loaders;
  21.     private $loadedVars = [];
  22.     /**
  23.      * @param EnvVarLoaderInterface[] $loaders
  24.      */
  25.     public function __construct(ContainerInterface $container, \Traversable $loaders null)
  26.     {
  27.         $this->container $container;
  28.         $this->loaders $loaders ?? new \ArrayIterator();
  29.     }
  30.     /**
  31.      * {@inheritdoc}
  32.      */
  33.     public static function getProvidedTypes()
  34.     {
  35.         return [
  36.             'base64' => 'string',
  37.             'bool' => 'bool',
  38.             'not' => 'bool',
  39.             'const' => 'bool|int|float|string|array',
  40.             'csv' => 'array',
  41.             'file' => 'string',
  42.             'float' => 'float',
  43.             'int' => 'int',
  44.             'json' => 'array',
  45.             'key' => 'bool|int|float|string|array',
  46.             'url' => 'array',
  47.             'query_string' => 'array',
  48.             'resolve' => 'string',
  49.             'default' => 'bool|int|float|string|array',
  50.             'string' => 'string',
  51.             'trim' => 'string',
  52.             'require' => 'bool|int|float|string|array',
  53.         ];
  54.     }
  55.     /**
  56.      * {@inheritdoc}
  57.      */
  58.     public function getEnv(string $prefixstring $name, \Closure $getEnv)
  59.     {
  60.         $i strpos($name':');
  61.         if ('key' === $prefix) {
  62.             if (false === $i) {
  63.                 throw new RuntimeException(sprintf('Invalid env "key:%s": a key specifier should be provided.'$name));
  64.             }
  65.             $next substr($name$i 1);
  66.             $key substr($name0$i);
  67.             $array $getEnv($next);
  68.             if (!\is_array($array)) {
  69.                 throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.'$next));
  70.             }
  71.             if (!isset($array[$key]) && !\array_key_exists($key$array)) {
  72.                 throw new EnvNotFoundException(sprintf('Key "%s" not found in %s (resolved from "%s").'$keyjson_encode($array), $next));
  73.             }
  74.             return $array[$key];
  75.         }
  76.         if ('default' === $prefix) {
  77.             if (false === $i) {
  78.                 throw new RuntimeException(sprintf('Invalid env "default:%s": a fallback parameter should be provided.'$name));
  79.             }
  80.             $next substr($name$i 1);
  81.             $default substr($name0$i);
  82.             if ('' !== $default && !$this->container->hasParameter($default)) {
  83.                 throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.'$name$default));
  84.             }
  85.             try {
  86.                 $env $getEnv($next);
  87.                 if ('' !== $env && null !== $env) {
  88.                     return $env;
  89.                 }
  90.             } catch (EnvNotFoundException $e) {
  91.                 // no-op
  92.             }
  93.             return '' === $default null $this->container->getParameter($default);
  94.         }
  95.         if ('file' === $prefix || 'require' === $prefix) {
  96.             if (!\is_scalar($file $getEnv($name))) {
  97.                 throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.'$name));
  98.             }
  99.             if (!is_file($file)) {
  100.                 throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").'$file$name));
  101.             }
  102.             if ('file' === $prefix) {
  103.                 return file_get_contents($file);
  104.             } else {
  105.                 return require $file;
  106.             }
  107.         }
  108.         $returnNull false;
  109.         if ('' === $prefix) {
  110.             $returnNull true;
  111.             $prefix 'string';
  112.         }
  113.         if (false !== $i || 'string' !== $prefix) {
  114.             $env $getEnv($name);
  115.         } elseif (isset($_ENV[$name])) {
  116.             $env $_ENV[$name];
  117.         } elseif (isset($_SERVER[$name]) && !str_starts_with($name'HTTP_')) {
  118.             $env $_SERVER[$name];
  119.         } elseif (false === ($env getenv($name)) || null === $env) { // null is a possible value because of thread safety issues
  120.             foreach ($this->loadedVars as $vars) {
  121.                 if (false !== $env = ($vars[$name] ?? false)) {
  122.                     break;
  123.                 }
  124.             }
  125.             if (false === $env || null === $env) {
  126.                 $loaders $this->loaders;
  127.                 $this->loaders = new \ArrayIterator();
  128.                 try {
  129.                     $i 0;
  130.                     $ended true;
  131.                     $count $loaders instanceof \Countable $loaders->count() : 0;
  132.                     foreach ($loaders as $loader) {
  133.                         if (\count($this->loadedVars) > $i++) {
  134.                             continue;
  135.                         }
  136.                         $this->loadedVars[] = $vars $loader->loadEnvVars();
  137.                         if (false !== $env $vars[$name] ?? false) {
  138.                             $ended false;
  139.                             break;
  140.                         }
  141.                     }
  142.                     if ($ended || $count === $i) {
  143.                         $loaders $this->loaders;
  144.                     }
  145.                 } catch (ParameterCircularReferenceException $e) {
  146.                     // skip loaders that need an env var that is not defined
  147.                 } finally {
  148.                     $this->loaders $loaders;
  149.                 }
  150.             }
  151.             if (false === $env || null === $env) {
  152.                 if (!$this->container->hasParameter("env($name)")) {
  153.                     throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".'$name));
  154.                 }
  155.                 $env $this->container->getParameter("env($name)");
  156.             }
  157.         }
  158.         if (null === $env) {
  159.             if ($returnNull) {
  160.                 return null;
  161.             }
  162.             if (!isset($this->getProvidedTypes()[$prefix])) {
  163.                 throw new RuntimeException(sprintf('Unsupported env var prefix "%s".'$prefix));
  164.             }
  165.             if (!\in_array($prefix, ['string''bool''not''int''float'], true)) {
  166.                 return null;
  167.             }
  168.         }
  169.         if (null !== $env && !\is_scalar($env)) {
  170.             throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to "%s".'$name$prefix));
  171.         }
  172.         if ('string' === $prefix) {
  173.             return (string) $env;
  174.         }
  175.         if (\in_array($prefix, ['bool''not'], true)) {
  176.             $env = (bool) (filter_var($env, \FILTER_VALIDATE_BOOLEAN) ?: filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT));
  177.             return 'not' === $prefix ? !$env $env;
  178.         }
  179.         if ('int' === $prefix) {
  180.             if (null !== $env && false === $env filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT)) {
  181.                 throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to int.'$name));
  182.             }
  183.             return (int) $env;
  184.         }
  185.         if ('float' === $prefix) {
  186.             if (null !== $env && false === $env filter_var($env, \FILTER_VALIDATE_FLOAT)) {
  187.                 throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to float.'$name));
  188.             }
  189.             return (float) $env;
  190.         }
  191.         if ('const' === $prefix) {
  192.             if (!\defined($env)) {
  193.                 throw new RuntimeException(sprintf('Env var "%s" maps to undefined constant "%s".'$name$env));
  194.             }
  195.             return \constant($env);
  196.         }
  197.         if ('base64' === $prefix) {
  198.             return base64_decode(strtr($env'-_''+/'));
  199.         }
  200.         if ('json' === $prefix) {
  201.             $env json_decode($envtrue);
  202.             if (\JSON_ERROR_NONE !== json_last_error()) {
  203.                 throw new RuntimeException(sprintf('Invalid JSON in env var "%s": '$name).json_last_error_msg());
  204.             }
  205.             if (null !== $env && !\is_array($env)) {
  206.                 throw new RuntimeException(sprintf('Invalid JSON env var "%s": array or null expected, "%s" given.'$nameget_debug_type($env)));
  207.             }
  208.             return $env;
  209.         }
  210.         if ('url' === $prefix) {
  211.             $parsedEnv parse_url($env);
  212.             if (false === $parsedEnv) {
  213.                 throw new RuntimeException(sprintf('Invalid URL in env var "%s".'$name));
  214.             }
  215.             if (!isset($parsedEnv['scheme'], $parsedEnv['host'])) {
  216.                 throw new RuntimeException(sprintf('Invalid URL env var "%s": schema and host expected, "%s" given.'$name$env));
  217.             }
  218.             $parsedEnv += [
  219.                 'port' => null,
  220.                 'user' => null,
  221.                 'pass' => null,
  222.                 'path' => null,
  223.                 'query' => null,
  224.                 'fragment' => null,
  225.             ];
  226.             // remove the '/' separator
  227.             $parsedEnv['path'] = '/' === ($parsedEnv['path'] ?? '/') ? '' substr($parsedEnv['path'], 1);
  228.             return $parsedEnv;
  229.         }
  230.         if ('query_string' === $prefix) {
  231.             $queryString parse_url($env, \PHP_URL_QUERY) ?: $env;
  232.             parse_str($queryString$result);
  233.             return $result;
  234.         }
  235.         if ('resolve' === $prefix) {
  236.             return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name$getEnv) {
  237.                 if (!isset($match[1])) {
  238.                     return '%';
  239.                 }
  240.                 if (str_starts_with($match[1], 'env(') && str_ends_with($match[1], ')') && 'env()' !== $match[1]) {
  241.                     $value $getEnv(substr($match[1], 4, -1));
  242.                 } else {
  243.                     $value $this->container->getParameter($match[1]);
  244.                 }
  245.                 if (!\is_scalar($value)) {
  246.                     throw new RuntimeException(sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.'$match[1], $nameget_debug_type($value)));
  247.                 }
  248.                 return $value;
  249.             }, $env);
  250.         }
  251.         if ('csv' === $prefix) {
  252.             return str_getcsv($env',''"', \PHP_VERSION_ID >= 70400 '' '\\');
  253.         }
  254.         if ('trim' === $prefix) {
  255.             return trim($env);
  256.         }
  257.         throw new RuntimeException(sprintf('Unsupported env var prefix "%s" for env name "%s".'$prefix$name));
  258.     }
  259. }