Added austinhyde\IniParser

This commit is contained in:
Netkas 2022-08-13 14:50:40 -04:00
parent 41fc5604fc
commit dea98c6435
9 changed files with 624 additions and 25 deletions

25
LICENSE
View file

@ -178,3 +178,28 @@ 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.
------------------------
austinhyde - IniParser
The MIT License (MIT)
Copyright (c) 2013 Austin Hyde
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.

View file

@ -6,6 +6,7 @@ autoload:
make src/ncc/ThirdParty/Symfony/Process/autoload_spl.php
make src/ncc/ThirdParty/Symfony/Uid/autoload_spl.php
make src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php
make src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php
make src/ncc/autoload_spl.php
cp src/autoload/autoload.php src/ncc/autoload.php
@ -33,6 +34,10 @@ src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php:
/usr/bin/env phpab --output src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php \
src/ncc/ThirdParty/Symfony/Filesystem
src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php:
/usr/bin/env phpab --output src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php \
src/ncc/ThirdParty/austinhyde/IniParser
src/ncc/autoload_spl.php:
/usr/bin/env phpab --output src/ncc/autoload_spl.php \
src/ncc/Abstracts \
@ -70,4 +75,5 @@ clean:
rm -f src/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php
rm -f src/ncc/ThirdParty/Symfony/Process/autoload_spl.php
rm -f src/ncc/ThirdParty/Symfony/Uid/autoload_spl.php
rm -f src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php
rm -f src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php
rm -f src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php

View file

@ -30,6 +30,7 @@ a PPM extension may be built in the future to allow for backwards compatibility.
- Copyright (c) 2022-2022, Nosial - All Rights Reserved
- Copyright (c) 2004-2022, Fabien Potencier
- Copyright (c) 2010, dealnews.com, Inc. All rights reserved.
- Copyright (c) 2013 Austin Hyde
# Licenses

View file

@ -21,6 +21,7 @@
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Process' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Uid' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Filesystem' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'austinhyde' . DIRECTORY_SEPARATOR . 'IniParser' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
];
foreach($target_files as $file)

View file

@ -1,42 +1,42 @@
[ncc]
# The default data directory that is used by NCC to store packages,
# cache, configuration files and other generated files. This includes
# data stored by packages using the NCC storage API.
; The default data directory that is used by NCC to store packages,
; cache, configuration files and other generated files. This includes
; data stored by packages using the NCC storage API.
data_directory=/var/ncc
[php]
# Configuration section for the PHP configuration that NCC will use to run
; Configuration section for the PHP configuration that NCC will use to run
# The main executable path for PHP that NCC should use
; The main executable path for PHP that NCC should use
executable_path=/usr/bin/php
# Enables/Disables the environment configuration feature
# Allowing packages to install environment configurations to NCC
# that can be loaded during runtime using the NCC API
#
# If disabled packages may break if they depend on this feature.
#
# Leaving this enabled while installing and using unknown packages
# without reviewing their source code could lead to potential security
# issues/backdoors, use this feature for containerized environments
; Enables/Disables the environment configuration feature
; Allowing packages to install environment configurations to NCC
; that can be loaded during runtime using the NCC API
;
; If disabled packages may break if they depend on this feature.
;
; Leaving this enabled while installing and using unknown packages
; without reviewing their source code could lead to potential security
; issues/backdoors, use this feature for containerized environments
enable_environment_configurations=False
# Enables/Disables the injection of NCC's include path
# during the initialization phase allowing you to import
# packages using the `import()` function and other ncc
# API Functions without needing to require NCC's autoloader
#
# This feature is highly recommended to be enabled
; Enables/Disables the injection of NCC's include path
; during the initialization phase allowing you to import
; packages using the `import()` function and other ncc
; API Functions without needing to require NCC's autoloader
;
; This feature is highly recommended to be enabled
enable_include_path=True
[git]
executable_path=/usr/bin/git
[composer]
# When enabled, NCC will use it's builtin version of composer
# to execute composer tasks, if disabled it will fallback to
# the `executable_path` option and attempt to use that specified
# location of composer
; When enabled, NCC will use it's builtin version of composer
; to execute composer tasks, if disabled it will fallback to
; the `executable_path` option and attempt to use that specified
; location of composer
enable_internal_composer=True
executable_path=/home/user/composer.phar

View file

@ -0,0 +1,16 @@
<?php
namespace ncc\Managers;
class ConfigurationManager
{
/**
* Public Constructor
*
* @param string $package
*/
public function __construct(string $package)
{
$this->Package = $package;
}
}

View file

@ -0,0 +1,282 @@
<?php
namespace ncc\ThirdParty\austinhyde\IniParser;
/**
* [MIT Licensed](http://www.opensource.org/licenses/mit-license.php)
* Copyright (c) 2013 Austin Hyde
*
* Implements a parser for INI files that supports
* * Section inheritance
* * Property nesting
* * Simple arrays
*
* Compatible with PHP 5.2.0+
*
* @author Austin Hyde
* @author Till Klampaeckel <till@php.net>
*/
class IniParser
{
/**
* Filename of our .ini file.
* @var string
*/
protected $file;
/**
* Enable/disable property nesting feature
* @var boolean
*/
public $property_nesting = true;
/**
* Use ArrayObject to allow array work as object (true) or use native arrays (false)
* @var boolean
*/
public $use_array_object = true;
/**
* Include original sections (pre-inherit names) on the final output
* @var boolean
*/
public $include_original_sections = false;
/**
* Disable array literal parsing
*/
const NO_PARSE = 0;
/**
* Parse simple arrays using regex (ex: [a,b,c,...])
*/
const PARSE_SIMPLE = 1;
/**
* Parse array literals using JSON, allowing advanced features like
* dictionaries, array nesting, etc.
*/
const PARSE_JSON = 2;
/**
* Array literals parse mode
* @var int
*/
public $array_literals_behavior = self::PARSE_SIMPLE;
/**
* @param string $file
*
* @return IniParser
*/
public function __construct($file = null)
{
if ($file !== null) {
$this->setFile($file);
}
}
/**
* Parses an INI file
*
* @param string $file
* @return array
*/
public function parse($file = null)
{
if ($file !== null) {
$this->setFile($file);
}
if (empty($this->file)) {
throw new LogicException("Need a file to parse.");
}
$simple_parsed = parse_ini_file($this->file, true);
$inheritance_parsed = $this->parseSections($simple_parsed);
return $this->parseKeys($inheritance_parsed);
}
/**
* Parses a string with INI contents
*
* @param string $src
*
* @return array
*/
public function process($src)
{
$simple_parsed = parse_ini_string($src, true);
$inheritance_parsed = $this->parseSections($simple_parsed);
return $this->parseKeys($inheritance_parsed);
}
/**
* @param string $file
*
* @return IniParser
* @throws InvalidArgumentException
*/
public function setFile($file)
{
if (!file_exists($file) || !is_readable($file)) {
throw new InvalidArgumentException("The file '{$file}' cannot be opened.");
}
$this->file = $file;
return $this;
}
/**
* Parse sections and inheritance.
* @param array $simple_parsed
* @return array Parsed sections
*/
private function parseSections(array $simple_parsed)
{
// do an initial pass to gather section names
$sections = array();
$globals = array();
foreach ($simple_parsed as $k => $v) {
if (is_array($v)) {
// $k is a section name
$sections[$k] = $v;
} else {
$globals[$k] = $v;
}
}
// now for each section, see if it uses inheritance
$output_sections = array();
foreach ($sections as $k => $v) {
$sects = array_map('trim', array_reverse(explode(':', $k)));
$root = array_pop($sects);
$arr = $v;
foreach ($sects as $s) {
if ($s === '^') {
$arr = array_merge($globals, $arr);
} elseif (array_key_exists($s, $output_sections)) {
$arr = array_merge($output_sections[$s], $arr);
} elseif (array_key_exists($s, $sections)) {
$arr = array_merge($sections[$s], $arr);
} else {
throw new UnexpectedValueException("IniParser: In file '{$this->file}', section '{$root}': Cannot inherit from unknown section '{$s}'");
}
}
if ($this->include_original_sections) {
$output_sections[$k] = $v;
}
$output_sections[$root] = $arr;
}
return $globals + $output_sections;
}
/**
* @param array $arr
*
* @return array
*/
private function parseKeys(array $arr)
{
$output = $this->getArrayValue();
$append_regex = '/\s*\+\s*$/';
foreach ($arr as $k => $v) {
if (is_array($v) && FALSE === strpos($k, '.')) {
// this element represents a section; recursively parse the value
$output[$k] = $this->parseKeys($v);
} else {
// if the key ends in a +, it means we should append to the previous value, if applicable
$append = false;
if (preg_match($append_regex, $k)) {
$k = preg_replace($append_regex, '', $k);
$append = true;
}
// transform "a.b.c = x" into $output[a][b][c] = x
$current = &$output;
$path = $this->property_nesting ? explode('.', $k) : array($k);
while (($current_key = array_shift($path)) !== null) {
if ('string' === gettype($current)) {
$current = array($current);
}
if (!array_key_exists($current_key, $current)) {
if (!empty($path)) {
$current[$current_key] = $this->getArrayValue();
} else {
$current[$current_key] = null;
}
}
$current = &$current[$current_key];
}
// parse value
$value = $v;
if (!is_array($v)) {
$value = $this->parseValue($v);
}
if ($append && $current !== null) {
if (is_array($value)) {
if (!is_array($current)) {
throw new LogicException("Cannot append array to inherited value '{$k}'");
}
$value = array_merge($current, $value);
} else {
$value = $current . $value;
}
}
$current = $value;
}
}
return $output;
}
/**
* Parses and formats the value in a key-value pair
*
* @param string $value
*
* @return mixed
*/
protected function parseValue($value)
{
switch ($this->array_literals_behavior) {
case self::PARSE_JSON:
if (in_array(substr($value, 0, 1), array('[', '{')) && in_array(substr($value, -1), array(']', '}'))) {
if (defined('JSON_BIGINT_AS_STRING')) {
$output = json_decode($value, true, 512, JSON_BIGINT_AS_STRING);
} else {
$output = json_decode($value, true);
}
if ($output !== NULL) {
return $output;
}
}
// fallthrough
// try regex parser for simple estructures not JSON-compatible (ex: colors = [blue, green, red])
case self::PARSE_SIMPLE:
// if the value looks like [a,b,c,...], interpret as array
if (preg_match('/^\[\s*.*?(?:\s*,\s*.*?)*\s*\]$/', trim($value))) {
return array_map('trim', explode(',', trim(trim($value), '[]')));
}
break;
}
return $value;
}
protected function getArrayValue($array = array())
{
if ($this->use_array_object) {
return new ArrayObject($array, ArrayObject::ARRAY_AS_PROPS);
} else {
return $array;
}
}
}

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Austin Hyde
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.

View file

@ -0,0 +1,247 @@
# IniParser
[![Build Status](https://secure.travis-ci.org/austinhyde/IniParser.png?branch=master)](http://travis-ci.org/austinhyde/IniParser)
IniParser is a simple parser for complex INI files, providing a number of extra syntactic features to the built-in INI parsing functions, including section inheritance, property nesting, and array literals.
**IMPORTANT:** IniParser should be considered beta-quality, and there may still be bugs. Feel free to open an issue or submit a pull request, and I'll take a look at it!
## Installing by [Composer](https://getcomposer.org)
Set your `composer.json` file to have :
```json
{
"require": {
"austinhyde/iniparser": "dev-master"
}
}
```
Then install the dependencies :
```shell
composer install
```
## An Example
Standard INI files look like this:
key = value
another_key = another value
[section_name]
a_sub_key = yet another value
And when parsed with PHP's built-in `parse_ini_string()` or `parse_ini_file()`, looks like
```php
array(
'key' => 'value',
'another_key' => 'another value',
'section_name' => array(
'a_sub_key' => 'yet another value'
)
)
```
This is great when you just want a simple configuration file, but here is a super-charged INI file that you might find in the wild:
environment = testing
[testing]
debug = true
database.connection = "mysql:host=127.0.0.1"
database.name = test
database.username =
database.password =
secrets = [1,2,3]
[staging : testing]
database.name = stage
database.username = staging
database.password = 12345
[production : staging]
debug = false;
database.name = production
database.username = root
And when parsed with IniParser:
$parser = new \IniParser('sample.ini');
$config = $parser->parse();
You get the following structure:
```php
array(
'environment' => 'testing',
'testing' => array(
'debug' => '1',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'test',
'username' => '',
'password' => ''
),
'secrets' => array('1','2','3')
),
'staging' => array(
'debug' => '1',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'stage',
'username' => 'staging',
'password' => '12345'
),
'secrets' => array('1','2','3')
),
'production' => array(
'debug' => '',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'production',
'username' => 'root',
'password' => '12345'
),
'secrets' => array('1','2','3')
)
)
```
## Supported Features
### Array Literals
You can directly create arrays using the syntax `[a, b, c]` on the right hand side of an assignment. For example:
colors = [blue, green, red]
**NOTE:** At the moment, quoted strings inside array literals have undefined behavior.
### Dictionaries and complex structures
Besides arrays, you can create dictionaries and more complex structures using JSON syntax. For example, you can use:
people = '{
"boss": {
"name": "John",
"age": 42
},
"staff": [
{
"name": "Mark",
"age": 35
},
{
"name": "Bill",
"age": 44
}
]
}'
This turns into an array like:
```php
array(
'boss' => array(
'name' => 'John',
'age' => 42
),
'staff' => array(
array (
'name' => 'Mark',
'age' => 35,
),
array (
'name' => 'Bill',
'age' => 44,
),
),
)
```
**NOTE:** Remember to wrap the JSON strings in single quotes for a correct analysis. The JSON names must be enclosed in double quotes and trailing commas are not allowed.
### Property Nesting
IniParser allows you to treat properties as associative arrays:
person.age = 42
person.name.first = John
person.name.last = Doe
This turns into an array like:
```php
array (
'person' => array (
'age' => 42,
'name' => array (
'first' => 'John',
'last' => 'Doe'
)
)
)
```
### Section Inheritance
Keeping to the DRY principle, IniParser allows you to "inherit" from other sections (similar to OOP inheritance), meaning you don't have to continually re-define the same properties over and over again. As you can see in the example above, "production" inherits from "staging", which in turn inherits from "testing".
You can even inherit from multiple parents, as in `[child : p1 : p2 : p3]`. The properties of each parent are merged into the child from left to right, so that the properties in `p1` are overridden by those in `p2`, then by `p3`, then by those in `child` on top of that.
During the inheritance process, if a key ends in a `+`, the merge behavior changes from overwriting the parent value to prepending the parent value (or appending the child value - same thing). So the example file
[parent]
arr = [a,b,c]
val = foo
[child : parent]
arr += [x,y,z]
val += bar
would be parsed into the following:
```php
array(
'parent' => array(
'arr' => array('a','b','c'),
'val' => 'foo'
),
'child' => array(
'arr' => array('a','b','c','x','y','z'),
'val' => 'foobar'
)
)
```
*If you can think of a more useful operation than concatenation for non-array types, please open an issue*
Finally, it is possible to inherit from the special `^` section, representing the top-level or global properties:
foo = bar
[sect : ^]
Parses to:
```php
array (
'foo' => 'bar',
'sect' => array (
'foo' => 'bar'
)
)
```
### ArrayObject
As an added bonus, IniParser also allows you to access the values OO-style:
```php
echo $config->production->database->connection; // output: mysql:host=127.0.0.1
echo $config->staging->debug; // output: 1
```