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.