Initial commit: apps.prometeysev.ru

This commit is contained in:
root committed 2026-10-22 00:22:57 +03:00
commit 96ccabcd8b
6561 files changed
+1270349

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
; This file is for unifying the coding style for different editors and IDEs.
; More information at http://editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
+46
View File
@@ -0,0 +1,46 @@
# Changelog
All Notable changes to `Env` will be documented in this file
## 2.1.0 - 2016-10-06
### Fixed
- Single quote variables in single quotes will be treated as strings
## 2.0.0 - 2016-01-07
### Altered
- Must pass `file_get_contents()` or content string to `parser` not a `file`
- Keys must not start with a number
- Make `#` in unquoted into string if no space, e.g. `value#notacomment`
### Removed
- File logic (Env.php)
## 1.1.0 - 2016-01-05
### Added
- Support for parameter expansions: [default value](http://wiki.bash-hackers.org/syntax/pe#use_a_default_value) and [assign default value](http://wiki.bash-hackers.org/syntax/pe#assign_a_default_value)
- Support for php `5.3` and `hhvm`
### Altered
- Updated README
- Test cases
## 1.0.2 - 2016-01-03
### Altered
- Updated README
## 1.0.1 - 2015-12-21
### Fixed
- Fixed composer.json
## 1.0.0 - 2015-12-13
### Altered
- Bump to version 1
- Refactored
## 0.2.0 - 2015-12-13
### Altered
- General refactoring and clean up for 0.2.0
## 0.1.0 - 2015-12-13
### Added
- Initial Release
+22
View File
@@ -0,0 +1,22 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
+32
View File
@@ -0,0 +1,32 @@
# Contributing
Contributions are **welcome** and will be fully **credited**.
We accept contributions via Pull Requests on [Github](https://github.com/m1/env).
## Pull Requests
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Check the code style with ``$ composer check-codestyle`` and fix it with ``$ composer fix-codestyle``.
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
- **Create feature branches** - Don't ask us to pull from your master branch.
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
## Running Tests
``` bash
$ composer test
```
**Happy coding**!
+21
View File
@@ -0,0 +1,21 @@
# The MIT License (MIT)
Copyright (c) 2015 Miles Croxford <hello@milescroxford.com>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
+612
View File
@@ -0,0 +1,612 @@
# Env
[![Author](http://img.shields.io/badge/author-@milescroxford-blue.svg?style=flat-square)](https://twitter.com/milescroxford)
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-travis]][link-travis]
[![Coverage Status][ico-scrutinizer]][link-scrutinizer]
[![Quality Score][ico-code-quality]][link-code-quality]
[![Downloads][ico-downloads]][link-downloads]
[![StyleCI](https://styleci.io/repos/47935133/shield)](https://styleci.io/repos/47935133)
[![Sensio badge][ico-sensio]][link-sensio]
Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.
* [Why?](#why)
* [Requirements](#requirements)
* [Install](#install)
* [Usage](#usage)
* [Basic](#basic)
* [Context variables](#context)
* [Syntax](#syntax)
* [Assignment](#assignment)
* [Strings](#strings)
* [Numbers](#numbers)
* [Booleans](#booleans)
* [Null](#null)
* [Variables](#variables)
* [Default Value/Assignment](#parameter-expansion)
* [Comments](#comments)
* [.env example](#env-example)
* [Notes](#notes)
* [Source](#source)
* [Other library comparisons](#other-library-comparisons)
* [Todo](#todo)
* [Change log](#change-log)
* [Testing](#testing)
* [Contributing](#Contributing)
* [Security](#security)
* [Credits](#credits)
* [License](#license)
## Why?
Env aims to bring a unified parser for env together for PHP rather than having a few incomplete or buggy parsers written
into other libraries. This library is not meant as a complete package for config loading like other libraries as this
is out of scope for this library. If you need something like that check out [Vars](http://github.com/m1/Vars) which incorporates
this library so you can load Env and other file types if you want, or checkout [PHP Dotenv](https://github.com/josegonzalez/php-dotenv)
if you only need .env parsing
## Requirements
Env requires PHP version `5.3+` - supported and tested on `5.3`, `5.4`, `5.5`, `5.6`, `7` and `hhvm`.
## Install
Via Composer
``` bash
$ composer require m1/env
```
## Usage
### Basic
test.env
```bash
TEST_1 = VALUE
```
example.php
```php
<?php
//both examples return the same thing
// example 1 -- standard
use M1\Env\Parser;
$env = new Parser(file_get_contents('test.env'));
$arr = $env->getContent();
// example 2 -- statically
$arr = Parser::parse(file_get_contents('test.env'));
var_dump($arr);
// [
// "TEST_1" => "VALUE"
// ]
```
### Context variables
test_context.env
```bash
TEST_1 = $EXTERNAL
TEST_2 = VALUE
```
example_context.php
```php
<?php
//both examples return the same thing
// example 1 -- standard
use M1\Env\Parser;
$env = new Parser(file_get_contents('test_context.env'), array('EXTERNAL' => 'external'));
$arr = $env->getContent();
// example 2 -- statically
$arr = Parser::parse(file_get_contents('test_context.env'), array('EXTERNAL' => 'external'));
var_dump($arr);
// [
// "TEST_1" => "external"
// "TEST_2" => "VALUE"
// ]
```
### Syntax
The Syntax is slightly more relaxed than bash, but still remains quite bash like
#### Assignment
To assign values the syntax is `key = value`, unlike bash the assignment is pretty relaxed, any of the below are valid:
```bash
TEST1 = value
TEST2= VALUE
TEST3 =VALUE
TEST4=VALUE
TEST5 = VALUE
TEST6 = VALUE
```
However keys can not start with a number, e.g.:
```bash
1notvalid = nope
```
Will throw a `ParseException`
You can also add `export` to the start of variables to `source` the file in bash ([see here](#source) for more info):
```bash
export TEST1=value
```
#### Strings
Strings can either be in quotes (single or double) or without:
```bash
TEST1 = value
TEST2 = "value"
TEST3 = 'value'
```
To escape new lines or quotes is the standard backslash:
```bash
TEST1 = "value \n value"
TEST2 = "value \"value\" value"
TEST3 = 'value \' value \' value'
```
If you feature two quoted strings as a value then only the first quoted string will be assigned to the key:
```bash
TEST1 = "value value" "this sentence in quotes will not be counted"
```
#### Numbers
Numbers are fairly standard:
```bash
TEST1 = 1
TEST2 = 2
```
Decimal numbers will be automatically cast to floats:
```bash
TEST1 = 1.1 # `float` type
TEST2 = 2 # `int` type
```
If you quote numbers they will be counted as strings, or if you have two numbers on one line:
```bash
TEST1 = 33 33 # `string` type
TEST2 = "22" # `string` type
```
#### Booleans
Booleans can be `true`, `false`, `yes` and `no`:
```bash
TEST1 = true
TEST2 = false
TEST3 = yes
TEST4 = no
```
Booleans are case-insensitive:
```bash
TEST1 = True
TEST2 = False
TEST3 = YES
TEST4 = NO
```
Booleans in quotes will be treated as strings:
```bash
TEST1 = "true" # `string` type
TEST2 = "YES" # `string` type
TEST3 = 'NO' # `string` type
```
#### Null
Both of the below are counted as null values:
```bash
TEST1 =
TEST2 = null
```
Whereas an empty string is counted as a string:
```bash
TEST1 = "" # `string` type
TEST2 = '' # `string` type
```
#### Variables
Variables are based of the bash syntax:
```bash
TEST1 = 'hello'
TEST2 = ${TEST27} # 'hello'
```
The types of variable get passed to the calling variable if there is only one variable. If there are more than one variable,
the calling variable is automatically cast to a string:
```bash
TEST1 = 1 # `int` type
TEST2 = 2 # `int` type
TEST3 = ${TEST1} ${TEST2} # `string` type
TEST4 = true # `bool` type
TEST5 = ${TEST4} # `bool` type
```
Also if the variable is in quotes then the variable will be automatically cast as a string:
```bash
TEST1 = 1 # `int` type
TEST2 = "${TEST1}" # `string` type
```
But you can use variables without quotes and they'll be cast as strings:
```bash
TEST1 = foo
TEST2 = bar
TEST3 = ${TEST1}/${TEST2} # `string` type
```
Variables are useful to use in strings like so:
```bash
TEST1 = "foo"
TEST2 = 'bar'
TEST3 = "hello ${TEST1} and ${TEST2}"
```
Null values are passed and casted as empty strings if in quotes:
```bash
TEST1 = null
TEST2 = ${TEST1} # `null` type
TEST3 = "${TEST1}" # `string` type
```
Single Quotes with variables will be counted as strings:
```bash
TEST1 = '${hello} # `string` type, will output: '${hello}'
```
##### Parameter Expansion
You can do parameter expansion, so far you can only do [default values](http://wiki.bash-hackers.org/syntax/pe#use_a_default_value)
and [assign default values](http://wiki.bash-hackers.org/syntax/pe#assign_a_default_value) like in the bash syntax:
```bash
TEST1 = foo
TEST2 = ${TEST3:=bar}
TEST4 = ${TEST5=bar}
TEST6 = ${TEST7:-bar}
TEST8 = ${TEST9-bar}
```
The default value parameter expansion syntax is `:-`, the explanation on the [bash-hackers wiki](http://wiki.bash-hackers.org/syntax/pe#use_a_default_value) for this is:
> SYNTAX:
>
>`${PARAMETER:-WORD}`
>
>`${PARAMETER-WORD}`
>
>If the parameter PARAMETER is unset (never was defined) or null (empty), this one expands to WORD, otherwise it
>expands to the value of PARAMETER, as if it just was ${PARAMETER}. If you omit the : (colon), like shown in the second
>form, the default value is only used when the parameter was unset, not when it was empty.
For example:
```bash
TEST1 = foo
TEST2 = ${TEST1:-bar} # TEST1 is set so the value of TEST2 = foo
TEST3 = ${TEST4:-bar} # TEST4 is not set so the value of TEST3 = bar
TEST5 = null
TEST6 = ${TEST5-bar} # TEST5 is set but empty so the value of TEST6 = null
TEST7 = ${TEST6:-bar} # TEST5 is set and empty so the value of TEST7 = bar
```
The assign default value parameter expansion is `:=`, the explanation on the [bash-hackers wiki](http://wiki.bash-hackers.org/syntax/pe#assign_a_default_value) for this is:
> SYNTAX:
>
>`${PARAMETER:=WORD}`
>
>`${PARAMETER=WORD}`
>
>This one works like the using default values, but the default text you give is not only expanded, but also assigned
>to the parameter, if it was unset or null. Equivalent to using a default value, when you omit the : (colon), as
>shown in the second form, the default value will only be assigned when the parameter was unset.
For example:
```bash
TEST1 = foo
TEST2 = ${TEST1:=bar} # TEST1 is set so the value of TEST2 = foo
TEST3 = ${TEST4:=bar} # TEST4 is not set so the value of TEST3 = bar and TEST4 = bar
TEST5 = null
TEST6 = ${TEST5=bar} # TEST5 is set but emtpy so the value of TEST6 = null
TEST7 = ${TEST6=bar} # TEST5 is set and empty so the value of TEST7 = bar and TEST5 = bar
```
#### Comments
To comment, just use the `#` syntax, you can also comment inline like so:
```bash
# This is a comment
TEST1 = bar # and so is this
```
If you put a `#` without a space in a unquoted string, it will be parsed as a string:
```bash
TEST1 = hello#notacomment
```
### .env example
```bash
# Comments are done like this
# Standard key=value
TEST1 = value
TEST2 = value
TEST3 = value # You can also comment inline like this
# Strings
TEST4 = "value"
## The value of the below variable will be TK4 = "value value"
TEST5 = "value value" "this sentence in quotes will not be counted"
## Escape newline
TEST6 = "value \n value"
## Escape double quotes
TEST7 = "value \"value\" value"
## You can also exchange any of the above for single quotes, eg:
TEST8 = 'value'
TEST9 = 'value \' value \' value'
# Numbers
TEST10 = 1
TEST11 = 1.1
TEST12 = 33 33 # Will output as a `string` -- not a number as two numbers are given
TEST13 = "33" # 33 -- `string` type
# Bools -- All of the below are valid booleans
TEST14 = true
TEST15 = false
TEST16 = yes
TEST17 = no
## Booleans are case-insensitive
TEST18 = True
TEST19 = False
TEST20 = YES
TEST21 = NO
TEST22 = "true" # "true" -- `string` type
TEST23 = "YES" # "YES" -- `string` type
TEST24 = 'NO' # "NO" -- `string` type
# Null values
TEST25 =
TEST26 = null
# Variables
TEST27 = 'hello'
TEST28 = ${TEST27} # 'hello'
TEST29 = 1
TEST30 = 2
TEST31 = ${TEST29} # 1 -- `int` type
TEST32 = "${TEST29}" # 1 -- `string` type
TEST33 = ${TEST29} ${TEST30} # 1 2 -- `string` type
TEST34 = foo
TEST35 = bar
TEST36 = ${TEST34}/${TEST35} # foo/bar -- `string` type
TEST37 = "foo"
TEST38 = 'bar'
TEST39 = "hello ${TEST37} and ${TEST38}" # hello foo and bar -- `string` type
TEST40 = true
TEST41 = false
TEST42 = ${TEST40} # true -- `bool` type
TEST43 = ${TEST40} ${TEST41} # true false -- `string` type
TEST44 = null
TEST45 = ${TEST44} # null -- `null` type
TEST46 = "${TEST44}" # '' -- `string` type
TEST46_5 = '${TEST44}' # '' -- `string` type
TEST47=foo
TEST48=${TEST47:=bar}
TEST49=${TEST50:=foo}
TEST51=${TEST52:-foo}
TEST53=null
TEST54=${TEST53=foo}
TEST55=null
TEST56=${TEST55-foo}
TEST57=${TEST58:=""}
TEST59=${TEST60:=null} # TEST59 = null TEST60 = null -- both `null` types
TEST61=${TEST62:=true} # TEST61 = true TEST62 = true -- both `bool` types
# Comments
TEST63 = hello # comment
TEST64 = "hello # comment"
TEST65 = "hello" #comment
TEST66 = #comment
TEST67 = "#comment"
TEST68 = thisisnota#comment
```
The result from this library and the expected result of the above is:
```php
array(
"TEST1" => "value",
"TEST2" => "value",
"TEST3" => "value",
"TEST4" => "value",
"TEST5" => "value value",
"TEST6" => "value \n value",
"TEST7" => 'value "value" value',
"TEST8" => "value",
"TEST9" => "value ' value ' value",
"TEST10" => 1,
"TEST11" => 1.1,
"TEST12" => "33 33",
"TEST13" => "33",
"TEST14" => true,
"TEST15" => false,
"TEST16" => true,
"TEST17" => false,
"TEST18" => true,
"TEST19" => false,
"TEST20" => true,
"TEST21" => false,
"TEST22" => "true",
"TEST23" => "YES",
"TEST24" => 'NO',
"TEST25" => null,
"TEST26" => null,
"TEST27" => "hello",
"TEST28" => "hello",
"TEST29" => 1,
"TEST30" => 2,
"TEST31" => 1,
"TEST32" => "1",
"TEST33" => "1 2",
"TEST34" => "foo",
"TEST35" => "bar",
"TEST36" => "foo/bar",
"TEST37" => "foo",
"TEST38" => 'bar',
"TEST39" => "hello foo and bar",
"TEST40" => true,
"TEST41" => false,
"TEST42" => true,
"TEST43" => "true false",
"TEST44" => null,
"TEST45" => null,
"TEST46" => "",
"TEST46_5" => "${TEST44}",
'TEST47' => 'foo',
'TEST48' => 'foo',
'TEST50' => 'foo',
'TEST49' => 'foo',
'TEST51' => 'foo',
'TEST53' => null,
'TEST54' => null,
'TEST55' => null,
'TEST56' => null,
'TEST58' => '',
'TEST57' => '',
'TEST60' => null,
'TEST59' => null,
'TEST62' => true,
'TEST61' => true,
'TEST63' => 'hello # comment',
'TEST64' => 'hello',
'TEST66' => null,
'TEST67' => '#comment',
'TEST68' => 'thisisnota#comment',
);
```
## Notes
### Source
If you need the .env variables in other applications, you can `source` the env, but make sure it's valid bash syntax, as this parser allows a more relaxed form of bash syntax.
```bash
source .env
```
This library will always be able to parse bash syntax, but for now the opposite (env syntax -> bash syntax) may not be true, however this is being worked on to bring a strict parser version for `3.0`
## Other library comparisons
The difference between this library and other similar libraries:
#### `zrcing/phpenv`:
- Converts all value types to string
- Does not support `null` values
- Does not support `int`, `float` or `bool` types
- Does not support variables
#### `Dotenv\Dotenv`:
- Does not support unquoted values like `33 33`, this should be cast to string. See `TEST12`
- Does not support concatenation of variables unquoted like `${VAR} ${VAR2}`, this should be cast to string. See `TEST33`
- Both of the above crash `Dotenv` without a helpful exception
- Converts all value types to string
- Does not support `null` values
- Does not support `int`, `float` or `bool` types
- Does not support variables
- Does not support [parameter expansions](#parameter-expansion)
- Does not support inline comments where there is no value. See `TEST66`
## Todo
- [Other bash parameter expansions](http://wiki.bash-hackers.org/syntax/pe#display_error_if_null_or_unset)
## Change log
Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
## Testing
``` bash
$ composer test
```
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details.
## Security
If you discover any security related issues, please email hello@milescroxford.com instead of using the issue tracker.
## Credits
- [m1][link-author]
- [All Contributors][link-contributors]
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
[ico-version]: https://img.shields.io/packagist/v/m1/Env.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/m1/Env/master.svg?style=flat-square
[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/m1/Env.svg?style=flat-square
[ico-hhvm]: https://img.shields.io/hhvm/m1/Env.svg?style=flat-square
[ico-code-quality]: https://img.shields.io/scrutinizer/g/m1/Env.svg?style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/m1/Env.svg?style=flat-square
[ico-sensio]: https://insight.sensiolabs.com/projects/1fb8cbab-f611-45b5-8a45-0113e433eab7/big.png
[link-packagist]: https://packagist.org/packages/m1/Env
[link-travis]: https://travis-ci.org/m1/Env
[link-scrutinizer]: https://scrutinizer-ci.com/g/m1/Env/code-structure
[link-code-quality]: https://scrutinizer-ci.com/g/m1/Env
[link-downloads]: https://packagist.org/packages/m1/Env
[link-author]: https://github.com/m1
[link-contributors]: ../../contributors
[link-sensio]: https://insight.sensiolabs.com/projects/1fb8cbab-f611-45b5-8a45-0113e433eab7
+51
View File
@@ -0,0 +1,51 @@
{
"name": "m1/env",
"description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.",
"keywords": [
"m1",
"env",
"loader",
"config",
".env",
"dotenv",
"support",
"parser"
],
"homepage": "https://github.com/m1/Env",
"license": "MIT",
"authors": [
{
"name": "Miles Croxford",
"email": "hello@milescroxford.com",
"homepage": "http://milescroxford.com",
"role": "Developer"
}
],
"require": {
"php" : ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit" : "4.*",
"scrutinizer/ocular": "~1.1",
"squizlabs/php_codesniffer": "^2.3"
},
"suggest": {
"josegonzalez/dotenv": "For loading of .env",
"m1/vars": "For loading of configs"
},
"autoload": {
"psr-4": {
"M1\\Env\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"M1\\Env\\Test\\": "tests"
}
},
"scripts": {
"test": "phpunit",
"check-codestyle": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests",
"fix-codestyle": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests"
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Exception;
/**
* Env ParseException
*
* @since 0.1.0
*/
class ParseException extends \ErrorException
{
/**
* Constructs a ParseException
*
* @param string $message The value to parse
* @param string $line The line of the value
* @param int $line_num The line num of the value
*/
public function __construct($message, $line = null, $line_num = null)
{
$message = $this->createMessage($message, $line, $line_num);
parent::__construct($message);
}
/**
* Constructs a ParseException message
*
* @param string $message The value to parse
* @param string $line The line of the value
* @param int $line_num The line num of the value
*
* @return string The exception message
*/
private function createMessage($message, $line, $line_num)
{
if (!is_null($line)) {
$message .= sprintf(" near %s", $line);
}
if (!is_null($line_num)) {
$message .= sprintf(" at line %d", $line_num);
}
return $message;
}
}
+150
View File
@@ -0,0 +1,150 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Helper;
/**
* The class for string helping
*
* @since 1.1.0
*/
class StringHelper
{
/**
* The bool variants available in .env
*
* @var array $bool_variants
*/
private static $bool_variants = array(
'true', 'false', 'yes', 'no'
);
/**
* Returns if value is a bool
*
* @param string $value The value to test
*
* @return bool Is a value a bool
*/
public function isBool($value)
{
return in_array(strtolower($value), self::$bool_variants);
}
/**
* Returns if the bool is in a string
*
* @param string $value The value to test
* @param bool $quoted_string Is the context a quoted string
* @param int $word_count The amount of words in the sentence
*
* @return bool Is a value a bool in a string
*/
public function isBoolInString($value, $quoted_string, $word_count)
{
return (is_bool($value)) && ($quoted_string || $word_count >= 2);
}
/**
* Returns if value is null
*
* @param string $value The value to test
*
* @return bool Is a value null
*/
public function isNull($value)
{
return $value === 'null';
}
/**
* Returns if value is number
*
* @param string $value The value to test
*
* @return bool Is a value a number
*/
public function isNumber($value)
{
return is_numeric($value);
}
/**
* Returns if value is a string
*
* @param string $value The value to test
*
* @return bool Is a value a string
*/
public function isString($value)
{
return $this->startsWith('\'', $value) || $this->startsWith('"', $value);
}
/**
* Returns if variable value is a clone, e.g. BOOL = $(BOOL_1)
*
* @param string $value The value to test
* @param array $matches The matches of the variables
* @param bool $quoted_string If the value is in a quoted string
*
* @return bool Is a value null
*/
public function isVariableClone($value, $matches, $quoted_string)
{
return (count($matches[0]) === 1) && $value == $matches[0][0] && !$quoted_string;
}
/**
* Returns if value starts with a value
*
* @param string $string The value to search for
* @param string $line The line to test
*
* @return bool Returns if the line starts with value
*/
public function startsWith($string, $line)
{
return $string === "" || strrpos($line, $string, -strlen($line)) !== false;
}
/**
* Returns if value starts with a number
*
* @param string $line The line to test
*
* @return bool Returns if the line starts with a number
*/
public function startsWithNumber($line)
{
return is_numeric(substr($line, 0, 1));
}
/**
* Strips comments from a value
*
* @param string $value The value to strip comments from
*
* @return string value
*/
public function stripComments($value)
{
$value = explode(" #", $value, 2);
return trim($value[0]);
}
}
+244
View File
@@ -0,0 +1,244 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env;
use M1\Env\Exception\ParseException;
use M1\Env\Helper\StringHelper;
use M1\Env\Parser\ValueParser;
use M1\Env\Parser\KeyParser;
/**
* The .env parser
*
* @since 0.1.0
*/
class Parser
{
/**
* The Env key parser
*
* @var \M1\Env\Parser\KeyParser $key_parser
*/
private $key_parser;
/**
* The line num of the current value
*
* @var int $line_num
*/
public $line_num;
/**
* The current parsed values/lines
*
* @var array $lines
*/
public $lines = array();
/**
* The String helper class
*
* @var \M1\Env\Helper\StringHelper $string_helper
*/
public $string_helper;
/**
* The Env value parser
*
* @var \M1\Env\Parser\ValueParser $value_parser
*/
public $value_parser;
/**
* The parser constructor
*
* @param string $content The content to parse
* @param array $context Variables context
*/
public function __construct($content, array $context = array())
{
$this->key_parser = new KeyParser($this);
$this->value_parser = new ValueParser($this, $context);
$this->string_helper = new StringHelper();
$this->doParse($content);
}
/**
* Parses the .env and returns the contents statically
*
* @param string $content The content to parse
* @param array $context Variables context
*
* @return array The .env contents
*/
public static function parse($content, array $context = array())
{
$parser = new Parser($content, $context);
return $parser->getContent();
}
/**
* Opens the .env, parses it then returns the contents
*
* @param string $content The content to parse
*
* @return array The .env contents
*/
protected function doParse($content)
{
$raw_lines = array_filter($this->makeLines($content), 'strlen');
if (empty($raw_lines)) {
return;
}
return $this->parseContent($raw_lines);
}
/**
* Splits the string into an array
*
* @param string $content The string content to split
*
* @return array The array of lines to parse
*/
private function makeLines($content)
{
return explode("\n", str_replace(array("\r\n", "\n\r", "\r"), "\n", $content));
}
/**
* Parses the .env line by line
*
* @param array $raw_lines The raw content of the file
*
* @throws \M1\Env\Exception\ParseException If the file does not have a key=value structure
*
* @return array The .env contents
*/
private function parseContent(array $raw_lines)
{
$this->lines = array();
$this->line_num = 0;
foreach ($raw_lines as $raw_line) {
$this->line_num++;
if ($this->string_helper->startsWith('#', $raw_line) || !$raw_line) {
continue;
}
$this->parseLine($raw_line);
}
return $this->lines;
}
/**
* Parses a line of the .env
*
* @param string $raw_line The raw content of the line
*
* @return array The parsed lines
*/
private function parseLine($raw_line)
{
$raw_line = $this->parseExport($raw_line);
list($key, $value) = $this->parseKeyValue($raw_line);
$key = $this->key_parser->parse($key);
if (!is_string($key)) {
return;
}
$this->lines[$key] = $this->value_parser->parse($value);
}
/**
* Parses a export line of the .env
*
* @param string $raw_line The raw content of the line
*
* @throws \M1\Env\Exception\ParseException If the file does not have a key=value structure
*
* @return string The parsed line
*/
private function parseExport($raw_line)
{
$line = trim($raw_line);
if ($this->string_helper->startsWith("export", $line)) {
$export_line = explode("export", $raw_line, 2);
if (count($export_line) !== 2 || empty($export_line[1])) {
throw new ParseException(
'You must have a export key = value',
$raw_line,
$this->line_num
);
}
$line = trim($export_line[1]);
}
return $line;
}
/**
* Gets the key = value items from the line
*
* @param string $raw_line The raw content of the line
*
* @throws \M1\Env\Exception\ParseException If the line does not have a key=value structure
*
* @return array The parsed lines
*/
private function parseKeyValue($raw_line)
{
$key_value = explode("=", $raw_line, 2);
if (count($key_value) !== 2) {
throw new ParseException(
'You must have a key = value',
$raw_line,
$this->line_num
);
}
return $key_value;
}
/**
* Returns the contents of the .env
*
* @return array The .env contents
*/
public function getContent($keyName = null)
{
if (!is_null($keyName)) {
return (array_key_exists($keyName, $this->lines)) ? $this->lines[$keyName] : null;
}
return $this->lines;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Parser;
/**
* The abstract parser for Env
*
* @since 0.2.0
*/
abstract class AbstractParser
{
/**
* The parent parser
*
* @var \M1\Env\Parser $parser
*/
protected $parser;
/**
* The abstract parser constructor for Env
*
* @param \M1\Env\Parser $parser The parent parser
*/
public function __construct($parser)
{
$this->parser = $parser;
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Parser;
use M1\Env\Exception\ParseException;
/**
* The key parser for Env
*
* @since 0.2.0
*/
class KeyParser extends AbstractParser
{
/**
* Parses a .env key
*
* @param string $key The key string
*
* @throws \M1\Env\Exception\ParseException If key contains a character that isn't alphanumeric or a _
*
* @return string|false The parsed key, or false if the key is a comment
*/
public function parse($key)
{
$key = trim($key);
if ($this->parser->string_helper->startsWith('#', $key)) {
return false;
}
if (!ctype_alnum(str_replace('_', '', $key)) || $this->parser->string_helper->startsWithNumber($key)) {
throw new ParseException(
sprintf('Key can only contain alphanumeric and underscores and can not start with a number: %s', $key),
$key,
$this->parser->line_num
);
}
return $key;
}
}
+264
View File
@@ -0,0 +1,264 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Parser;
use M1\Env\Exception\ParseException;
/**
* The value parser for Env
*
* @since 0.2.0
*/
class ValueParser extends AbstractParser
{
/**
* The regex to get the content between double quote (") strings, ignoring escaped quotes.
* Unescaped: "(?:[^"\\]*(?:\\.)?)*"
*
* @var string REGEX_QUOTE_DOUBLE_STRING
*/
const REGEX_QUOTE_DOUBLE_STRING = '"(?:[^\"\\\\]*(?:\\\\.)?)*\"';
/**
* The regex to get the content between single quote (') strings, ignoring escaped quotes
* Unescaped: '(?:[^'\\]*(?:\\.)?)*'
*
* @var string REGEX_QUOTE_SINGLE_STRING
*/
const REGEX_QUOTE_SINGLE_STRING = "'(?:[^'\\\\]*(?:\\\\.)?)*'";
/**
* The value types that Env supports
*
* @var array $value_types
*/
private static $value_types = array(
'string',
'bool',
'number',
'null',
);
/**
* The map to convert escaped characters into real characters
*
* @var array $character_map
*/
private static $character_map = array(
"\\n" => "\n",
"\\\"" => "\"",
'\\\'' => "'",
'\\t' => "\t"
);
/**
* The parser for variables
*
* @var \M1\Env\Parser\VariableParser $variable_parser
*/
private $variable_parser;
/**
* {@inheritdoc}
*
* @param \M1\Env\Parser $parser The parent parser
* @param array $context Variables context
*/
public function __construct($parser, array $context = array())
{
parent::__construct($parser);
$this->variable_parser = new VariableParser($parser, $context);
}
/**
* Parses a .env value
*
* @param string $value The value to parse
*
* @return string|null The parsed key, or null if the key is a comment
*/
public function parse($value)
{
$value = trim($value);
if ($this->parser->string_helper->startsWith('#', $value)) {
return null;
}
return $this->parseValue($value);
}
/**
* Parses a .env value
*
* @param string $value The value to parse
*
* @return string|null The parsed value, or null if the value is null
*
* @uses parseString
* @uses parseNull
* @uses parseBool
* @uses parseNumber
*/
private function parseValue($value)
{
foreach (self::$value_types as $type) {
$parsed_value = $value;
if ($type !== 'string') {
$parsed_value = $this->parser->string_helper->stripComments($value);
}
list($is_function, $parse_function) = $this->fetchFunctionNames($type);
if ($this->parser->string_helper->$is_function($parsed_value)) {
return $this->$parse_function($parsed_value);
}
}
return (isset($parsed_value)) ? $this->parseUnquotedString($parsed_value) : $value;
}
/**
* Gets the functions for the value type
*
* @param string $type The value type
*
* @return string[] The is and parse function names
*/
private function fetchFunctionNames($type)
{
$type = ucfirst($type);
return array(
'is'.$type,
'parse'.$type
);
}
/**
* Parses a .env string
*
* @param string $value The value to parse
*
* @return string The parsed string
*/
private function parseString($value)
{
$single = false;
$regex = self::REGEX_QUOTE_DOUBLE_STRING;
$symbol = '"';
if ($this->parser->string_helper->startsWith('\'', $value)) {
$single = true;
$regex = self::REGEX_QUOTE_SINGLE_STRING;
$symbol = "'";
}
$matches = $this->fetchStringMatches($value, $regex, $symbol);
$value = trim($matches[0], $symbol);
$value = strtr($value, self::$character_map);
return ($single) ? $value : $this->variable_parser->parse($value, true);
}
/**
* Gets the regex matches in the string
*
* @param string $regex The regex to use
* @param string $value The value to parse
* @param string $symbol The symbol we're parsing for
*
* @throws \M1\Env\Exception\ParseException If the string has a missing end quote
*
* @return string[] The matches based on the regex and the value
*/
private function fetchStringMatches($value, $regex, $symbol)
{
if (!preg_match('/'.$regex.'/', $value, $matches)) {
throw new ParseException(
sprintf('Missing end %s quote', $symbol),
$value,
$this->parser->line_num
);
}
return $matches;
}
/**
* Parses a .env null value
*
* @param string $value The value to parse
*
* @return null Null value
*/
private function parseNull($value)
{
return (is_null($value) || $value === "null") ? null : false;
}
/**
* Parses a .env unquoted string
*
* @param string $value The value to parse
*
* @return string The parsed string
*/
private function parseUnquotedString($value)
{
if ($value === "") {
return null;
}
return $this->variable_parser->parse($value);
}
/**
* Parses a .env bool
*
* @param string $value The value to parse
*
* @return bool The parsed bool
*/
private function parseBool($value)
{
$value = strtolower($value);
return $value === "true" || $value === "yes";
}
/**
* Parses a .env number
*
* @param string $value The value to parse
*
* @return int|float The parsed bool
*/
private function parseNumber($value)
{
if (strpos($value, '.') !== false) {
return (float) $value;
}
return (int) $value;
}
}
+358
View File
@@ -0,0 +1,358 @@
<?php
/**
* This file is part of the m1\env library
*
* (c) m1 <hello@milescroxford.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package m1/env
* @version 2.0.0
* @author Miles Croxford <hello@milescroxford.com>
* @copyright Copyright (c) Miles Croxford <hello@milescroxford.com>
* @license http://github.com/m1/env/blob/master/LICENSE.md
* @link http://github.com/m1/env/blob/master/README.md Documentation
*/
namespace M1\Env\Parser;
use M1\Env\Exception\ParseException;
/**
* The value parser for Env
*
* @since 1.1.0
*/
class VariableParser extends AbstractParser
{
/**
* The regex to get variables '$(VARIABLE)' in .env
* Unescaped: ${(.*?)}
*
* @var string REGEX_ENV_VARIABLE
*/
const REGEX_ENV_VARIABLE = '\\${(.*?)}';
/**
* The symbol for the assign default value parameter expansion
*
* @var string SYMBOL_ASSIGN_DEFAULT_VALUE
*/
const SYMBOL_ASSIGN_DEFAULT_VALUE = '=';
/**
* The symbol for the default value parameter expansion
*
* @var string SYMBOL_DEFAULT_VALUE
*/
const SYMBOL_DEFAULT_VALUE = '-';
/**
* Variables context
*
* @var array
*/
private $context;
/**
* {@inheritdoc}
*
* @param \M1\Env\Parser $parser The parent parser
* @param array $context Variables context
*/
public function __construct($parser, array $context = array())
{
parent::__construct($parser);
$this->context = $context;
}
/**
* Parses a .env variable
*
* @param string $value The value to parse
* @param bool $quoted_string Is the value in a quoted string
*
* @return string The parsed value
*/
public function parse($value, $quoted_string = false)
{
$matches = $this->fetchVariableMatches($value);
if (is_array($matches)) {
if ($this->parser->string_helper->isVariableClone($value, $matches, $quoted_string)) {
return $this->fetchVariable($value, $matches[1][0], $matches, $quoted_string);
}
$value = $this->doReplacements($value, $matches, $quoted_string);
}
return $value;
}
/**
* Get variable matches inside a string
*
* @param string $value The value to parse
*
* @return array The variable matches
*/
private function fetchVariableMatches($value)
{
preg_match_all('/' . self::REGEX_ENV_VARIABLE . '/', $value, $matches);
if (!is_array($matches) || !isset($matches[0]) || empty($matches[0])) {
return false;
}
return $matches;
}
/**
* Parses a .env variable
*
* @param string $value The value to parse
* @param string $variable_name The variable name to get
* @param array $matches The matches of the variables
* @param bool $quoted_string Is the value in a quoted string
*
* @return string The parsed value
* @throws \M1\Env\Exception\ParseException If the variable can not be found
*/
private function fetchVariable($value, $variable_name, $matches, $quoted_string)
{
if ($this->hasParameterExpansion($variable_name)) {
$replacement = $this->fetchParameterExpansion($variable_name);
} elseif ($this->hasVariable($variable_name)) {
$replacement = $this->getVariable($variable_name);
} else {
throw new ParseException(
sprintf('Variable has not been defined: %s', $variable_name),
$value,
$this->parser->line_num
);
}
if ($this->parser->string_helper->isBoolInString($replacement, $quoted_string, count($matches[0]))) {
$replacement = ($replacement) ? 'true' : 'false';
}
return $replacement;
}
/**
* Checks to see if the variable has a parameter expansion
*
* @param string $variable The variable to check
*
* @return bool Does the variable have a parameter expansion
*/
private function hasParameterExpansion($variable)
{
if ((strpos($variable, self::SYMBOL_DEFAULT_VALUE) !== false) ||
(strpos($variable, self::SYMBOL_ASSIGN_DEFAULT_VALUE) !== false)
) {
return true;
}
return false;
}
/**
* Fetches and sets the parameter expansion
*
* @param string $variable_name The parameter expansion inside this to fetch
*
* @return string The parsed value
*/
private function fetchParameterExpansion($variable_name)
{
$parameter_type = $this->fetchParameterExpansionType($variable_name);
list($parameter_symbol, $empty_flag) = $this->fetchParameterExpansionSymbol($variable_name, $parameter_type);
list($variable, $default) = $this->splitVariableDefault($variable_name, $parameter_symbol);
$value = $this->getVariable($variable);
return $this->parseVariableParameter(
$variable,
$default,
$this->hasVariable($variable),
$empty_flag && empty($value),
$parameter_type
);
}
/**
* Fetches the parameter expansion type
*
* @param string $variable_name The parameter expansion type to get from this
*
* @return string The parameter expansion type
*/
private function fetchParameterExpansionType($variable_name)
{
if (strpos($variable_name, self::SYMBOL_ASSIGN_DEFAULT_VALUE) !== false) {
return 'assign_default_value';
}
return 'default_value'; // self::DEFAULT_VALUE_SYMBOL
}
/**
* Fetches the parameter type symbol
*
* @param string $variable_name The variable
* @param string $type The type of parameter expansion
*
* @return array The symbol and if there is a empty check
*/
private function fetchParameterExpansionSymbol($variable_name, $type)
{
$class = new \ReflectionClass($this);
$symbol = $class->getConstant('SYMBOL_'.strtoupper($type));
$pos = strpos($variable_name, $symbol);
$check_empty = substr($variable_name, ($pos - 1), 1) === ":";
if ($check_empty) {
$symbol = sprintf(":%s", $symbol);
}
return array($symbol, $check_empty);
}
/**
* Splits the parameter expansion into variable and default
*
* @param string $variable_name The variable name to split
* @param string $parameter_symbol The parameter expansion symbol
*
* @throws \M1\Env\Exception\ParseException If the parameter expansion if not valid syntax
*
* @return array The split variable and default value
*/
private function splitVariableDefault($variable_name, $parameter_symbol)
{
$variable_default = explode($parameter_symbol, $variable_name, 2);
if (count($variable_default) !== 2 || empty($variable_default[1])) {
throw new ParseException(
'You must have valid parameter expansion syntax, eg. ${parameter:=word}',
$variable_name,
$this->parser->line_num
);
}
return array(trim($variable_default[0]), trim($variable_default[1]));
}
/**
* Parses and sets the variable and default if needed
*
* @param string $variable The variable to parse
* @param string $default The default value
* @param bool $exists Does the variable exist
* @param bool $empty Is there the variable empty if exists and the empty flag is set
* @param string $type The type of parameter expansion
*
* @return string The parsed value
*/
private function parseVariableParameter($variable, $default, $exists, $empty, $type)
{
if ($exists && !$empty) {
return $this->getVariable($variable);
}
return $this->assignVariableParameterDefault($variable, $default, $empty, $type);
}
/**
* Parses and sets the variable parameter to default
*
* @param string $variable The variable to parse
* @param string $default The default value
* @param bool $empty Is there the variable empty if exists and the empty flag is set
* @param string $type The type of parameter expansion
*
* @return string The parsed default value
*/
private function assignVariableParameterDefault($variable, $default, $empty, $type)
{
$default = $this->parser->value_parser->parse($default);
if ($type === "assign_default_value" && $empty) {
$this->parser->lines[$variable] = $default;
}
return $default;
}
/**
* Checks to see if a variable exists
*
* @param string $variable The variable name to get
*
* @return bool
*/
private function hasVariable($variable)
{
if (array_key_exists($variable, $this->parser->lines)) {
return true;
}
if (array_key_exists($variable, $this->context)) {
return true;
}
return false;
}
/**
* Get variable value
*
* @param string $variable
*
* @return mixed
*/
private function getVariable($variable)
{
if (array_key_exists($variable, $this->parser->lines)) {
return $this->parser->lines[$variable];
}
if (array_key_exists($variable, $this->context)) {
return $this->context[$variable];
}
return null;
}
/**
* Do the variable replacements
*
* @param string $value The value to throw an error with if doesn't exist
* @param array $matches The matches of the variables
* @param bool $quoted_string Is the value in a quoted string
*
* @return string The parsed value
*/
public function doReplacements($value, $matches, $quoted_string)
{
$replacements = array();
for ($i = 0; $i <= (count($matches[0]) - 1); $i++) {
$replacement = $this->fetchVariable($value, $matches[1][$i], $matches, $quoted_string);
$replacements[$matches[0][$i]] = $replacement;
}
if (!empty($replacements)) {
$value = strtr($value, $replacements);
}
return $value;
}
}