代码之家  ›  专栏  ›  技术社区  ›  Austin Hyde

用PHP解析“高级”INI文件

  •  12
  • Austin Hyde  · 技术社区  · 15 年前

    基本上,我想要一个简单,简单,一个文件的方式来解析一个具有“高级”特性的INI文件,比如节继承和属性嵌套,比如 Zend_Config_Ini .

    例如:

    [foo]
    a = 1
    b.a = 2
    b.b = 3
    b.c = 4
    c = 5
    
    [bar : foo]
    b.b = 17
    c = 42
    

    将解析为

    array(
      'foo'=>array(
        'a'=>'1',
        'b'=>array(
          'a'=>'2',
          'b'=>'3',
          'c'=>'4'
        ),
        'c'=>'5'
      ),
      'bar'=>array(
        'a'=>'1',
        'b'=>array(
          'a'=>'2',
          'b'=>'17',
          'c'=>'4'
        ),
        'c'=>'42'
      )
    )
    

    PHP内置 parse_ini_file

    我的问题是使用 Zend_Config_Ini 我将不得不包括几乎整个Zendëu配置子包,并且是超级膨胀和可配置的。

    有什么问题吗 小的 库是否可用于分析?
    如果没有,是否有 我没看见?

    在我(非常缺乏经验)的眼里,我必须用 解析ini文件 ,然后返回并解析继承,然后遍历每个部分并递归地展开键。。。

    更新 :由于这似乎是一个普遍的问题,我想指出 I have a simple class implementing this on GitHub

    4 回复  |  直到 13 年前
        1
  •  16
  •   bndn Viper_Sb    13 年前

    不确定我是应该编辑旧答案还是添加新答案。

    function parse_ini_advanced($array) {
        $returnArray = array();
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $e = explode(':', $key);
                if (!empty($e[1])) {
                    $x = array();
                    foreach ($e as $tk => $tv) {
                        $x[$tk] = trim($tv);
                    }
                    $x = array_reverse($x, true);
                    foreach ($x as $k => $v) {
                        $c = $x[0];
                        if (empty($returnArray[$c])) {
                            $returnArray[$c] = array();
                        }
                        if (isset($returnArray[$x[1]])) {
                            $returnArray[$c] = array_merge($returnArray[$c], $returnArray[$x[1]]);
                        }
                        if ($k === 0) {
                            $returnArray[$c] = array_merge($returnArray[$c], $array[$key]);
                        }
                    }
                } else {
                    $returnArray[$key] = $array[$key];
                }
            }
        }
        return $returnArray;
    }
    function recursive_parse($array)
    {
        $returnArray = array();
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                if (is_array($value)) {
                    $array[$key] = recursive_parse($value);
                }
                $x = explode('.', $key);
                if (!empty($x[1])) {
                    $x = array_reverse($x, true);
                    if (isset($returnArray[$key])) {
                        unset($returnArray[$key]);
                    }
                    if (!isset($returnArray[$x[0]])) {
                        $returnArray[$x[0]] = array();
                    }
                    $first = true;
                    foreach ($x as $k => $v) {
                        if ($first === true) {
                            $b = $array[$key];
                            $first = false;
                        }
                        $b = array($v => $b);
                    }
                    $returnArray[$x[0]] = array_merge_recursive($returnArray[$x[0]], $b[$x[0]]);
                } else {
                    $returnArray[$key] = $array[$key];
                }
            }
        }
        return $returnArray;
    }
    

    会这样称呼:

    $array = parse_ini_file('test.ini', true);
    $array = recursive_parse(parse_ini_advanced($array));
    

    如果您的配置是:

    [foo]
    a = 1
    b.a = 2
    b.b = 3
    b.c = 4
    c = 5
    
    [bar : foo]
    b.x.c = 33
    b.b = 17
    c = 42
    
    [hot : bar : foo]
    b.a = 83
    b.d = 23
    

    输出应为:

    Array
    (
    [foo] => Array
        (
            [a] => 1
            [b] => Array
                (
                    [a] => 2
                    [b] => 3
                    [c] => 4
                )
    
            [c] => 5
        )
    
    [bar] => Array
        (
            [a] => 1
            [b] => Array
                (
                    [a] => 2
                    [b] => 17
                    [c] => 4
                    [x] => Array
                        (
                            [c] => 33
                        )
    
                )
    
            [c] => 42
        )
    
    [hot] => Array
        (
            [a] => 1
            [b] => Array
                (
                    [a] => 83
                    [b] => 17
                    [c] => 4
                    [x] => Array
                        (
                            [c] => 33
                        )
    
                    [d] => 23
                )
    
            [c] => 42
        )
    )
    
        2
  •  3
  •   Viper_Sb    15 年前

    首先要回答一件事,parse_ini_file()中可以进行属性嵌套,将第二个参数设置为true,即parse_ini_file('test.ini',true);这将给你一个多维数组,即

    Array
    (
        [foo] => Array
            (
                [a] => 1
                [b.a] => 2
                [b.b] => 3
                [b.c] => 4
                [c] => 5
            )
    
        [bar : foo] => Array
            (
                [b.b] => 17
                [c] => 42
            )
    )
    

    下面是一个小函数,它将解析parse\u ini\u file()返回的数组并将其转换为类别。

    /**
     * Parse INI files Advanced
     * process_sections = true
     * scanner_mode = default
     * 
     * Supports section inheritance
     * and has property nesting turned on
     * 
     * @param string $filename
     * return array
     */
    function parse_ini_file_advanced($filename) {
        $array = parse_ini_file($filename, true);
        $returnArray = array();
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $x = explode(':', $key);
                if (!empty($x[1])) {
                    $x = array_reverse($x, true);
                    foreach ($x as $k => $v) {
                        $i = trim($x[0]);
                        $v = trim($v);
                        if (empty($returnArray[$i])) {
                            $returnArray[$i] = array();
                        }
                        if (isset($array[$v])) {
                            $returnArray[$i] = array_merge($returnArray[$i], $array[$v]);
                        }
                        if ($k === 0) {
                            $returnArray[$i] = array_merge($returnArray[$i], $array[$key]);
                        }
                    }
                } else {
                    $returnArray[$key] = $array[$key];
                }
            }
        } else {
            return false;
        }
    
        return $returnArray;
    }
    

    Array
    (
        [foo] => Array
            (
                [a] => 1
                [b.a] => 2
                [b.b] => 3
                [b.c] => 4
                [c] => 5
            )
    
        [bar] => Array
            (
                [a] => 1
                [b.a] => 2
                [b.b] => 17
                [b.c] => 4
                [c] => 42
            )
    )
    

    最后写入成功,即

    bar2在它自己的阵法中用它的设置获胜
    注意:其他3个数组将一直存在。

    希望这就是你要找的。

        3
  •  0
  •   barthPL    12 年前

    我写过这样的东西,现在对我来说还可以:

            $config = array();
            $configSrc = parse_ini_file( $filePath, true );
            foreach( $configSrc as $sectionName => $section )
            {
                $config[$sectionName] = array();
                foreach( $section as $itemName => $item )
                {
                    $itemNameArray = explode( '.', $itemName );
                    eval( sprintf('$config[$sectionName][\'%s\'] = $item;', join("']['", $itemNameArray)) );
                }
            }
    
            // marge inheritance;
            foreach( $config as $sectionName => $section )
            {
                $ancestryArray = explode( ':', $sectionName );
                $ancestryCount = count( $ancestryArray );
                if( $ancestryCount > 1 )
                { //
                    $config[$sectionNameTrimmed = trim($ancestryArray[0])] = array();
                    $ancestryArray = array_reverse( array_slice($ancestryArray, 1) );
                    foreach( $ancestryArray as $ancestryName )
                    {
                        $ancestryName = trim( $ancestryName );
                        if( isset($config[$ancestryName]) ) {
                            $config[$sectionNameTrimmed] = array_replace_recursive( $config[$sectionNameTrimmed], $config[$ancestryName] );
                        }
                    }
    
                    $config[$sectionNameTrimmed] = array_replace_recursive( $config[$sectionNameTrimmed], $section );
                    unset( $config[$sectionName] );
                }
    
            }
    
        4
  •  0
  •   David H.    9 年前

    另一个选项是pair,build和parse。

    function build_ini_string_nested( $data, $path = null ){
      $content = array();
      foreach( $data AS $key => $val ){
        if( is_array($val) ){
          $content[] = build_ini_string_nested( $val, ($path ? $path. '.' : '') . $key );
        }
        else if( $path ) {
          $content[] = $path . '[' . ($path && is_numeric($key) ? '' : $key) . '] = ' . $val;
        }
        else {
          $content[] = $key . ' = ' . $val;
        }
      }
      return implode("\n", $content);
    }
    
    function parse_ini_string_nested( $data, $path = null ){
      if( is_string($data) )
        $data = parse_ini_string($data);
      if( $path )
        foreach( $data AS $key => $val ){
          if( strpos( $key, $path.'.' ) !== false ){
            $find_node = explode('.', $path);
            $this_path = reset(explode('.', substr($key, strlen($path.'.'))));
            $node =& $data;
            do {
              $node =& $node[ array_shift($find_node) ];
            } while( count($find_node) );
            if( is_array($node[ $this_path ]) ){
              $node[ $this_path ][] = $val;
            }
            else {
              $node[ $this_path ] = $val;
            }
          }
        }
      else {
        $drop_keys = array();
        foreach( $data AS $key => $val ){
          if( count(explode('.', $key)) > 1 ){
            $path = reset(explode('.', $key));
            $data[ $path ] = array();
            $data = parse_ini_string_nested( $data, $path );
            $drop_keys[] = $key;
          }
        }
        foreach( $drop_keys AS $key ){
          unset($data[ $key ]);
        }
      }
      return $data;
    }