Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Parsing INI Files With PHP

PHP

Introduction

Some people like to use .ini files for configuration settings. PHP can parse these ini files with the parse_ini_file function, but unfortunately it's default settings are a bit rubbish and this tutorial will explain why and how to fix it.

Setup

All of the examples here will be using the following example config.ini configuration file.

global_decimal_value = 0.25

[Falses]
false_string = "False"
false_bool = False
false_empty_string = ""
false_int = 0

[Trues]
true_string = "True"
true_bool = True
true_int = 1

As you can see, we have a mixture of decimals/floats, strings, booleans, and integers, as well as two "sections" named "Falses" and "Trues".

Basic Parsing

If you were to use the parse the ini file like so:

$data = parse_ini_file(__DIR__ . '/config.ini');
var_dump($data);

Then you would get the following output:

array(8) {
  ["global_decimal_value"]=>
  string(4) "0.25"
  ["false_string"]=>
  string(5) "False"
  ["false_bool"]=>
  string(0) ""
  ["false_empty_string"]=>
  string(0) ""
  ["false_int"]=>
  string(1) "0"
  ["true_string"]=>
  string(4) "True"
  ["true_bool"]=>
  string(1) "1"
  ["true_int"]=>
  string(1) "1"
}

As you can see, everything has been returned as a string value, and the sectioning has been completely lost.

Restore Sectioning

Luckily, you can easily restore the sectioning, by adding a simple parameter like so (I'm using named parameters to make things straightforward).

$data = parse_ini_file(
    filename: __DIR__ . '/config.ini',
    process_sections: true,
);

var_dump($data);

This will output the following:

array(3) {
  ["global_decimal_value"]=>
  string(4) "0.25"
  ["Falses"]=>
  array(4) {
    ["false_string"]=>
    string(5) "False"
    ["false_bool"]=>
    string(0) ""
    ["false_empty_string"]=>
    string(0) ""
    ["false_int"]=>
    string(1) "0"
  }
  ["Trues"]=>
  array(3) {
    ["true_string"]=>
    string(4) "True"
    ["true_bool"]=>
    string(1) "1"
    ["true_int"]=>
    string(1) "1"
  }
}

As you can see, the global vars are held in name/value pairs without any nesting, and the subsections can be accessed through nested indexed arrays. However, we have still lost all of our typings, such that integers and booleans are returned as strings.

Restore Types

One can optionally specify a scanner_mode which as of PHP 5.6.1 (god help you if you are running a PHP version lower than this), has the INI_SCANNER_TYPED optional value, which will preserve the types.

If you were to run:

$data = parse_ini_file(
    filename: __DIR__ . '/config.ini',
    process_sections: true,
    scanner_mode: INI_SCANNER_TYPED
);

var_dump($data);

Then it would output:

array(3) {
  ["global_decimal_value"]=>
  float(0.25)
  ["Falses"]=>
  array(4) {
    ["false_string"]=>
    string(5) "False"
    ["false_bool"]=>
    bool(false)
    ["false_empty_string"]=>
    string(0) ""
    ["false_int"]=>
    int(0)
  }
  ["Trues"]=>
  array(3) {
    ["true_string"]=>
    string(4) "True"
    ["true_bool"]=>
    bool(true)
    ["true_int"]=>
    int(1)
  }
}

As you can see, all of the types camee through correctly.

Conclusion

Whenever parsing INI files, make sure to remember to specify both the process_sections and scanner_mode optional parameters like so:

parse_ini_file(
    filename: __DIR__ . '/config.ini',
    process_sections: true,
    scanner_mode: INI_SCANNER_TYPED
); 

Frankly, it seems so obvious that I'm amazed their default values are not set to this, but I guess it's to prevent accidentally breaking legacy code with a PHP version update (e.g. backwards compatibility).

References

Last updated: 2nd May 2024
First published: 2nd May 2024