Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a7ade86485 | |||
| b9feacaded | |||
| 646456b86b | |||
| 4b0550b8d2 | |||
| efb99f259e | |||
| 72f4827985 | |||
| d5bf24c8cf | |||
| 773f40e2d1 | |||
| 0bb137dff6 | |||
| 7e1a19b86b | |||
| 2524092cd8 | |||
| f692ca41b1 | |||
| b9620704bc | |||
| 5004e3c9d8 | |||
| e86528a366 | |||
| e99a995a2e | |||
| e29f9fcd88 | |||
| ae0eb1f939 | |||
| c608201de1 | |||
| 8e062ff114 | |||
| 225e3e7929 | |||
| 44bcb39e51 | |||
| 5729a0c977 | |||
| 9af7790b61 | |||
| 0579a075dc | |||
| 58a6d994ca | |||
| 233f9fbf81 | |||
| 8ae06efe4e | |||
| 4079d7c66e | |||
| dd2274f3b1 | |||
| 5742314581 |
35
.github/workflows/ci.yml
vendored
Normal file
35
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: CI
|
||||||
|
run-name: ${{ github.actor}} runs CI
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: php-actions/composer@v6
|
||||||
|
env:
|
||||||
|
COMPOSER_ROOT_VERSION: dev-master
|
||||||
|
- name: "Restore result cache"
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
with:
|
||||||
|
path: ./tmp
|
||||||
|
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||||
|
restore-keys: |
|
||||||
|
result-cache-v1-${{ matrix.php-version }}-
|
||||||
|
- name: PHPStan Static Analysis
|
||||||
|
uses: php-actions/phpstan@v3
|
||||||
|
with:
|
||||||
|
path: src/
|
||||||
|
configuration: phpstan.neon
|
||||||
|
- name: "Save result cache"
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
path: ./tmp
|
||||||
|
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||||
|
# We need to use phpunit from the self install to get the class paths
|
||||||
|
- name: PHPunit Tests
|
||||||
|
run: |
|
||||||
|
vendor/bin/phpunit
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
vendor
|
vendor
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
.phplint-cache
|
||||||
composer.lock
|
composer.lock
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ return [
|
|||||||
// to parse, but not analyze
|
// to parse, but not analyze
|
||||||
"exclude_analysis_directory_list" => [
|
"exclude_analysis_directory_list" => [
|
||||||
'vendor',
|
'vendor',
|
||||||
'test'
|
'test',
|
||||||
|
'tmp'
|
||||||
],
|
],
|
||||||
'exclude_file_list' => [
|
'exclude_file_list' => [
|
||||||
],
|
],
|
||||||
|
|||||||
39
Readme.md
39
Readme.md
@@ -60,3 +60,42 @@ ESCAPE="String \" inside \" other "
|
|||||||
DOUBLE="I will be used"
|
DOUBLE="I will be used"
|
||||||
DOUBLE="This will be ignored"
|
DOUBLE="This will be ignored"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A prefix name can be set with `[PrefixName]`. Tne name rules are like for variables, but spaces
|
||||||
|
are allowed, but will be converted to "_".
|
||||||
|
The prefix is valid from the time set until the next prefix block appears or the file ends.
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
```ini
|
||||||
|
FOO="bar"
|
||||||
|
FOOBAR="bar bar"
|
||||||
|
[SecitonA]
|
||||||
|
FOO="other bar"
|
||||||
|
FOOBAR="other bar bar"
|
||||||
|
```
|
||||||
|
|
||||||
|
Will have environmen variables as
|
||||||
|
|
||||||
|
```php
|
||||||
|
$_ENV["FOO"];
|
||||||
|
$_ENV["FOOBAR"];
|
||||||
|
$_ENV["SecitonA.FOO"];
|
||||||
|
$_ENV["SecitonA.FOOBAR"];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Phan
|
||||||
|
|
||||||
|
`vendor/bin/phan --analyze-twice`
|
||||||
|
|
||||||
|
### PHPstan
|
||||||
|
|
||||||
|
`vendor/bin/phpstan`
|
||||||
|
|
||||||
|
### PHPUnit
|
||||||
|
|
||||||
|
Unit tests have to be run from base folder with
|
||||||
|
|
||||||
|
`vendor/bin/phpunit test/phpUnitTests/`
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"gullevek\\dotEnv\\": "src/"
|
"gullevek\\dotEnv\\": "src/",
|
||||||
|
"gullevek\\dotenv\\": "src/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -25,6 +26,10 @@
|
|||||||
"exclude": ["/test/", "/test/*", "/phpstan.neon", "/psalm.xml", "/.phan/", "/.vscode/", "/phpunit.xml"]
|
"exclude": ["/test/", "/test/*", "/phpstan.neon", "/psalm.xml", "/.phan/", "/.vscode/", "/phpunit.xml"]
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9"
|
"phpunit/phpunit": "^9",
|
||||||
|
"phan/phan": "^5.4",
|
||||||
|
"phpstan/phpstan": "^2.0",
|
||||||
|
"phpstan/phpdoc-parser": "^2.0",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# PHP Stan Config
|
# PHP Stan Config
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
tmpDir: /tmp/phpstan-codeblocks-dotenv
|
tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-dotenv
|
||||||
level: max
|
level: max
|
||||||
paths:
|
paths:
|
||||||
- %currentWorkingDirectory%
|
- %currentWorkingDirectory%/src
|
||||||
excludePaths:
|
excludePaths:
|
||||||
- vendor
|
- vendor
|
||||||
- test
|
- test
|
||||||
|
|||||||
@@ -2,4 +2,9 @@
|
|||||||
colors="true"
|
colors="true"
|
||||||
verbose="true"
|
verbose="true"
|
||||||
>
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="unit">
|
||||||
|
<directory>test/phpUnitTests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class DotEnv
|
|||||||
* if there are two variables with the same name only the first is used
|
* if there are two variables with the same name only the first is used
|
||||||
* variables are case sensitive
|
* variables are case sensitive
|
||||||
*
|
*
|
||||||
|
* [] Grouping Block Name as prefix until next or end if set,
|
||||||
|
* space replaced by _, all other var rules apply
|
||||||
|
*
|
||||||
* @param string $path Folder to file, default is __DIR__
|
* @param string $path Folder to file, default is __DIR__
|
||||||
* @param string $env_file What file to load, default is .env
|
* @param string $env_file What file to load, default is .env
|
||||||
* @return int -1 other error
|
* @return int -1 other error
|
||||||
@@ -56,10 +59,14 @@ class DotEnv
|
|||||||
$status = 1;
|
$status = 1;
|
||||||
$block = false;
|
$block = false;
|
||||||
$var = '';
|
$var = '';
|
||||||
while ($line = fgets($fp)) {
|
$prefix_name = '';
|
||||||
|
while (($line = fgets($fp)) !== false) {
|
||||||
|
// [] block must be a single line, or it will be ignored
|
||||||
|
if (preg_match("/^\s*\[([\w_.\s]+)\]/", $line, $matches)) {
|
||||||
|
$prefix_name = preg_replace("/\s+/", "_", $matches[1]) . ".";
|
||||||
|
} elseif (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
|
||||||
// main match for variable = value part
|
// main match for variable = value part
|
||||||
if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
|
$var = $prefix_name . $matches[1];
|
||||||
$var = $matches[1];
|
|
||||||
$value = $matches[2];
|
$value = $matches[2];
|
||||||
$quotes = $matches[3];
|
$quotes = $matches[3];
|
||||||
// write only if env is not set yet, and write only the first time
|
// write only if env is not set yet, and write only the first time
|
||||||
@@ -97,6 +104,9 @@ class DotEnv
|
|||||||
// just be sure it is init before we fill
|
// just be sure it is init before we fill
|
||||||
if (!isset($_ENV[$var])) {
|
if (!isset($_ENV[$var])) {
|
||||||
$_ENV[$var] = '';
|
$_ENV[$var] = '';
|
||||||
|
} elseif (!is_string($_ENV[$var])) {
|
||||||
|
// if this is not string, skip
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
// strip line of slashes
|
// strip line of slashes
|
||||||
$_ENV[$var] .= stripslashes($line);
|
$_ENV[$var] .= stripslashes($line);
|
||||||
|
|||||||
0
test/env/.gitignore
vendored
Normal file
0
test/env/.gitignore
vendored
Normal file
@@ -13,6 +13,36 @@ use PHPUnit\Framework\TestCase;
|
|||||||
*/
|
*/
|
||||||
final class DotEnvTest extends TestCase
|
final class DotEnvTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* setup the .env files before test run
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
// create .env files
|
||||||
|
$file_content = __DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. 'dotenv' . DIRECTORY_SEPARATOR
|
||||||
|
. 'test.env';
|
||||||
|
// copy to all folder levels
|
||||||
|
$env_files = [
|
||||||
|
__DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. 'dotenv' . DIRECTORY_SEPARATOR
|
||||||
|
. '.env',
|
||||||
|
__DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. '.env',
|
||||||
|
__DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. '..' . DIRECTORY_SEPARATOR
|
||||||
|
. '.env',
|
||||||
|
];
|
||||||
|
// if not found, skip -> all will fail
|
||||||
|
if (is_file($file_content)) {
|
||||||
|
foreach ($env_files as $env_file) {
|
||||||
|
copy($file_content, $env_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Undocumented function
|
||||||
*
|
*
|
||||||
@@ -30,6 +60,8 @@ final class DotEnvTest extends TestCase
|
|||||||
'HAS_COMMENT_NO_QUOTES_SPACE' => 'Comment at end no quotes and space',
|
'HAS_COMMENT_NO_QUOTES_SPACE' => 'Comment at end no quotes and space',
|
||||||
'HAS_COMMENT_NO_QUOTES_NO_SPACE' => 'Comment at end no quotes no space',
|
'HAS_COMMENT_NO_QUOTES_NO_SPACE' => 'Comment at end no quotes no space',
|
||||||
'COMMENT_IN_TEXT_QUOTES' => 'Foo bar # comment in here',
|
'COMMENT_IN_TEXT_QUOTES' => 'Foo bar # comment in here',
|
||||||
|
'HAS_EQUAL_NO_QUITES' => 'Is This = Valid',
|
||||||
|
'HAS_EQUAL_QUITES' => 'Is This = Valid',
|
||||||
'FAILURE' => 'ABC',
|
'FAILURE' => 'ABC',
|
||||||
'SIMPLEBOX' => 'A B C',
|
'SIMPLEBOX' => 'A B C',
|
||||||
'TITLE' => '1',
|
'TITLE' => '1',
|
||||||
@@ -57,6 +89,8 @@ final class DotEnvTest extends TestCase
|
|||||||
'__FOOFOO' => 'f ',
|
'__FOOFOO' => 'f ',
|
||||||
123123 => 'number',
|
123123 => 'number',
|
||||||
'EMPTY' => '',
|
'EMPTY' => '',
|
||||||
|
'Var_Test.TEST' => 'Block 1 D',
|
||||||
|
'OtherSet.TEST' => 'Block 2 D',
|
||||||
];
|
];
|
||||||
// 0: folder relative to test folder, if unset __DIR__
|
// 0: folder relative to test folder, if unset __DIR__
|
||||||
// 1: file, if unset .env
|
// 1: file, if unset .env
|
||||||
@@ -76,21 +110,24 @@ final class DotEnvTest extends TestCase
|
|||||||
'file' => 'cannot_read.env',
|
'file' => 'cannot_read.env',
|
||||||
'status' => 2,
|
'status' => 2,
|
||||||
'content' => [],
|
'content' => [],
|
||||||
'chmod' => '000',
|
// 0000
|
||||||
|
'chmod' => '100000',
|
||||||
],
|
],
|
||||||
'empty file' => [
|
'empty file' => [
|
||||||
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
||||||
'file' => 'empty.env',
|
'file' => 'empty.env',
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'content' => [],
|
'content' => [],
|
||||||
'chmod' => null,
|
// 0664
|
||||||
|
'chmod' => '100664',
|
||||||
],
|
],
|
||||||
'override all' => [
|
'override all' => [
|
||||||
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
||||||
'file' => 'test.env',
|
'file' => 'test.env',
|
||||||
'status' => 0,
|
'status' => 0,
|
||||||
'content' => $dot_env_content,
|
'content' => $dot_env_content,
|
||||||
'chmod' => null,
|
// 0664
|
||||||
|
'chmod' => '100664',
|
||||||
],
|
],
|
||||||
'override directory' => [
|
'override directory' => [
|
||||||
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
|
||||||
@@ -123,8 +160,23 @@ final class DotEnvTest extends TestCase
|
|||||||
array $expected_env,
|
array $expected_env,
|
||||||
?string $chmod
|
?string $chmod
|
||||||
): void {
|
): void {
|
||||||
// if we have file + chmod set
|
// skip if chmod is set to 10000 (000 no rights) if we are root
|
||||||
|
// as root there is no stop reading a file
|
||||||
|
if (
|
||||||
|
!empty($chmod) &&
|
||||||
|
$chmod == '100000' &&
|
||||||
|
getmyuid() == 0
|
||||||
|
) {
|
||||||
|
$this->markTestSkipped(
|
||||||
|
"Skip cannot read file test because run user is root"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// reset $_ENV for clean compare
|
||||||
|
$_ENV = [];
|
||||||
|
// previous file perm
|
||||||
$old_chmod = null;
|
$old_chmod = null;
|
||||||
|
// if we have change permission for file
|
||||||
if (
|
if (
|
||||||
is_file($folder . DIRECTORY_SEPARATOR . $file) &&
|
is_file($folder . DIRECTORY_SEPARATOR . $file) &&
|
||||||
!empty($chmod)
|
!empty($chmod)
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
test.env
|
|
||||||
@@ -10,6 +10,8 @@ HAS_COMMENT_QUOTES_NO_SPACE="Comment at end with quotes no space"# Comment QES
|
|||||||
HAS_COMMENT_NO_QUOTES_SPACE=Comment at end no quotes and space # Comment NQE
|
HAS_COMMENT_NO_QUOTES_SPACE=Comment at end no quotes and space # Comment NQE
|
||||||
HAS_COMMENT_NO_QUOTES_NO_SPACE=Comment at end no quotes no space# Comment NQES
|
HAS_COMMENT_NO_QUOTES_NO_SPACE=Comment at end no quotes no space# Comment NQES
|
||||||
COMMENT_IN_TEXT_QUOTES="Foo bar # comment in here"
|
COMMENT_IN_TEXT_QUOTES="Foo bar # comment in here"
|
||||||
|
HAS_EQUAL_NO_QUITES=Is This = Valid
|
||||||
|
HAS_EQUAL_QUITES="Is This = Valid"
|
||||||
FAILURE = ABC
|
FAILURE = ABC
|
||||||
SIMPLEBOX= A B C
|
SIMPLEBOX= A B C
|
||||||
TITLE=1
|
TITLE=1
|
||||||
@@ -47,3 +49,10 @@ SUPERLINE=
|
|||||||
EMPTY=
|
EMPTY=
|
||||||
= flase
|
= flase
|
||||||
asfasdf
|
asfasdf
|
||||||
|
# BLOCK TESTS
|
||||||
|
[Var Test]
|
||||||
|
TEST="Block 1 D"
|
||||||
|
[OtherSet]
|
||||||
|
TEST="Block 2 D"
|
||||||
|
[Ignore-Invalid-Block]
|
||||||
|
TEST="Block 3 D"
|
||||||
|
|||||||
@@ -6,12 +6,33 @@ $loader = require '../vendor/autoload.php';
|
|||||||
$loader->addPsr4('gullevek\\', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src');
|
$loader->addPsr4('gullevek\\', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src');
|
||||||
use gullevek\dotEnv\DotEnv;
|
use gullevek\dotEnv\DotEnv;
|
||||||
|
|
||||||
print "BASE: " . __DIR__ . "<br>";
|
// copy test file to .env file in env folder
|
||||||
print "ORIG: <pre>" . file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '.env') . "</pre>";
|
$file_content = __DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. 'phpUnitTests' . DIRECTORY_SEPARATOR
|
||||||
|
. 'dotenv' . DIRECTORY_SEPARATOR
|
||||||
|
. 'test.env';
|
||||||
|
// env folder
|
||||||
|
$env_file = __DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. 'env' . DIRECTORY_SEPARATOR
|
||||||
|
. '.env';
|
||||||
|
if (!is_file($file_content)) {
|
||||||
|
die("Cannot read $file_content");
|
||||||
|
}
|
||||||
|
if (copy($file_content, $env_file) === false) {
|
||||||
|
die("Cannot copy $file_content to $env_file");
|
||||||
|
}
|
||||||
|
|
||||||
$status = DotEnv::readEnvFile(__DIR__);
|
print "BASE: " . __DIR__ . "<br>";
|
||||||
|
print "ENV: " . $env_file . "<br>";
|
||||||
|
print "ORIG: <pre>" . file_get_contents($env_file) . "</pre>";
|
||||||
|
|
||||||
|
$status = DotEnv::readEnvFile(__DIR__ . DIRECTORY_SEPARATOR . 'env');
|
||||||
|
|
||||||
print "STATUS: " . (string)$status . "<br>";
|
print "STATUS: " . (string)$status . "<br>";
|
||||||
print "ENV: <pre>" . print_r($_ENV, true) . "</pre><br>";
|
print "ENV: <pre>" . print_r($_ENV, true) . "</pre><br>";
|
||||||
|
|
||||||
|
$status = gullevek\dotenv\DotEnv::readEnvFile(__DIR__ . DIRECTORY_SEPARATOR . 'env');
|
||||||
|
print "STATUS B: " . (string)$status . "<br>";
|
||||||
|
print "ENV B: <pre>" . print_r($_ENV, true) . "</pre><br>";
|
||||||
|
|
||||||
// __END__
|
// __END__
|
||||||
|
|||||||
2
tmp/.gitignore
vendored
Normal file
2
tmp/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
Reference in New Issue
Block a user