PHP Conference Japan 2024

parse_ini_file

(PHP 4, PHP 5, PHP 7, PHP 8)

parse_ini_file解析配置文件

描述

parse_ini_file(字符串 $filename, 布尔值 $process_sections = false, 整数 $scanner_mode = INI_SCANNER_NORMAL): 数组|false

parse_ini_file() 加载 filename 中指定的 ini 文件,并将其中的设置以关联数组的形式返回。

ini 文件的结构与 php.ini 的结构相同。

参数

filename

要解析的 ini 文件的文件名。如果使用相对路径,则相对于当前工作目录进行评估,然后是 include_path

process_sections

通过将 process_sections 参数设置为 true,您可以获得一个多维数组,其中包含节名称和设置。 process_sections 的默认值为 false

scanner_mode

可以是 INI_SCANNER_NORMAL(默认值)或 INI_SCANNER_RAW。如果提供了 INI_SCANNER_RAW,则不会解析选项值。

从 PHP 5.6.1 开始,还可以指定为 INI_SCANNER_TYPED。在此模式下,布尔值、null 和整数类型在可能的情况下会保留。字符串值 "true""on""yes" 会转换为 true"false""off""no""none" 被视为 false"null" 在类型化模式下转换为 null。此外,如果所有数字字符串都可能转换为整数类型,则将其转换为整数类型。

返回值

如果成功,则设置将作为关联 数组 返回,如果失败,则返回 false

示例

示例 #1 sample.ini 的内容

; This is a sample configuration file
; Comments start with ';', as in php.ini

[first_section]
one = 1
five = 5
animal = BIRD

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

[third_section]
phpversion[] = "5.0"
phpversion[] = "5.1"
phpversion[] = "5.2"
phpversion[] = "5.3"

urls[svn] = "http://svn.php.net"
urls[git] = "http://git.php.net"

示例 #2 parse_ini_file() 示例

常量(但不是像 __FILE__ 这样的“魔术常量”)也可以在 ini 文件中解析,因此,如果您在运行 parse_ini_file() 之前将常量定义为 ini 值,它将被集成到结果中。仅评估 ini 值,并且该值必须只是常量。例如

<?php

define
('BIRD', 'Dodo bird');

// 解析无节
$ini_array = parse_ini_file("sample.ini");
print_r($ini_array);

// 解析有节
$ini_array = parse_ini_file("sample.ini", true);
print_r($ini_array);

?>

以上示例将输出类似以下内容

Array
(
    [one] => 1
    [five] => 5
    [animal] => Dodo bird
    [path] => /usr/local/bin
    [URL] => http://www.example.com/~username
    [phpversion] => Array
        (
            [0] => 5.0
            [1] => 5.1
            [2] => 5.2
            [3] => 5.3
        )

    [urls] => Array
        (
            [svn] => http://svn.php.net
            [git] => http://git.php.net
        )

)
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
                (
                    [0] => 5.0
                    [1] => 5.1
                    [2] => 5.2
                    [3] => 5.3
                )

            [urls] => Array
                (
                    [svn] => http://svn.php.net
                    [git] => http://git.php.net
                )

        )

)

示例 #3 parse_ini_file() 解析 php.ini 文件

<?php
// 用于比较以下结果的简单函数
function yesno($expression)
{
return(
$expression ? 'Yes' : 'No');
}

// 使用 php_ini_loaded_file() 函数获取 php.ini 的路径
$ini_path = php_ini_loaded_file();

// 解析 php.ini
$ini = parse_ini_file($ini_path);

// 打印并比较值,请注意,使用 get_cfg_var()
// 将为此处解析和加载的值提供相同的结果
echo '(parsed) magic_quotes_gpc = ' . yesno($ini['magic_quotes_gpc']) . PHP_EOL;
echo
'(loaded) magic_quotes_gpc = ' . yesno(get_cfg_var('magic_quotes_gpc')) . PHP_EOL;
?>

以上示例将输出类似以下内容

(parsed) magic_quotes_gpc = Yes
(loaded) magic_quotes_gpc = Yes

示例 #4 值插值

除了评估常量之外,ini 值中某些字符具有特殊含义。此外,可以使用 ${} 语法读取环境变量和先前定义的配置选项(请参阅 get_cfg_var())。

; | is used for bitwise OR
three = 2|3

; & is used for bitwise AND
four = 6&5

; ^ is used for bitwise XOR
five = 3^6

; ~ is used for bitwise negate
negative_two = ~1

; () is used for grouping
seven = (8|7)&(6|5)

; Interpolate the PATH environment variable
path = ${PATH}

; Interpolate the configuration option 'memory_limit'
configured_memory_limit = ${memory_limit}

示例 #5 转义字符

某些字符在双引号字符串中具有特殊含义,必须通过反斜杠前缀进行转义。首先,这些是作为边界标记的双引号 ",以及反斜杠 \ 本身(如果后面跟着特殊字符之一)

quoted = "She said \"Exactly my point\"." ; Results in a string with quote marks in it.
hint = "Use \\\" to escape double quote" ; Results in: Use \" to escape double quote

对类似 Windows 的路径有一个例外:如果带引号的字符串后面直接跟着换行符,则可以不转义尾随的反斜杠

save_path = "C:\Temp\"

如果确实需要在多行值中转义双引号后跟换行符,则可以使用以下方法进行值连接(一个双引号字符串直接后跟另一个双引号字符串)

long_text = "Lorem \"ipsum\"""
 dolor" ; Results in: Lorem "ipsum"\n dolor

另一个具有特殊含义的字符是 $(美元符号)。如果后面跟着左花括号,则必须对其进行转义

code = "\${test}"

INI_SCANNER_RAW 模式下不支持转义字符(在此模式下,所有字符都“按原样”处理)。

请注意,ini 解析器不支持标准转义序列(\n\t 等)。如有必要,请使用 stripcslashes() 函数对 parse_ini_file() 的结果进行后处理。

注释

注意:

此函数与 php.ini 文件无关。在您运行脚本时,它已经被处理过了。此函数可用于读取您自己的应用程序的配置文件。

注意:

如果 ini 文件中的值包含任何非字母数字字符,则需要将其括在双引号 (") 中。

注意 有些保留字不能用作 ini 文件的键。这些包括:nullyesnotruefalseonoffnone。除非使用 INI_SCANNER_TYPED 模式,否则值 nulloffnofalse 将导致 "",而值 onyestrue 将导致 "1"。字符 ?{}|&~!()^" 不能在键中使用,并且在值中具有特殊含义。

注意:

没有等号的条目将被忽略。例如,“foo”将被忽略,而“bar =”将被解析并添加一个空值。例如,MySQL 在 my.cnf 中有一个“no-auto-rehash”设置,它不接受值,因此会被忽略。

注意:

ini 文件通常被 Web 服务器视为纯文本,因此如果请求,则会提供给浏览器。这意味着出于安全考虑,您必须将 ini 文件保存在 docroot 之外,或者重新配置您的 Web 服务器以使其不提供这些文件。如果不执行这两者中的任何一项,可能会造成安全风险。

参见

添加注释

用户贡献的注释 13 条注释

jeremygiberson at gmail dot com
15 年前
这是一个快速的 parse_ini_file 包装器,用于添加扩展支持以节省键入和冗余。
<?php
/**
* 解析 INI 文件,通过命名空间上的“:base”后缀添加扩展功能。
*
* @param string $filename
* @return array
*/
function parse_ini_file_extended($filename) {
$p_ini = parse_ini_file($filename, true);
$config = array();
foreach(
$p_ini as $namespace => $properties){
list(
$name, $extends) = explode(':', $namespace);
$name = trim($name);
$extends = trim($extends);
// 创建命名空间(如有必要)
if(!isset($config[$name])) $config[$name] = array();
// 继承基础命名空间
if(isset($p_ini[$extends])){
foreach(
$p_ini[$extends] as $prop => $val)
$config[$name][$prop] = $val;
}
// 覆盖/设置当前命名空间的值
foreach($properties as $prop => $val)
$config[$name][$prop] = $val;
}
return
$config;
}
?>

将此 ini 处理为
<?php
/*
[base]
host=localhost
user=testuser
pass=testpass
database=default

[users:base]
database=users

[archive : base]
database=archive
*/
?>
如同它像这样
<?php
/*
[base]
host=localhost
user=testuser
pass=testpass
database=default

[users:base]
host=localhost
user=testuser
pass=testpass
database=users

[archive : base]
host=localhost
user=testuser
pass=testpass
database=archive
*/
?>
Rekam
10 年前
在某些非常特殊的情况下,您可能希望在您的 ini 文件中解析具有 N 个级别的多维数组。例如,设置 setting[data][config][debug] = true 将导致错误(预期为“=”)。

以下是一个使用点(可自定义)来匹配此情况的小函数。
<?php
function parse_ini_file_multi($file, $process_sections = false, $scanner_mode = INI_SCANNER_NORMAL) {
$explode_str = '.';
$escape_char = "'";
// 以常规方式加载 ini 文件
$data = parse_ini_file($file, $process_sections, $scanner_mode);
if (!
$process_sections) {
$data = array($data);
}
foreach (
$data as $section_key => $section) {
// 循环遍历节
foreach ($section as $key => $value) {
if (
strpos($key, $explode_str)) {
if (
substr($key, 0, 1) !== $escape_char) {
// 键包含点。根据点进行拆分,然后解析每个子键
// 并使用引用在正确的位置设置值
$sub_keys = explode($explode_str, $key);
$subs =& $data[$section_key];
foreach (
$sub_keys as $sub_key) {
if (!isset(
$subs[$sub_key])) {
$subs[$sub_key] = [];
}
$subs =& $subs[$sub_key];
}
// 在正确的位置设置值
$subs = $value;
// 取消设置带点的键,我们不再需要它
unset($data[$section_key][$key]);
}
// 我们转义了键,因此我们将点保留原样
else {
$new_key = trim($key, $escape_char);
$data[$section_key][$new_key] = $value;
unset(
$data[$section_key][$key]);
}
}
}
}
if (!
$process_sections) {
$data = $data[0];
}
return
$data;
}
?>

以下文件
<?php
/*
[normal]
foo = bar
; 使用引号保留键的原样
'foo.with.dots' = true

[array]
foo[] = 1
foo[] = 2

[dictionary]
foo[debug] = false
foo[path] = /some/path

[multi]
foo.data.config.debug = true
foo.data.password = 123456
*/
?>

将产生
<?php
parse_ini_file_multi
('file.ini', true);

数组
(
[
normal] => 数组
(
[
foo] => bar
[foo.with.dots] => 1
)
[array] => 数组
(
[
foo] => 数组
(
[
0] => 1
[1] => 2
)
)
[
dictionary] => 数组
(
[
foo] => 数组
(
[
debug] =>
[
path] => /some/path
)
)
[
multi] => 数组
(
[
foo] => 数组
(
[
data] => 数组
(
[
config] => 数组
(
[
debug] => 1
)
[
password] => 123456
)
)
)
)
?>
[email protected]
8年前
文档说明
字符 ?{}|&~!()^" 不能在键中使用,在值中具有特殊含义。

以下是我对它们含义的实验结果

; | 用于按位或
three = 2|3

; & 用于按位与
four = 6&5

; ^ 用于按位异或
five = 3^6

; ~ 用于按位取反
negative_two = ~1

; () 用于分组
seven = (8|7)&(6|5)

; ${...} 用于获取环境变量或先前定义的值。
path = ${PATH}
also = ${five}

; ? 我没有猜测
; ! 我没有猜测
YAPs
8年前
此函数用于保存 ini 文件

<?php
function array_to_ini($array,$out="")
{
$t="";
$q=false;
foreach(
$array as $c=>$d)
{
if(
is_array($d))$t.=array_to_ini($d,$c);
else
{
if(
$c===intval($c))
{
if(!empty(
$out))
{
$t.="\r\n".$out." = \"".$d."\"";
if(
$q!=2)$q=true;
}
else
$t.="\r\n".$d;
}
else
{
$t.="\r\n".$c." = \"".$d."\"";
$q=2;
}
}
}
if(
$q!=true && !empty($out)) return "[".$out."]\r\n".$t;
if(!empty(
$out)) return $t;
return
trim($t);
}

function
save_ini_file($array,$file)
{
$a=array_to_ini($array);
$ffl=fopen($file,"w");
fwrite($ffl,$a);
fclose($ffl);
}
?>
info () gaj ! design
7年前
文档中未提及,此函数的行为类似于 include

"文件根据给定的文件路径包含,或者如果没有给出,则包含指定的 include_path。如果在 include_path 中找不到文件,则 include 最终会在调用脚本自己的目录和当前工作目录中检查,然后再失败。"

(至少对于 PHP 7;尚未检查 PHP 5。)
[email protected]
21年前
对于所有遇到转义双引号问题的用户,请注意

我通过在输入 ini 文件时对我的内容进行 "base64_encode()",并在输出时进行 "base64_decode()" 来解决此问题。

因为 base64 使用 "=" 符号,所以您必须将整个值用双引号括起来,使该行看起来像这样

varname = "TmlhZ2FyYSBGYWxscywgT04="

当进行 base64 编码时,您的字符串将保留所有 \n、\t...等等... URL 会完美地保留所有内容 :-)

希望你们中的一些人发现这很有用!

干杯,Kieran
Justin Hall
18年前
这是一种简单(但略显笨拙)的方法来避免字符限制(在值中)

<?php
define
('QUOTE', '"');
$test = parse_ini_file('test.ini');

echo
"<pre>";
print_r($test);
?>

test.ini 的内容

park yesterday = "I (walked) | {to} " QUOTE"the"QUOTE " park yesterday & saw ~three~ dogs!"

输出

<?php
数组
(
[
park yesterday] => I (walked) | {to} "the" park yesterday & saw ~three~ dogs!
)
?>
[email protected]
17年前
警告:parse_ini_files 无法处理包含等号 (=) 的值。

以下函数支持节、注释、数组以及任何节之外的键值对。
注意,类似的键将覆盖彼此(除非在不同的节中)。

<?php
function parse_ini ( $filepath ) {
$ini = file( $filepath );
if (
count( $ini ) == 0 ) { return array(); }
$sections = array();
$values = array();
$globals = array();
$i = 0;
foreach(
$ini as $line ){
$line = trim( $line );
// 注释
if ( $line == '' || $line{0} == ';' ) { continue; }
// 节点
if ( $line{0} == '[' ) {
$sections[] = substr( $line, 1, -1 );
$i++;
continue;
}
// 键值对
list( $key, $value ) = explode( '=', $line, 2 );
$key = trim( $key );
$value = trim( $value );
if (
$i == 0 ) {
// 数组值
if ( substr( $line, -1, 2 ) == '[]' ) {
$globals[ $key ][] = $value;
} else {
$globals[ $key ] = $value;
}
} else {
// 数组值
if ( substr( $line, -1, 2 ) == '[]' ) {
$values[ $i - 1 ][ $key ][] = $value;
} else {
$values[ $i - 1 ][ $key ] = $value;
}
}
}
for(
$j=0; $j<$i; $j++ ) {
$result[ $sections[ $j ] ] = $values[ $j ];
}
return
$result + $globals;
}
?>

示例用法
<?php
$stores
= parse_ini('stores.ini');
print_r( $stores );
?>

一个示例 ini 文件
<?php
/*
; 以 ';' 开头的行是注释
global_value1 = a string value
global_value1 = another string value

; 空行会被忽略
[Section1]
key = value
; 键和值周围的空格也会被忽略
otherkey=other value
otherkey=yet another value
; 这对键值对将覆盖前一个。
*/
?>
simon dot riget at gmail dot com
11 年前
.ini 文件或也称为 JSON 文件格式,是一种非常有用的存储数据格式。特别是大型数组。

奇怪的是,有一个很好的函数可以读取文件,但没有函数可以写入它。

所以这里有一个。

使用方法:put_ini_file(string $file, array $array)

<?php
function put_ini_file($file, $array, $i = 0){
$str="";
foreach (
$array as $k => $v){
if (
is_array($v)){
$str.=str_repeat(" ",$i*2)."[$k]".PHP_EOL;
$str.=put_ini_file("",$v, $i+1);
}else
$str.=str_repeat(" ",$i*2)."$k = $v".PHP_EOL;
}
if(
$file)
return
file_put_contents($file,$str);
else
return
$str;
}
?>
theking2(at)king.ma
9 个月前
为了使内容在应用程序的每个角落都可用,我使用用户定义的常量 $SETTINGS。它是这样初始化的
<?php

define
( 'SETTINGS", parse_ini_file('settings.ini', true) );

?>
使用正确的 settings.ini 文件,您现在可以执行以下操作
<?php
$db = new \PDO(
"mysql:host={SETTINGS['
db']['host']};dbname={SETTINGS['db']['name']};charset=utf8",
SETTINGS['
db']['user'],
SETTINGS['
db']['pass'], [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]
);
?>

确保在网站上隐藏您的 settings.ini 文件,例如
<?php
<FilesMatch "\.(?:ini|htaccess)$">
Order allow,deny
Deny from all
</FilesMatch>
?>
eciruam35 at gmail dot com
1 年前
修复了 put_ini_file 函数中的一点小错误(此处)

function put_ini_file($config, $file, $has_section = false, $write_to_file = true){
$fileContent = '';
if(!empty($config)){
foreach($config as $i=>$v){
if($has_section){
$fileContent .= "\n[$i]".PHP_EOL.put_ini_file($v, $file, false, false);
}
else{
if(is_array($v)){
foreach($v as $t=>$m){
//--->>> 此处 $fileContent .= "-->$i[$t] = ".(is_numeric($m) ? $m : '"'.$m.'"').PHP_EOL;
$fileContent .= "$i"."[] = ".(is_numeric($m) ? $m : '"'.$m.'"').PHP_EOL;
}
}
else $fileContent .= "$i = ".(is_numeric($v) ? $v : '"'.$v.'"').PHP_EOL;
}
}
}

if($write_to_file && strlen($fileContent)) return file_put_contents($file, $fileContent, LOCK_EX);
else return $fileContent;
}
manngo
1 年前
保护您的 .ini 文件

“ini 文件通常被 Web 服务器视为纯文本,因此如果请求,会提供给浏览器。这意味着出于安全考虑,您必须将 ini 文件保存在 docroot 之外,或者重新配置 Web 服务器以不提供它们。如果不执行这两者中的任何一项,可能会带来安全风险。”

或者,您可以将文件保存为

stuff.ini.php

在开头添加以下内容

;<?php die('go away'); ?>

开头的分号被视为注释,因此此行对 ini 文件没有影响。

由于文件具有 .php 扩展名,因此如果您尝试直接访问此文件,它将通过 PHP 解释器运行,并且 php 代码块将被处理并退出。

文件扩展名对 parse_ini_file() 函数没有不良影响,当然,.ini 部分是个人喜好问题。
jbricci at ya-right dot com
9 年前
此核心函数无法处理 ini key[][] = value(s)(多维数组),因此如果您需要支持这种设置,则需要编写自己的函数。一种方法是将所有 key = value(s) 转换为数组字符串 [key][][]=value(s),然后使用 parse_str() 转换所有这些 [key][][]=value(s),这样您只需逐行读取 ini 文件,而不是执行疯狂的 foreach() 循环来处理每个部分中的这些(多维数组),例如…

ini 文件...... config.php

<?php

; 这是一个示例配置文件
; 注释以 ';' 开头,就像在 php.ini 中一样

[first_section]
one = 1
five
= 5
animal
= BIRD

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

[third_section]
phpversion[] = "5.0"
phpversion[] = "5.1"
phpversion[] = "5.2"
phpversion[] = "5.3"

urls[svn] = "http://svn.php.net"
urls[git] = "http://git.php.net"

[fourth_section]

a[][][] = b
a
[][][][] = c
a
[test_test][][] = d
test
[one][two][three] = true

?>

echo parse_ini_file ( "C:\\services\\www\\docs\\config.php" );

结果为...

// PHP Warning: syntax error, unexpected TC_SECTION, expecting '=' line 27 -> a[][][] = b

这里有一个简单的函数,它处理(多维数组)而无需循环每个键[][]= 值。

<?php

function getIni ( $file, $sections = FALSE )
{
$return = array ();

$keeper = array ();

$config = fopen ( $file, 'r' );

while ( !
feof ( $config ) )
{
$line = trim ( fgets ( $config, 1024 ) );

$line = ( $line == '' ) ? ' ' : $line;

switch (
$line{0} )
{
case
' ':
case
'#':
case
'/':
case
';':
case
'<':
case
'?':

break;

case
'[':

if (
$sections )
{
$header = 'config[' . trim ( substr ( $line, 1, -1 ) ) . ']';
}
else
{
$header = 'config';
}

break;

default:

$kv = array_map ( 'trim', explode ( '=', $line ) );

$kv[0] = str_replace ( ' ', '+', $kv[0] );

$kv[1] = str_replace ( ' ', '+', $kv[1] );

if ( (
$pos = strpos ( $kv[0], '[' ) ) !== FALSE )
{
$kv[0] = '[' . substr ( $kv[0], 0, $pos ) . ']' . substr ( $kv[0], $pos );
}
else
{
$kv[0] = '[' . $kv[0] . ']';
}

$bt = strtolower ( $kv[1] );

if (
in_array ( $bt, array ( 'true', 'false', 'on', 'off' ) ) )
{
$kv[1] = ( $bt == 'true' || $bt == 'on' ) ? TRUE : FALSE;
}

$keeper[] = $header . $kv[0] . '=' . $kv[1];
}
}

fclose ( $config );

parse_str ( implode ( '&', $keeper ), $return );

return
$return['config'];
}

// 用法...

$sections = TRUE;

print_r ( $config->getIni ( "C:\\services\\www\\docs\\config.php" ), $sections );

?>
To Top