Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 107 additions & 79 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ IniParser is a simple parser for complex INI files, providing a number of extra

**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:
Expand All @@ -18,13 +36,15 @@ Standard INI files look like this:

And when parsed with PHP's built-in `parse_ini_string()` or `parse_ini_file()`, looks like

array(
'key' => 'value',
'another_key' => 'another value',
'section_name' => array(
'a_sub_key' => 'yet another value'
)
```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:

Expand Down Expand Up @@ -55,39 +75,41 @@ And when parsed with IniParser:

You get the following structure:

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')
```php
array(
'environment' => 'testing',
'testing' => array(
'debug' => '1',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'test',
'username' => '',
'password' => ''
),
'staging' => array(
'debug' => '1',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'stage',
'username' => 'staging',
'password' => '12345'
),
'secrets' => array('1','2','3')
'secrets' => array('1','2','3')
),
'staging' => array(
'debug' => '1',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'stage',
'username' => 'staging',
'password' => '12345'
),
'production' => array(
'debug' => '',
'database' => array(
'connection' => 'mysql:host=127.0.0.1',
'name' => 'production',
'username' => 'root',
'password' => '12345'
),
'secrets' => array('1','2','3')
)
'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

Expand Down Expand Up @@ -122,26 +144,24 @@ Besides arrays, you can create dictionaries and more complex structures using JS

This turns into an array like:

array (
'boss' =>
array (
'name' => 'John',
'age' => 42,
),
'staff' =>
array (
0 =>
array (
'name' => 'Mark',
'age' => 35,
),
1 =>
array (
'name' => 'Bill',
'age' => 44,
),
),
);
```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.

Expand All @@ -155,15 +175,17 @@ IniParser allows you to treat properties as associative arrays:

This turns into an array like:

array (
'person' => array (
'age' => 42,
'name' => array (
'first' => 'John',
'last' => 'Doe'
)
```php
array (
'person' => array (
'age' => 42,
'name' => array (
'first' => 'John',
'last' => 'Doe'
)
)
)
```

### Section Inheritance

Expand All @@ -183,16 +205,18 @@ During the inheritance process, if a key ends in a `+`, the merge behavior chang

would be parsed into the following:

array (
'parent' => array (
'arr' => array('a','b','c'),
'val' => 'foo'
),
'child' => array (
'arr' => array('a','b','c','x','y','z'),
'val' => 'foobar'
)
```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*

Expand All @@ -204,16 +228,20 @@ Finally, it is possible to inherit from the special `^` section, representing th

Parses to:

array (
'foo' => 'bar',
'sect' => array (
'foo' => 'bar'
)
```php
array (
'foo' => 'bar',
'sect' => array (
'foo' => 'bar'
)
)
```

### ArrayObject

As an added bonus, IniParser also allows you to access the values OO-style:

echo $config->production->database->connection; // output: mysql:host=127.0.0.1
echo $config->staging->debug; // output: 1
```php
echo $config->production->database->connection; // output: mysql:host=127.0.0.1
echo $config->staging->debug; // output: 1
```
40 changes: 33 additions & 7 deletions src/IniParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ class IniParser {
*/
public $include_original_sections = false;

/**
* Parse C-like delimiters in strings (\r\n\t)
* @var boolean
*/
public $parse_delimiters = true;

/**
* Disable array literal parsing
*/
Expand All @@ -60,7 +66,7 @@ class IniParser {
* Array literals parse mode
* @var int
*/
public $array_literals_behaviour = self::PARSE_JSON;
public $array_literals_behavior = self::PARSE_SIMPLE;

/**
* @param string $file
Expand Down Expand Up @@ -174,7 +180,7 @@ private function parseKeys(array $arr) {
$output = $this->getArrayValue();
$append_regex = '/\s*\+\s*$/';
foreach ($arr as $k => $v) {
if (is_array($v)) {
if (is_array($v) && FALSE === strpos($k, '.')) {
// this element represents a section; recursively parse the value
$output[$k] = $this->parseKeys($v);
} else {
Expand Down Expand Up @@ -205,7 +211,10 @@ private function parseKeys(array $arr) {
}

// parse value
$value = $this->parseValue($v);
$value = $v;
if (!is_array($v)) {
$value = $this->parseValue($v);
}

if ($append && $current !== null) {
if (is_array($value)) {
Expand All @@ -225,6 +234,20 @@ private function parseKeys(array $arr) {
return $output;
}

/**
* Callback for replace delimiters regex
* @param array $matches
* @return string
*/
protected function replaceDelimiter($matches) {
switch ($matches[0]) {
case '\\n':return "\n";
case '\\t':return "\t";
case '\\r':return "\r";
default:return $matches[0];
}
}

/**
* Parses and formats the value in a key-value pair
*
Expand All @@ -233,7 +256,11 @@ private function parseKeys(array $arr) {
* @return mixed
*/
protected function parseValue($value) {
switch ($this->array_literals_behaviour) {
if ($this->parse_delimiters && !is_numeric($value)) {//parse_ini_string treats all values as strings, even numeric ones
$value = preg_replace_callback('/(?<!\\\\)\\\\[rnt]/', array($this, 'replaceDelimiter'), $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')) {
Expand All @@ -246,9 +273,8 @@ protected function parseValue($value) {
return $output;
}
}
//try regex parser for simple estructures not JSON-compatible (ex: colors = [blue, green, red])


// 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))) {
Expand Down
Loading