/vendor/vlucas/phpdotenv/src/Loader.php

https://gitlab.com/madwanz64/laravel · PHP · 255 lines · 103 code · 24 blank · 128 comment · 2 complexity · 2e67d63f8784c4ccb285111974184e39 MD5 · raw file

  1. <?php
  2. namespace Dotenv;
  3. use Dotenv\Environment\FactoryInterface;
  4. use Dotenv\Exception\InvalidPathException;
  5. use Dotenv\Regex\Regex;
  6. use PhpOption\Option;
  7. /**
  8. * This is the loader class.
  9. *
  10. * It's responsible for loading variables by reading a file from disk and:
  11. * - stripping comments beginning with a `#`,
  12. * - parsing lines that look shell variable setters, e.g `export key = value`, `key="value"`.
  13. * - multiline variable look always start with a " and end with it, e.g: `key="value
  14. * value"`
  15. */
  16. class Loader
  17. {
  18. /**
  19. * The file paths.
  20. *
  21. * @var string[]
  22. */
  23. protected $filePaths;
  24. /**
  25. * The environment factory instance.
  26. *
  27. * @var \Dotenv\Environment\FactoryInterface
  28. */
  29. protected $envFactory;
  30. /**
  31. * The environment variables instance.
  32. *
  33. * @var \Dotenv\Environment\VariablesInterface
  34. */
  35. protected $envVariables;
  36. /**
  37. * The list of environment variables declared inside the 'env' file.
  38. *
  39. * @var string[]
  40. */
  41. protected $variableNames = [];
  42. /**
  43. * Create a new loader instance.
  44. *
  45. * @param string[] $filePaths
  46. * @param \Dotenv\Environment\FactoryInterface $envFactory
  47. * @param bool $immutable
  48. *
  49. * @return void
  50. */
  51. public function __construct(array $filePaths, FactoryInterface $envFactory, $immutable = false)
  52. {
  53. $this->filePaths = $filePaths;
  54. $this->envFactory = $envFactory;
  55. $this->setImmutable($immutable);
  56. }
  57. /**
  58. * Set immutable value.
  59. *
  60. * @param bool $immutable
  61. *
  62. * @return $this
  63. */
  64. public function setImmutable($immutable = false)
  65. {
  66. $this->envVariables = $immutable
  67. ? $this->envFactory->createImmutable()
  68. : $this->envFactory->create();
  69. return $this;
  70. }
  71. /**
  72. * Load the environment file from disk.
  73. *
  74. * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
  75. *
  76. * @return array<string|null>
  77. */
  78. public function load()
  79. {
  80. return $this->loadDirect(
  81. self::findAndRead($this->filePaths)
  82. );
  83. }
  84. /**
  85. * Directly load the given string.
  86. *
  87. * @param string $content
  88. *
  89. * @throws \Dotenv\Exception\InvalidFileException
  90. *
  91. * @return array<string|null>
  92. */
  93. public function loadDirect($content)
  94. {
  95. return $this->processEntries(
  96. Lines::process(preg_split("/(\r\n|\n|\r)/", $content))
  97. );
  98. }
  99. /**
  100. * Attempt to read the files in order.
  101. *
  102. * @param string[] $filePaths
  103. *
  104. * @throws \Dotenv\Exception\InvalidPathException
  105. *
  106. * @return string[]
  107. */
  108. private static function findAndRead(array $filePaths)
  109. {
  110. if ($filePaths === []) {
  111. throw new InvalidPathException('At least one environment file path must be provided.');
  112. }
  113. foreach ($filePaths as $filePath) {
  114. $lines = self::readFromFile($filePath);
  115. if ($lines->isDefined()) {
  116. return $lines->get();
  117. }
  118. }
  119. throw new InvalidPathException(
  120. sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $filePaths))
  121. );
  122. }
  123. /**
  124. * Read the given file.
  125. *
  126. * @param string $filePath
  127. *
  128. * @return \PhpOption\Option
  129. */
  130. private static function readFromFile($filePath)
  131. {
  132. $content = @file_get_contents($filePath);
  133. return Option::fromValue($content, false);
  134. }
  135. /**
  136. * Process the environment variable entries.
  137. *
  138. * We'll fill out any nested variables, and acually set the variable using
  139. * the underlying environment variables instance.
  140. *
  141. * @param string[] $entries
  142. *
  143. * @throws \Dotenv\Exception\InvalidFileException
  144. *
  145. * @return array<string|null>
  146. */
  147. private function processEntries(array $entries)
  148. {
  149. $vars = [];
  150. foreach ($entries as $entry) {
  151. list($name, $value) = Parser::parse($entry);
  152. $vars[$name] = $this->resolveNestedVariables($value);
  153. $this->setEnvironmentVariable($name, $vars[$name]);
  154. }
  155. return $vars;
  156. }
  157. /**
  158. * Resolve the nested variables.
  159. *
  160. * Look for ${varname} patterns in the variable value and replace with an
  161. * existing environment variable.
  162. *
  163. * @param string|null $value
  164. *
  165. * @return string|null
  166. */
  167. private function resolveNestedVariables($value = null)
  168. {
  169. return Option::fromValue($value)
  170. ->filter(function ($str) {
  171. return strpos($str, '$') !== false;
  172. })
  173. ->flatMap(function ($str) {
  174. return Regex::replaceCallback(
  175. '/\${([a-zA-Z0-9_.]+)}/',
  176. function (array $matches) {
  177. return Option::fromValue($this->getEnvironmentVariable($matches[1]))
  178. ->getOrElse($matches[0]);
  179. },
  180. $str
  181. )->success();
  182. })
  183. ->getOrElse($value);
  184. }
  185. /**
  186. * Search the different places for environment variables and return first value found.
  187. *
  188. * @param string $name
  189. *
  190. * @return string|null
  191. */
  192. public function getEnvironmentVariable($name)
  193. {
  194. return $this->envVariables->get($name);
  195. }
  196. /**
  197. * Set an environment variable.
  198. *
  199. * @param string $name
  200. * @param string|null $value
  201. *
  202. * @return void
  203. */
  204. public function setEnvironmentVariable($name, $value = null)
  205. {
  206. $this->variableNames[] = $name;
  207. $this->envVariables->set($name, $value);
  208. }
  209. /**
  210. * Clear an environment variable.
  211. *
  212. * This method only expects names in normal form.
  213. *
  214. * @param string $name
  215. *
  216. * @return void
  217. */
  218. public function clearEnvironmentVariable($name)
  219. {
  220. $this->envVariables->clear($name);
  221. }
  222. /**
  223. * Get the list of environment variables names.
  224. *
  225. * @return string[]
  226. */
  227. public function getEnvironmentVariableNames()
  228. {
  229. return $this->variableNames;
  230. }
  231. }