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

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.             'const' => 'bool|int|float|string|array',
  39.             'csv' => 'array',
  40.             'file' => 'string',
  41.             'float' => 'float',
  42.             'int' => 'int',
  43.             'json' => 'array',
  44.             'key' => 'bool|int|float|string|array',
  45.             'url' => 'array',
  46.             'query_string' => 'array',
  47.             'resolve' => 'string',
  48.             'default' => 'bool|int|float|string|array',
  49.             'string' => 'string',
  50.             'trim' => 'string',
  51.             'require' => 'bool|int|float|string|array',
  52.         ];
  53.     }
  54.     /**
  55.      * {@inheritdoc}
  56.      */
  57.     public function getEnv($prefix$name, \Closure $getEnv)
  58.     {
  59.         $i strpos($name':');
  60.         if ('key' === $prefix) {
  61.             if (false === $i) {
  62.                 throw new RuntimeException(sprintf('Invalid env "key:%s": a key specifier should be provided.'$name));
  63.             }
  64.             $next substr($name$i 1);
  65.             $key substr($name0$i);
  66.             $array $getEnv($next);
  67.             if (!\is_array($array)) {
  68.                 throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.'$next));
  69.             }
  70.             if (!isset($array[$key]) && !\array_key_exists($key$array)) {
  71.                 throw new EnvNotFoundException(sprintf('Key "%s" not found in "%s" (resolved from "%s").'$keyjson_encode($array), $next));
  72.             }
  73.             return $array[$key];
  74.         }
  75.         if ('default' === $prefix) {
  76.             if (false === $i) {
  77.                 throw new RuntimeException(sprintf('Invalid env "default:%s": a fallback parameter should be provided.'$name));
  78.             }
  79.             $next substr($name$i 1);
  80.             $default substr($name0$i);
  81.             if ('' !== $default && !$this->container->hasParameter($default)) {
  82.                 throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.'$name$default));
  83.             }
  84.             try {
  85.                 $env $getEnv($next);
  86.                 if ('' !== $env && null !== $env) {
  87.                     return $env;
  88.                 }
  89.             } catch (EnvNotFoundException $e) {
  90.                 // no-op
  91.             }
  92.             return '' === $default null $this->container->getParameter($default);
  93.         }
  94.         if ('file' === $prefix || 'require' === $prefix) {
  95.             if (!is_scalar($file $getEnv($name))) {
  96.                 throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.'$name));
  97.             }
  98.             if (!file_exists($file)) {
  99.                 throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").'$file$name));
  100.             }
  101.             if ('file' === $prefix) {
  102.                 return file_get_contents($file);
  103.             } else {
  104.                 return require $file;
  105.             }
  106.         }
  107.         if (false !== $i || 'string' !== $prefix) {
  108.             $env $getEnv($name);
  109.         } elseif (isset($_ENV[$name])) {
  110.             $env $_ENV[$name];
  111.         } elseif (isset($_SERVER[$name]) && !== strpos($name'HTTP_')) {
  112.             $env $_SERVER[$name];
  113.         } elseif (false === ($env getenv($name)) || null === $env) { // null is a possible value because of thread safety issues
  114.             foreach ($this->loadedVars as $vars) {
  115.                 if (false !== $env = ($vars[$name] ?? false)) {
  116.                     break;
  117.                 }
  118.             }
  119.             if (false === $env || null === $env) {
  120.                 $loaders $this->loaders;
  121.                 $this->loaders = new \ArrayIterator();
  122.                 try {
  123.                     $i 0;
  124.                     $ended true;
  125.                     $count $loaders instanceof \Countable $loaders->count() : 0;
  126.                     foreach ($loaders as $loader) {
  127.                         if (\count($this->loadedVars) > $i++) {
  128.                             continue;
  129.                         }
  130.                         $this->loadedVars[] = $vars $loader->loadEnvVars();
  131.                         if (false !== $env $vars[$name] ?? false) {
  132.                             $ended false;
  133.                             break;
  134.                         }
  135.                     }
  136.                     if ($ended || $count === $i) {
  137.                         $loaders $this->loaders;
  138.                     }
  139.                 } catch (ParameterCircularReferenceException $e) {
  140.                     // skip loaders that need an env var that is not defined
  141.                 } finally {
  142.                     $this->loaders $loaders;
  143.                 }
  144.             }
  145.             if (false === $env || null === $env) {
  146.                 if (!$this->container->hasParameter("env($name)")) {
  147.                     throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".'$name));
  148.                 }
  149.                 $env $this->container->getParameter("env($name)");
  150.             }
  151.         }
  152.         if (null === $env) {
  153.             if (!isset($this->getProvidedTypes()[$prefix])) {
  154.                 throw new RuntimeException(sprintf('Unsupported env var prefix "%s".'$prefix));
  155.             }
  156.             return null;
  157.         }
  158.         if (!is_scalar($env)) {
  159.             throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to "%s".'$name$prefix));
  160.         }
  161.         if ('string' === $prefix) {
  162.             return (string) $env;
  163.         }
  164.         if ('bool' === $prefix) {
  165.             return (bool) (filter_var($env, \FILTER_VALIDATE_BOOLEAN) ?: filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT));
  166.         }
  167.         if ('int' === $prefix) {
  168.             if (false === $env filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT)) {
  169.                 throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to int.'$name));
  170.             }
  171.             return (int) $env;
  172.         }
  173.         if ('float' === $prefix) {
  174.             if (false === $env filter_var($env, \FILTER_VALIDATE_FLOAT)) {
  175.                 throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to float.'$name));
  176.             }
  177.             return (float) $env;
  178.         }
  179.         if ('const' === $prefix) {
  180.             if (!\defined($env)) {
  181.                 throw new RuntimeException(sprintf('Env var "%s" maps to undefined constant "%s".'$name$env));
  182.             }
  183.             return \constant($env);
  184.         }
  185.         if ('base64' === $prefix) {
  186.             return base64_decode(strtr($env'-_''+/'));
  187.         }
  188.         if ('json' === $prefix) {
  189.             $env json_decode($envtrue);
  190.             if (\JSON_ERROR_NONE !== json_last_error()) {
  191.                 throw new RuntimeException(sprintf('Invalid JSON in env var "%s": '$name).json_last_error_msg());
  192.             }
  193.             if (null !== $env && !\is_array($env)) {
  194.                 throw new RuntimeException(sprintf('Invalid JSON env var "%s": array or null expected, "%s" given.'$name, \gettype($env)));
  195.             }
  196.             return $env;
  197.         }
  198.         if ('url' === $prefix) {
  199.             $parsedEnv parse_url($env);
  200.             if (false === $parsedEnv) {
  201.                 throw new RuntimeException(sprintf('Invalid URL in env var "%s".'$name));
  202.             }
  203.             if (!isset($parsedEnv['scheme'], $parsedEnv['host'])) {
  204.                 throw new RuntimeException(sprintf('Invalid URL env var "%s": schema and host expected, "%s" given.'$name$env));
  205.             }
  206.             $parsedEnv += [
  207.                 'port' => null,
  208.                 'user' => null,
  209.                 'pass' => null,
  210.                 'path' => null,
  211.                 'query' => null,
  212.                 'fragment' => null,
  213.             ];
  214.             if (null !== $parsedEnv['path']) {
  215.                 // remove the '/' separator
  216.                 $parsedEnv['path'] = '/' === $parsedEnv['path'] ? null substr($parsedEnv['path'], 1);
  217.             }
  218.             return $parsedEnv;
  219.         }
  220.         if ('query_string' === $prefix) {
  221.             $queryString parse_url($env, \PHP_URL_QUERY) ?: $env;
  222.             parse_str($queryString$result);
  223.             return $result;
  224.         }
  225.         if ('resolve' === $prefix) {
  226.             return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name) {
  227.                 if (!isset($match[1])) {
  228.                     return '%';
  229.                 }
  230.                 $value $this->container->getParameter($match[1]);
  231.                 if (!is_scalar($value)) {
  232.                     throw new RuntimeException(sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.'$match[1], $name, \gettype($value)));
  233.                 }
  234.                 return $value;
  235.             }, $env);
  236.         }
  237.         if ('csv' === $prefix) {
  238.             return str_getcsv($env',''"', \PHP_VERSION_ID >= 70400 '' '\\');
  239.         }
  240.         if ('trim' === $prefix) {
  241.             return trim($env);
  242.         }
  243.         throw new RuntimeException(sprintf('Unsupported env var prefix "%s".'$prefix));
  244.     }
  245. }