Skip to content

Commit

Permalink
v0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
prinx committed Jun 10, 2020
1 parent cbca59b commit 55c1f02
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 62 deletions.
54 changes: 31 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
- [Using the `env()` function](#using-the-env-function)
- [Details on setting environment variables](#details-on-setting-environment-variables)
- [Using the `addEnv()` function](#using-the-addenv-function)
- [The main package class](#the-main-package-class)
- [The main class instance](#the-main-class-instance)
- [Getting a variable](#getting-a-variable)
- [Getting all variables](#getting-all-variables)
- [Adding a variable](#adding-a-variable)
- [Persisting a variable (writing in the .env file)](#persisting-a-variable-writing-in-the-env-file)
# PHP Dotenv
Get easily access to your environment variables set in your .env file.

Expand All @@ -37,7 +39,7 @@ use function Prinx\Dotenv\addEnv;

/*
* 1. Retrieve an environment
* 1.1. Without a default value
* 1.1. Without a default value, will return false if variable not found
*/
$hostname = env('DEV_DB_HOST');

Expand All @@ -63,6 +65,13 @@ addEnv('LOG_LEVEL', 'info');
persistEnv('LOG_LEVEL', 'warn');
persistEnv('LOG_LEVEL', 'debug', false);
persistEnv('LOG_LEVEL', 'info');

/*
* 4. Get all variables from the .env file
*/
env()
// OR
allEnv();
```
Now let's see the format of a typical .env file.

Expand Down Expand Up @@ -200,10 +209,10 @@ $db_driver = env('DB.DRIVER');
$session_driver = env('SESSION.DRIVER');
```
### Referring to another variable
You can refer to the value of another variable in your .env file:
You can refer to the value of another variable in your .env file by putting the name of the variable you are referring to variable inside ${}:
```ini
SESSION_DRIVER=MySQL
INFO=App based on $SESSION_DRIVER database
INFO=App based on ${SESSION_DRIVER} database
```
```php
// PHP
Expand Down Expand Up @@ -239,7 +248,7 @@ You can pass a default value that will be return if the variable is not found in
$hostname = env('DEV_DB_HOST', 'localhost');
```

***Note**: If the variable is not defined in the .env file and no default value has been provided, an exception will be thrown.*
***Note**: If the variable is not defined in the .env file and no default value has been provided, the boolean value false will be returned.*

```php
// An exception will be thrown if DEV_DB_HOST does not exist in the .env
Expand Down Expand Up @@ -270,47 +279,46 @@ use function Prinx\Dotenv\addEnv;
addEnv('GUEST_NAME', 'john');
```

## The main package class
## The main class instance

You can also get or set a variable using the Dotenv class instance:

You access the main package class by calling the `env()` function without any parameter:
You access the main package class by calling the `dotenv()` function without any parameter:

```php
// Top of the file
// We no more need to use function Prinx\Dotenv\addEnv; to be able to set a variable
use function Prinx\Dotenv\env;
use function Prinx\Dotenv\dotenv;
```

### Getting a variable

Then you use its `get()` static method to have access to the variables.

```php
$hostname = env()::get('DEV_DB_HOST');
$hostname = dotenv()->get('DEV_DB_HOST');

// With a default value
$hostname = env()::get('DEV_DB_HOST', 'localhost');
$hostname = dotenv()->get('DEV_DB_HOST', 'localhost');
```

or maybe:

```php
$env = env();
$hostname = $env::get('DEV_DB_HOST', 'localhost');
$env = dotenv();
$hostname = $env->get('DEV_DB_HOST', 'localhost');
```
### Getting all variables
```php
$hostname = dotenv()->all();

### Adding a variable
// or use get without any parameter
$hostname = dotenv()->get();
```

Use the `add()` static method to add a variable.
### Adding a variable

```php
env()::add('GUEST_NAME', 'john');
dotenv()->add('GUEST_NAME', 'john');
```

or
### Persisting a variable (writing in the .env file)

```php
$env = env();
$env::add('GUEST_NAME', 'john');
dotenv()->persist('GUEST_NAME', 'john');
```
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "prinx/dotenv",
"type": "library",
"description": "Make easy access to the environment variables in your application",
"keywords": ["dotenv", "env"],
"keywords": ["phpdotenv", "dotenv", "env"],
"homepage": "https://github.com/Prinx/dotenv",
"license": "MIT",
"authors": [{
Expand All @@ -24,4 +24,4 @@
"Prinx\\Dotenv\\": "src/"
}
}
}
}
154 changes: 120 additions & 34 deletions src/Dotenv.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,70 +12,158 @@ class Dotenv
{
protected $env = [];
protected $path = '';
protected $pattern = '/^[^#;][a-zA-Z0-9_]+[ ]*=*[ ]*.*/';
protected $section_separator = '.';

public function __construct($path = '')
{
$path = $path ?: realpath(__DIR__ . '/../../../../.env');
$this->setPath($path);
$this->env = \parse_ini_file($this->path, true, INI_SCANNER_TYPED);

try {
$this->env = \parse_ini_file($this->path, true, INI_SCANNER_TYPED);
} catch (\Throwable $th) {
throw new \Exception('An error happened when parsing the .env file: ' . $th->getMessage());
}

$this->replaceReferences();
}

public function replaceReferences()
{
foreach ($this->env as $name => $value) {
$matches = [];
$pattern = '/\$[^$#;][a-zA-Z0-9_]+[ ]*/';
$env = file($this->path, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
$pattern = '/^([^#;][a-zA-Z0-9_]+)[ ]*=[ ]*(.*\$\{([a-zA-Z0-9_]+)\}.*)/';

if (preg_match($pattern, $value, $matches)) {
foreach ($matches as $match) {
if (strpos($match, '$$') === 0) {
continue;
}
foreach ($env as $line) {
if (preg_match($pattern, $line, $matches)) {
$ref = $matches[3];

if (!$this->envVariableExists($match)) {
throw new \Exception('Error in the .env file (' . $this->file . ")\n$" . $match . ' does not refer to any value');
}
if (!$this->envVariableExists($ref)) {
return null;
}

$match = \substr($match, 1, strlen($match) - 1);
$ref_value = $this->env[$ref];
$line_value = $matches[2];

$value = preg_replace($pattern, $this->env[$match], $value);
$this->env[$name] = $value;
}
$line_value_formatted = preg_replace('/\$\{[a-zA-Z0-9_]+\}/', $ref_value, $line_value);

$line_value_formatted = $this->properValueOfRef($ref_value, $line_value_formatted);

$this->env[$matches[1]] = $line_value_formatted;
}
}
}

public function get($name, $default = null)
public function properValueOfRef($ref_value, $line_value)
{
$name_exploded = explode('.', $name);
$lookup = $this->env;
$value = null;
if ($this->valueSameAsReference($ref_value, $line_value)) {
settype($line_value, gettype($ref_value));
}

foreach ($name_exploded as $variable_name) {
$name_exists_in_env = isset($lookup[$name]);
return $line_value;
}

if (!$name_exists_in_env && \func_num_args() < 2) {
throw new \Exception('Variable "' . $name . '" not defined in the .env file. You can either add the variable to the .env file or pass a second value to the function that will be return if the variable is not define in the .env file.');
public function valueSameAsReference($ref_value, $line_value)
{
$ref_value_string = '';
$ref_value_type = gettype($ref_value);

if ($this->isStringifiable($ref_value)) {
$ref_value_string = strval($line_value);
}

return $ref_value_string === $line_value;
}

// Thanks to https://stackoverflow.com/a/5496674
public function isStringifiable($var)
{
return (
!is_array($var) &&
((!is_object($var) && settype($var, 'string') !== false) ||
(is_object($var) && method_exists($var, '__toString')))
);
}

public function all()
{
return $this->env;
}

public function get($name = null, $default = null)
{
if (\func_num_args() === 0) {
return $this->all();
}

if (isset($this->env[$name])) {
return $this->env[$name];
} elseif ($value = getenv($name)) {
return $value;
}

$name_exploded = explode($this->section_separator, $name);
$lookup = $this->env;
$value = false;

$last_index = count($name_exploded) - 1;
foreach ($name_exploded as $key => $variable_name) {
if (!$variable_name) {
return false;
}

$value = $lookup[$name];
$lookup = $lookup[$name];
if (isset($lookup[$variable_name])) {
if (!is_array($value) && $key < $last_index) {
return false;
}

$lookup = $value;
} else {
return \func_num_args() < 2 ? getenv($variable_name) : $default;
}
}

return $name_exists_in_env ? $value : $default;
return $value;
}

/**
* Section not yet support
*/
public function add($name, $value, $section = '')
public function add($name, $value)
{
$this->env[$name] = $value;
$name_exploded = explode($this->section_separator, $name);

$namespace_count = count($name_exploded);

if ($namespace_count === 1) {
return $this->env[$name] = $value;
}

$this->env[$name_exploded[0]] = $this->nextArrayValue(
$value,
$name_exploded,
1,
$namespace_count - 1
);
}

public function nextArrayValue(
$value_to_insert,
$name_indexes,
$current_index,
$last_index
) {
return $current_index === $last_index ?
$value_to_insert :
[
$name_indexes[$current_index] =>
$this->nextArrayValue(
$value_to_insert,
$name_indexes,
$current_index + 1,
$last_index
),
];
}
/**
* Write a new environment variable to the .env file
*
Expand All @@ -98,10 +186,10 @@ public function persist($name, $value, $overwrite = true)

public function envVariableExists($name)
{
return isset($this->data[$name]);
return isset($this->env[$name]);
}

// https://stackoverflow.com/questions/9721952/search-string-and-return-line-php
// Thanks to https://stackoverflow.com/questions/9721952/search-string-and-return-line-php
public function getLineWithString($fileName, $str)
{
$lines = file($fileName);
Expand All @@ -113,8 +201,6 @@ public function getLineWithString($fileName, $str)
return -1;
}

// https://stackoverflow.com/questions/3004041/how-to-replace-a-particular-line-in-a-text-file-using-php

public function addIfNotExists($name, $value, $section = '')
{
if (!isset($this->env[$name])) {
Expand Down
25 changes: 22 additions & 3 deletions src/aliases_functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function env($name = null, $default = null)

switch (\func_num_args()) {
case 0:
return $env;
return \call_user_func([$env, 'all']);
case 1:
return \call_user_func([$env, 'get'], $name);

Expand All @@ -20,9 +20,28 @@ function env($name = null, $default = null)
}
}

function addEnv($name, $value, $section = '')
function addEnv($name, $value)
{
$env = DotenvInstance::get();

\call_user_func([$env, 'set'], $name, $value, $section);
\call_user_func([$env, 'add'], $name, $value);
}

function persistEnv($name, $value)
{
$env = DotenvInstance::get();

\call_user_func([$env, 'persist'], $name, $value);
}

function allEnv()
{
$env = DotenvInstance::get();

\call_user_func([$env, 'all']);
}

function dotenv()
{
return DotenvInstance::get();
}

0 comments on commit 55c1f02

Please sign in to comment.