Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert array to an .ini file

Tags:

arrays

php

ini

I need to parse an .ini file into an array, and later change the values of the array and export it to the same .ini file. I managed to read the file, but didn’t find any simple way to write it back. Any suggestions?

Sample .ini file:

1 = 0;
2 = 1372240157;    // timestamp.
like image 794
user2216190 Avatar asked Jun 26 '13 09:06

user2216190


3 Answers

In order to write the .ini file back, you need to create your own function, for PHP offers no functions out of the box other than for reading (which can be found here: http://php.net/manual/pl/function.parse-ini-file.php).

An example of function that might encapsulate a multidimensional array to .ini-syntax compatible string might look like this:

function arr2ini(array $a, array $parent = array())
{
    $out = '';
    foreach ($a as $k => $v)
    {
        if (is_array($v))
        {
            //subsection case
            //merge all the sections into one array...
            $sec = array_merge((array) $parent, (array) $k);
            //add section information to the output
            $out .= '[' . join('.', $sec) . ']' . PHP_EOL;
            //recursively traverse deeper
            $out .= arr2ini($v, $sec);
        }
        else
        {
            //plain key->value case
            $out .= "$k=$v" . PHP_EOL;
        }
    }
    return $out;
}

You can test it like this:

$x = [
  'section1' => [
    'key1' => 'value1',
    'key2' => 'value2',
    'subsection' => [
      'subkey' => 'subvalue',
      'further' => ['a' => 5],
      'further2' => ['b' => -5]]]];
echo arr2ini($x);

(Note that short array syntax is available only since PHP 5.4+.)

Also note that it doesn't preserve the comments that were present in your question. There are no easy ways to remember them, when it is software (as opposed to a human) that updates the file back.

like image 100
rr- Avatar answered Nov 05 '22 01:11

rr-


I've made significant changes to the function provided by rr- (many thanks for the kick-start!)

I was unhappy with the way multidimensional properties are handled in that version. I took the example ini file from the php documentation page for parse_ini_file and got a result which included the keys third_section.phpversion and third_section.urls - not what I expected.

I tried using a RecursiveArrayIterator for unlimited nesting, but unfortunately, a header with key-value pairs under it is the maximum limit of recursion that parse_ini_string will process before choking on an error message.

So I started from scratch, added some curveballs as the fourth and last items, and ended up with this:

$test = array(
    'first_section' => array(
        'one' => 1,
        'five' => 5,
        'animal' => "Dodo bird",
    ),
    'second_section' => array(
        'path' => "/usr/local/bin",
        'URL' => "http://www.example.com/username",
    ),

    'third_section' => array(
        'phpversion' => array(5.0, 5.1, 5.2, 5.3),
        'urls' => array(
            'svn' => "http://svn.php.net",
            'git' => "http://git.php.net",
        ),
    ),

    'fourth_section' => array(
        7.0, 7.1, 7.2, 7.3,
    ),
    'last_item' => 23,
);
echo '<pre>';
print_r($test);
echo '<hr>';
$ini = build_ini_string($test);
echo $ini;
echo '<hr>';
print_r( parse_ini_string($ini, true) );

function build_ini_string(array $a) {
    $out = '';
    $sectionless = '';
    foreach($a as $rootkey => $rootvalue){
        if(is_array($rootvalue)){
            // find out if the root-level item is an indexed or associative array
            $indexed_root = array_keys($rootvalue) == range(0, count($rootvalue) - 1);
            // associative arrays at the root level have a section heading
            if(!$indexed_root) $out .= PHP_EOL."[$rootkey]".PHP_EOL;
            // loop through items under a section heading
            foreach($rootvalue as $key => $value){
                if(is_array($value)){
                    // indexed arrays under a section heading will have their key omitted
                    $indexed_item = array_keys($value) == range(0, count($value) - 1);
                    foreach($value as $subkey=>$subvalue){
                        // omit subkey for indexed arrays
                        if($indexed_item) $subkey = "";
                        // add this line under the section heading
                        $out .= "{$key}[$subkey] = $subvalue" . PHP_EOL;
                    }
                }else{
                    if($indexed_root){
                        // root level indexed array becomes sectionless
                        $sectionless .= "{$rootkey}[] = $value" . PHP_EOL;
                    }else{
                        // plain values within root level sections
                        $out .= "$key = $value" . PHP_EOL;
                    }
                }
            }

        }else{
            // root level sectionless values
            $sectionless .= "$rootkey = $rootvalue" . PHP_EOL;
        }
    }
    return $sectionless.$out;
}

My input and output arrays match (functionally, anyway) and my ini file looks like this:

fourth_section[] = 7
fourth_section[] = 7.1
fourth_section[] = 7.2
fourth_section[] = 7.3
last_item = 23

[first_section]
one = 1
five = 5
animal = Dodo bird

[second_section]
path = /usr/local/bin
URL = http://www.example.com/username

[third_section]
phpversion[] = 5
phpversion[] = 5.1
phpversion[] = 5.2
phpversion[] = 5.3
urls[svn] = http://svn.php.net
urls[git] = http://git.php.net

I know it may be a little overkill, but I really needed this function in two of my own projects. Now I can read an ini file, make changes and save it.

like image 3
vahanpwns Avatar answered Nov 05 '22 02:11

vahanpwns


The answer by RR works and I added one change

in else statement

//plain key->value case
$out .= "$k=$v" . PHP_EOL;

change it to

//plain key->value case
$out .= "$k=\"$v\"" . PHP_EOL;

By having " around the value, you can have larges values in the INI otherwise parse_ini_* functions will have an issue

http://missioncriticallabs.com/blog/2009/08/double-quotation-marks-in-php-ini-files/

like image 1
Suhas Pharkute Avatar answered Nov 05 '22 01:11

Suhas Pharkute