Using the TOML configuration format in your applications

As any one who has programmed knows about configuration files. Configuration files are mostly text files used to configure the parameters and initial settings for computer programs – mostly user applications, operating system settings. Below is a small list of frequently used file formats.

– XML
– Windows INI
– YAML
– JSON
– toml

In this post we will look into parsing TOML files in PHP. TOML is a configuration file format that is intended to be easy to read due to its obvious semantics and is designed to map unambiguously to a dictionary data structure. “TOML”, the name, is an acronym for “Tom’s Obvious, Minimal Language” referring to its creator Tom Preston-Werner.

TOML’s syntax largely consists of key = “value” pairs, [section names], and #comments. It specifies a list of various data types: String, Integer, Float, Boolean, Datetime, Array, and Table. An example TOML file is shown below.

# This is a TOML document.

title = "TOML Example"
 
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates

[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
 
[servers]
 
  # Indentation (tabs and/or spaces) is allowed but not required
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"
 
  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"
 
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
 
# Line breaks are OK when inside arrays
hosts = [
  "alpha",
  "omega"
]

Installing TOML PHP library

Note that this requires PHP >= 7.1.

composer require yosymfony/toml

Reading TOML files

Below is a simple example to parse a inline TOML string and print as an array.

use Yosymfony\Toml\Toml;
require __DIR__ . '/vendor/autoload.php';
 
$array = Toml::Parse('key = [1,2,3]');
print_r($array);
 
/* output
 
Array
(
    [key] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )
 
)
*/

To parse a TOML file instead use the following:

$array = Toml::ParseFile('example.toml');
print_r($array);

After parsing the example text given at the start of the post and printing it gives the following.

Array
(
    [title] => TOML Example
    [owner] => Array
        (
            [name] => Tom Preston-Werner
            [dob] => DateTime Object
                (
                    [date] => 1979-05-27 07:32:00.000000
                    [timezone_type] => 1
                    [timezone] => -08:00
                )
 
        )
 
    [database] => Array
        (
            [server] => 192.168.1.1
            [ports] => Array
                (
                    [0] => 8001
                    [1] => 8001
                    [2] => 8002
                )
 
            [connection_max] => 5000
            [enabled] => 1
        )
 
    [servers] => Array
        (
            [alpha] => Array
                (
                    [ip] => 10.0.0.1
                    [dc] => eqdc10
                )
 
            [beta] => Array
                (
                    [ip] => 10.0.0.2
                    [dc] => eqdc10
                )
 
        )
 
    [clients] => Array
        (
            [data] => Array
                (
                    [0] => Array
                        (
                            [0] => gamma
                            [1] => delta
                        )
 
                    [1] => Array
                        (
                            [0] => 1
                            [1] => 2
                        )
 
                )
 
            [hosts] => Array
                (
                    [0] => alpha
                    [1] => omega
                )
 
        )
 
)

Doing a var dump instead returns the following, which includes the datatype of the strings.

array(5) {
  ["title"]=>
  string(12) "TOML Example"
  ["owner"]=>
  array(2) {
    ["name"]=>
    string(18) "Tom Preston-Werner"
    ["dob"]=>
    object(DateTime)#240 (3) {
      ["date"]=>
      string(26) "1979-05-27 07:32:00.000000"
      ["timezone_type"]=>
      int(1)
      ["timezone"]=>
      string(6) "-08:00"
    }
  }
  ["database"]=>
  array(4) {
    ["server"]=>
    string(11) "192.168.1.1"
    ["ports"]=>
    array(3) {
      [0]=>
      int(8001)
      [1]=>
      int(8001)
      [2]=>
      int(8002)
    }
    ["connection_max"]=>
    int(5000)
    ["enabled"]=>
    bool(true)
  }
  ["servers"]=>
  array(2) {
    ["alpha"]=>
    array(2) {
      ["ip"]=>
      string(8) "10.0.0.1"
      ["dc"]=>
      string(6) "eqdc10"
    }
    ["beta"]=>
    array(2) {
      ["ip"]=>
      string(8) "10.0.0.2"
      ["dc"]=>
      string(6) "eqdc10"
    }
  }
  ["clients"]=>
  array(2) {
    ["data"]=>
    array(2) {
      [0]=>
      array(2) {
        [0]=>
        string(5) "gamma"
        [1]=>
        string(5) "delta"
      }
      [1]=>
      array(2) {
        [0]=>
        int(1)
        [1]=>
        int(2)
      }
    }
    ["hosts"]=>
    array(2) {
      [0]=>
      string(5) "alpha"
      [1]=>
      string(5) "omega"
    }
  }
}

Writing TOML files

You can also create new TOML files programatically as shown below.

use Yosymfony\Toml\Toml;
use Yosymfony\Toml\TomlBuilder;
 
require __DIR__ . '/vendor/autoload.php';
 
$tb = new TomlBuilder();
 
$result = $tb->addComment('Toml file')
        ->addTable('data.string')
        ->addValue('name', "Toml", 'This is your name')
        ->addValue('newline', "This string has a \n new line character.")
        ->addValue('winPath', "C:\\Users\\nodejs\\templates")
        ->addValue('literal', '@<\i\c*\s*>') // literals starts with '@'.
        ->addValue('unicode', 'unicode character: ' . json_decode('"\u03B4"'))
 
        ->addTable('data.bool')
        ->addValue('t', true)
        ->addValue('f', false)
 
        ->addTable('data.integer')
        ->addValue('positive', 25, 'Comment inline.')
        ->addValue('negative', -25)
 
        ->addTable('data.float')
        ->addValue('positive', 25.25)
        ->addValue('negative', -25.25)
 
        ->addTable('data.datetime')
        ->addValue('datetime', new \Datetime())
 
        ->addComment('Related to arrays')
 
        ->addTable('data.array')
        ->addValue('simple', array(1,2,3))
        ->addValue('multiple', array(
            array(1,2),
            array('abc', 'def'),
            array(1.1, 1.2),
            array(true, false),
            array( new \Datetime()) ))
 
        ->addComment('Array of tables')
 
        ->addArrayOfTable('fruit')                            // Row
            ->addValue('name', 'apple')
            ->addArrayOfTable('fruit.variety')
                ->addValue('name', 'red delicious')
            ->addArrayOfTable('fruit.variety')
                ->addValue('name', 'granny smith')
        ->addArrayOfTable('fruit')                            // Row
            ->addValue('name', 'banana')
            ->addArrayOfTable('fruit.variety')
                ->addValue('name', 'plantain')
 
        ->getTomlString();    // Generate the TOML string
echo $result;

This will return the following which you can than save to a file.

#Toml file
 
[data.string]
name = "Toml" #This is your name
newline = "This string has a \n new line character."
winPath = "C:\\Users\\nodejs\\templates"
literal = '<\i\c*\s*>'
unicode = "unicode character: δ"
 
[data.bool]
t = true
f = false
 
[data.integer]
positive = 25 #Comment inline.
negative = -25
 
[data.float]
positive = 25.25
negative = -25.25
 
[data.datetime]
datetime = 2018-07-31T03:31:40Z
#Related to arrays
 
[data.array]
simple = [1, 2, 3]
multiple = [[1, 2], ["abc", "def"], [1.1, 1.2], [true, false], [2018-07-31T03:31:40Z]]
#Array of tables
 
[[fruit]]
name = "apple"
 
[[fruit.variety]]
name = "red delicious"
 
[[fruit.variety]]
name = "granny smith"
 
[[fruit]]
name = "banana"
 
[[fruit.variety]]
name = "plantain"

As you can see the TOML format can be quite complex and allows nesting of elements and creation of arrays. The availability of datatype for elements adds more power to TOML which is absent in many other formats.

Leave a Reply

Your email address will not be published. Required fields are marked *