【问题标题】:Convert array to an .ini file将数组转换为 .ini 文件
【发布时间】:2013-06-23 09:41:00
【问题描述】:

我需要将.ini 文件解析为一个数组,然后更改数组的值并将其导出到同一个.ini 文件。 我设法读取了该文件,但没有找到任何简单的方法将其写回。 有什么建议吗?

示例.ini 文件:

1 = 0;
2 = 1372240157;    // timestamp.

【问题讨论】:

  • 用json不是更好吗?
  • 取决于应用程序罗伯特。如果数据打算在没有人工交互的情况下存储和检索,或者通过网络传输(ajax 等),那么 json 是合适的。如果数据偶尔需要由可能是开发人员也可能不是开发人员的人手动编辑,则将其采用更具可读性的 .ini 格式是合适的。还应该提到的是,.ini 文件实际上比 php 文件解析得更快。

标签: php arrays ini


【解决方案1】:

这是我对rr- 的增强版答案(感谢他),我的函数是 生态系统中类的一部分,因此使用了一个名为 Arr::isAssoc 的函数这基本上是检测给定数组是否为关联数组。


  private function arrayToConfig(array $array, array $parent = []): string
  {
    $returnValue = '';

    foreach ($array as $key => $value)
      {
        if (is_array($value)) // Subsection case
          {
            // Merge all the sections into one array
            if (is_int($key)) $key++;
            $subSection = array_merge($parent, (array)$key);
            // Add section information to the output
            if (Arr::isAssoc($value))
              {
                if (count($subSection) > 1) $returnValue .= PHP_EOL;
                $returnValue .= '[' . implode(':', $subSection) . ']' . PHP_EOL;
              }
            // Recursively traverse deeper
            $returnValue .= $this->arrayToConfig($value, $subSection);
            $returnValue .= PHP_EOL;
          }
        elseif (isset($value)) $returnValue .= "$key=" . (is_bool($value) ? var_export($value, true) : $value) . PHP_EOL; // Plain key->value case
      }

    return count($parent) ? $returnValue : rtrim($returnValue) . PHP_EOL;
  }

【讨论】:

    【解决方案2】:

    我对@9​​87654321@ 提供的功能进行了重大更改(非常感谢您的启动!)

    我对该版本中处理多维属性的方式不满意。我从 parse_ini_file 的 php 文档页面中获取了示例 ini 文件,并得到了一个包含键 third_section.phpversionthird_section.urls 的结果——这不是我所期望的。

    我尝试使用RecursiveArrayIterator 进行无限嵌套,但不幸的是,带有键值对的标头是parse_ini_string 在收到错误消息之前将处理的最大递归限制。

    所以我从头开始,添加了一些曲线球作为第四个也是最后一个项目,最后得到了这个:

    $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;
    }
    

    我的输入和输出数组匹配(无论如何在功能上),我的 ini 文件如下所示:

    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
    

    我知道这可能有点矫枉过正,但我​​在自己的两个项目中确实需要这个功能。现在我可以读取一个 ini 文件,进行更改并保存它。

    【讨论】:

      【解决方案3】:

      RR 的答案有效,我添加了一个更改

      在其他语句中

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

      改成

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

      通过在值周围加上 ",您可以在 INI 中设置较大的值,否则 parse_ini_* 函数会出现问题

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

      【讨论】:

        【解决方案4】:

        为了写回 .ini 文件,您需要创建自己的函数,因为 PHP 没有提供开箱即用的函数,除了读取(可以在这里找到:http://php.net/manual/pl/function.parse-ini-file.php)。

        可能将多维数组封装为.ini-syntax 兼容字符串的函数示例如下所示:

        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;
        }
        

        你可以这样测试:

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

        (请注意,短数组语法仅在 PHP 5.4+ 之后可用。)

        另请注意,它不会保留您问题中存在的 cmets。当是软件(而不是人类)更新文件时,没有简单的方法来记住它们。

        【讨论】:

        • 谢谢!你能解释一下$out .= "$k=$v" . PHP_EOL;这行吗?
        • 这与一系列串联相同:$out = $out . $k.'='.$v . PHP_EOL;,其中PHP_EOL 是换行符。
        • 为什么要连接点?此功能无法按预期工作
        【解决方案5】:

        使用php内部函数怎么样? http://php.net/manual/en/function.parse-ini-file.php

        【讨论】:

        • 这些函数是解析ini文件或ini格式的字符串,他想将数组导出到ini文件,这些函数不要做
        • @Brewal 来自手册“parse_ini_string() 在关联数组中返回字符串 ini 中的设置。” 他想要相反的行动。他希望将数组中的设置写入 ini。
        • @Robert 你完全理解我。你有什么解决办法吗?
        • @user2216190 - 你期望已经写好的代码?从数组创建ini文件真的不难。即使是初学者也可以在 15 分钟内完成,这太简单了,如果你用谷歌搜索,你可以找到问题的结果(它甚至会引导你到 stackoverflow)。
        • “我需要将一个 .ini 文件读入一个数组”...你至少已经做到了
        猜你喜欢
        • 2012-04-14
        • 2016-06-05
        • 1970-01-01
        • 2020-07-17
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        • 2018-09-29
        相关资源
        最近更新 更多