PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/patadejaguar/S.A.F.E.-Open-Source-Microfinance-Suite
PHP | 376 lines | 147 code | 40 blank | 189 comment | 19 complexity | dc1a793a4c234c9352d2e5987ce3ad1d MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-2.0, GPL-3.0, BSD-3-Clause
  1. <?php
  2. namespace Dotenv;
  3. use Dotenv\Exception\InvalidPathException;
  4. /**
  5. * This is the loaded class.
  6. *
  7. * It's responsible for loading variables by reading a file from disk and:
  8. * - stripping comments beginning with a `#`,
  9. * - parsing lines that look shell variable setters, e.g `export key = value`, `key="value"`.
  10. */
  11. class Loader
  12. {
  13. /**
  14. * The file path.
  15. *
  16. * @var string
  17. */
  18. protected $filePath;
  19. /**
  20. * Are we immutable?
  21. *
  22. * @var bool
  23. */
  24. protected $immutable;
  25. /**
  26. * The list of environment variables declared inside the 'env' file.
  27. *
  28. * @var array
  29. */
  30. public $variableNames = array();
  31. /**
  32. * Create a new loader instance.
  33. *
  34. * @param string $filePath
  35. * @param bool $immutable
  36. *
  37. * @return void
  38. */
  39. public function __construct($filePath, $immutable = false)
  40. {
  41. $this->filePath = $filePath;
  42. $this->immutable = $immutable;
  43. }
  44. /**
  45. * Set immutable value.
  46. *
  47. * @param bool $immutable
  48. * @return $this
  49. */
  50. public function setImmutable($immutable = false)
  51. {
  52. $this->immutable = $immutable;
  53. return $this;
  54. }
  55. /**
  56. * Get immutable value.
  57. *
  58. * @return bool
  59. */
  60. public function getImmutable()
  61. {
  62. return $this->immutable;
  63. }
  64. /**
  65. * Load `.env` file in given directory.
  66. *
  67. * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
  68. *
  69. * @return array
  70. */
  71. public function load()
  72. {
  73. $this->ensureFileIsReadable();
  74. $filePath = $this->filePath;
  75. $lines = $this->readLinesFromFile($filePath);
  76. foreach ($lines as $line) {
  77. if (!$this->isComment($line) && $this->looksLikeSetter($line)) {
  78. $this->setEnvironmentVariable($line);
  79. }
  80. }
  81. return $lines;
  82. }
  83. /**
  84. * Ensures the given filePath is readable.
  85. *
  86. * @throws \Dotenv\Exception\InvalidPathException
  87. *
  88. * @return void
  89. */
  90. protected function ensureFileIsReadable()
  91. {
  92. if (!is_readable($this->filePath) || !is_file($this->filePath)) {
  93. throw new InvalidPathException(sprintf('Unable to read the environment file at %s.', $this->filePath));
  94. }
  95. }
  96. /**
  97. * Normalise the given environment variable.
  98. *
  99. * Takes value as passed in by developer and:
  100. * - ensures we're dealing with a separate name and value, breaking apart the name string if needed,
  101. * - cleaning the value of quotes,
  102. * - cleaning the name of quotes,
  103. * - resolving nested variables.
  104. *
  105. * @param string $name
  106. * @param string $value
  107. *
  108. * @throws \Dotenv\Exception\InvalidFileException
  109. *
  110. * @return array
  111. */
  112. protected function normaliseEnvironmentVariable($name, $value)
  113. {
  114. list($name, $value) = $this->processFilters($name, $value);
  115. $value = $this->resolveNestedVariables($value);
  116. return array($name, $value);
  117. }
  118. /**
  119. * Process the runtime filters.
  120. *
  121. * Called from `normaliseEnvironmentVariable` and the `VariableFactory`, passed as a callback in `$this->loadFromFile()`.
  122. *
  123. * @param string $name
  124. * @param string $value
  125. *
  126. * @throws \Dotenv\Exception\InvalidFileException
  127. *
  128. * @return array
  129. */
  130. public function processFilters($name, $value)
  131. {
  132. list($name, $value) = $this->splitCompoundStringIntoParts($name, $value);
  133. list($name, $value) = $this->sanitiseVariableName($name, $value);
  134. list($name, $value) = $this->sanitiseVariableValue($name, $value);
  135. return array($name, $value);
  136. }
  137. /**
  138. * Read lines from the file, auto detecting line endings.
  139. *
  140. * @param string $filePath
  141. *
  142. * @return array
  143. */
  144. protected function readLinesFromFile($filePath)
  145. {
  146. // Read file into an array of lines with auto-detected line endings
  147. $autodetect = ini_get('auto_detect_line_endings');
  148. ini_set('auto_detect_line_endings', '1');
  149. $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
  150. ini_set('auto_detect_line_endings', $autodetect);
  151. return $lines;
  152. }
  153. /**
  154. * Determine if the line in the file is a comment, e.g. begins with a #.
  155. *
  156. * @param string $line
  157. *
  158. * @return bool
  159. */
  160. protected function isComment($line)
  161. {
  162. $line = ltrim($line);
  163. return isset($line[0]) && $line[0] === '#';
  164. }
  165. /**
  166. * Determine if the given line looks like it's setting a variable.
  167. *
  168. * @param string $line
  169. *
  170. * @return bool
  171. */
  172. protected function looksLikeSetter($line)
  173. {
  174. return strpos($line, '=') !== false;
  175. }
  176. /**
  177. * Split the compound string into parts.
  178. *
  179. * If the `$name` contains an `=` sign, then we split it into 2 parts, a `name` & `value`
  180. * disregarding the `$value` passed in.
  181. *
  182. * @param string $name
  183. * @param string $value
  184. *
  185. * @return array
  186. */
  187. protected function splitCompoundStringIntoParts($name, $value)
  188. {
  189. if (strpos($name, '=') !== false) {
  190. list($name, $value) = array_map('trim', explode('=', $name, 2));
  191. }
  192. return array($name, $value);
  193. }
  194. /**
  195. * Strips quotes from the environment variable value.
  196. *
  197. * @param string $name
  198. * @param string $value
  199. *
  200. * @throws \Dotenv\Exception\InvalidFileException
  201. *
  202. * @return array
  203. */
  204. protected function sanitiseVariableValue($name, $value)
  205. {
  206. $value = trim($value);
  207. if (!$value) {
  208. return array($name, $value);
  209. }
  210. return array($name, Parser::parseValue($value));
  211. }
  212. /**
  213. * Resolve the nested variables.
  214. *
  215. * Look for ${varname} patterns in the variable value and replace with an
  216. * existing environment variable.
  217. *
  218. * @param string $value
  219. *
  220. * @return mixed
  221. */
  222. protected function resolveNestedVariables($value)
  223. {
  224. if (strpos($value, '$') !== false) {
  225. $loader = $this;
  226. $value = preg_replace_callback(
  227. '/\${([a-zA-Z0-9_.]+)}/',
  228. function ($matchedPatterns) use ($loader) {
  229. $nestedVariable = $loader->getEnvironmentVariable($matchedPatterns[1]);
  230. if ($nestedVariable === null) {
  231. return $matchedPatterns[0];
  232. } else {
  233. return $nestedVariable;
  234. }
  235. },
  236. $value
  237. );
  238. }
  239. return $value;
  240. }
  241. /**
  242. * Strips quotes and the optional leading "export " from the environment variable name.
  243. *
  244. * @param string $name
  245. * @param string $value
  246. *
  247. * @return array
  248. */
  249. protected function sanitiseVariableName($name, $value)
  250. {
  251. return array(Parser::parseName($name), $value);
  252. }
  253. /**
  254. * Search the different places for environment variables and return first value found.
  255. *
  256. * @param string $name
  257. *
  258. * @return string|null
  259. */
  260. public function getEnvironmentVariable($name)
  261. {
  262. switch (true) {
  263. case array_key_exists($name, $_ENV):
  264. return $_ENV[$name];
  265. case array_key_exists($name, $_SERVER):
  266. return $_SERVER[$name];
  267. default:
  268. $value = getenv($name);
  269. return $value === false ? null : $value; // switch getenv default to null
  270. }
  271. }
  272. /**
  273. * Set an environment variable.
  274. *
  275. * This is done using:
  276. * - putenv,
  277. * - $_ENV,
  278. * - $_SERVER.
  279. *
  280. * The environment variable value is stripped of single and double quotes.
  281. *
  282. * @param string $name
  283. * @param string|null $value
  284. *
  285. * @throws \Dotenv\Exception\InvalidFileException
  286. *
  287. * @return void
  288. */
  289. public function setEnvironmentVariable($name, $value = null)
  290. {
  291. list($name, $value) = $this->normaliseEnvironmentVariable($name, $value);
  292. $this->variableNames[] = $name;
  293. // Don't overwrite existing environment variables if we're immutable
  294. // Ruby's dotenv does this with `ENV[key] ||= value`.
  295. if ($this->immutable && $this->getEnvironmentVariable($name) !== null) {
  296. return;
  297. }
  298. // If PHP is running as an Apache module and an existing
  299. // Apache environment variable exists, overwrite it
  300. if (function_exists('apache_getenv') && function_exists('apache_setenv') && apache_getenv($name) !== false) {
  301. apache_setenv($name, $value);
  302. }
  303. if (function_exists('putenv')) {
  304. putenv("$name=$value");
  305. }
  306. $_ENV[$name] = $value;
  307. $_SERVER[$name] = $value;
  308. }
  309. /**
  310. * Clear an environment variable.
  311. *
  312. * This is not (currently) used by Dotenv but is provided as a utility
  313. * method for 3rd party code.
  314. *
  315. * This is done using:
  316. * - putenv,
  317. * - unset($_ENV, $_SERVER).
  318. *
  319. * @param string $name
  320. *
  321. * @see setEnvironmentVariable()
  322. *
  323. * @return void
  324. */
  325. public function clearEnvironmentVariable($name)
  326. {
  327. // Don't clear anything if we're immutable.
  328. if ($this->immutable) {
  329. return;
  330. }
  331. if (function_exists('putenv')) {
  332. putenv($name);
  333. }
  334. unset($_ENV[$name], $_SERVER[$name]);
  335. }
  336. }