PHP 8.3.4 Released!

parse_ini_file

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

parse_ini_file解析一个配置文件

说明

parse_ini_file(string $filename, bool $process_sections = false, int $scanner_mode = INI_SCANNER_NORMAL): array|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,然后将不会解析选项值。

As of PHP 5.6.1 can also be specified as INI_SCANNER_TYPED. In this mode boolean, null and integer types are preserved when possible. String values "true", "on" and "yes" are converted to true. "false", "off", "no" and "none" are considered false. "null" is converted to null in typed mode. Also, all numeric strings are converted to integer type if it is possible.

返回值

成功时以关联数组 array 返回设置,失败时返回 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');

// Parse without sections
$ini_array = parse_ini_file("sample.ini");
print_r($ini_array);

// Parse with sections
$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);

// Print and compare the values, note that using get_cfg_var()
// will give the same results for parsed and loaded here
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 转义字符

Some characters have special meaning in double-quoted strings and must be escaped by the backslash prefix. First of all, these are the double quote " as the boundary marker, and the backslash \ itself (if followed by one of the special characters):

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

There is an exception made for Windows-like paths: it's possible to not escape trailing backslash if the quoted string is directly followed by a linebreak:

save_path = "C:\Temp\"

If one does need to escape double quote followed by linebreak in a multiline value, it's possible to use value concatenation in the following way (there is one double-quoted string directly followed by another one):

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

Another character with special meaning is $ (the dollar sign). It must be escaped if followed by the open curly brace:

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 服务器,不会提供这些文件。如果不这么做,可能会带来安全风险。

参见

add a note

User Contributed Notes 13 notes

up
29
jeremygiberson at gmail dot com
14 years ago
Here is a quick parse_ini_file wrapper to add extend support to save typing and redundancy.
<?php
/**
* Parses INI file adding extends functionality via ":base" postfix on namespace.
*
* @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);
// create namespace if necessary
if(!isset($config[$name])) $config[$name] = array();
// inherit base namespace
if(isset($p_ini[$extends])){
foreach(
$p_ini[$extends] as $prop => $val)
$config[$name][$prop] = $val;
}
// overwrite / set current namespace values
foreach($properties as $prop => $val)
$config[$name][$prop] = $val;
}
return
$config;
}
?>

Treats this ini:
<?php
/*
[base]
host=localhost
user=testuser
pass=testpass
database=default

[users:base]
database=users

[archive : base]
database=archive
*/
?>
As if it were like this:
<?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
*/
?>
up
13
Rekam
9 years ago
You may want, in some very special cases, to parse multi-dimensional array with N levels in your ini file. Something like setting[data][config][debug] = true will result in an error (expected "=").

Here's a little function to match this, using dots (customizable).
<?php
function parse_ini_file_multi($file, $process_sections = false, $scanner_mode = INI_SCANNER_NORMAL) {
$explode_str = '.';
$escape_char = "'";
// load ini file the normal way
$data = parse_ini_file($file, $process_sections, $scanner_mode);
if (!
$process_sections) {
$data = array($data);
}
foreach (
$data as $section_key => $section) {
// loop inside the section
foreach ($section as $key => $value) {
if (
strpos($key, $explode_str)) {
if (
substr($key, 0, 1) !== $escape_char) {
// key has a dot. Explode on it, then parse each subkeys
// and set value at the right place thanks to references
$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];
}
// set the value at the right place
$subs = $value;
// unset the dotted key, we don't need it anymore
unset($data[$section_key][$key]);
}
// we have escaped the key, so we keep dots as they are
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;
}
?>

The following file:
<?php
/*
[normal]
foo = bar
; use quotes to keep your key as it is
'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
*/
?>

will result in:
<?php
parse_ini_file_multi
('file.ini', true);

Array
(
[
normal] => Array
(
[
foo] => bar
[foo.with.dots] => 1
)
[array] => Array
(
[
foo] => Array
(
[
0] => 1
[1] => 2
)
)
[
dictionary] => Array
(
[
foo] => Array
(
[
debug] =>
[
path] => /some/path
)
)
[
multi] => Array
(
[
foo] => Array
(
[
data] => Array
(
[
config] => Array
(
[
debug] => 1
)
[
password] => 123456
)
)
)
)
?>
up
4
dschnepper at box dot com
8 years ago
The documentation states:
Characters ?{}|&~!()^" must not be used anywhere in the key and have a special meaning in the value.

Here's the results of my experiments on what they mean:

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

; ${...} is used for grabbing values from the environment, or previously defined values.
path = ${PATH}
also = ${five}

; ? I have no guess for
; ! I have no guess for
up
5
YAPs
7 years ago
This function for save ini files

<?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);
}
?>
up
3
info () gaj ! design
7 years ago
Not mentioned in the documentation, this function acts like include:

"Files are included based on the file path given or, if none is given, the include_path specified. If the file isn't found in the include_path, include will finally check in the calling script's own directory and the current working directory before failing."

(At least for PHP 7; have not checked PHP 5.)
up
2
kieran dot huggins at rogers dot com
21 years ago
Just a quick note for all those running into trouble escaping double quotes:

I got around this by "base64_encode()"-ing my content on the way in to the ini file, and "base64_decode()"-ing on the way out.

Because base64 uses the "=" sign, you will have to encapsulate the entire value in double quotes so the line looks like this:

varname = "TmlhZ2FyYSBGYWxscywgT04="

When base64'd, your strings will retain all \n, \t...etc... URL's retain everything perfectly :-)

I hope some of you find this useful!

Cheers, Kieran
up
4
Justin Hall
17 years ago
This is a simple (but slightly hackish) way of avoiding the character limitations (in values):

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

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

contents of test.ini:

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

output:

<?php
Array
(
[
park yesterday] => I (walked) | {to} "the" park yesterday & saw ~three~ dogs!
)
?>
up
3
goulven.ch AT gmail DOT com
16 years ago
Warning: parse_ini_files cannot cope with values containing the equal sign (=).

The following function supports sections, comments, arrays, and key-value pairs outside of any section.
Beware that similar keys will overwrite one another (unless in different sections).

<?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 );
// Comments
if ( $line == '' || $line{0} == ';' ) { continue; }
// Sections
if ( $line{0} == '[' ) {
$sections[] = substr( $line, 1, -1 );
$i++;
continue;
}
// Key-value pair
list( $key, $value ) = explode( '=', $line, 2 );
$key = trim( $key );
$value = trim( $value );
if (
$i == 0 ) {
// Array values
if ( substr( $line, -1, 2 ) == '[]' ) {
$globals[ $key ][] = $value;
} else {
$globals[ $key ] = $value;
}
} else {
// Array values
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;
}
?>

Example usage:
<?php
$stores
= parse_ini('stores.ini');
print_r( $stores );
?>

An example ini file:
<?php
/*
;Commented line start with ';'
global_value1 = a string value
global_value1 = another string value

; empty lines are discarded
[Section1]
key = value
; whitespace around keys and values is discarded too
otherkey=other value
otherkey=yet another value
; this key-value pair will overwrite the former.
*/
?>
up
5
simon dot riget at gmail dot com
11 years ago
.ini files or JSON file format as it is also known as, are very useful format to store stuff in. Especially large arrays.

Strangely enough there is this nice function to read the file, but no function to write it.

So here is one.

Use it as: 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;
}
?>
up
1
theking2(at)king.ma
22 days ago
To make the content available in every corner of you application I use a user defined constant. $SETTINGS. It is initialized like this
<?php

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

?>
With the proper settings.ini file you can now do stuff like
<?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
]
);
?>

Make sure to hide your settings.ini file on a website with for instance
<?php
<FilesMatch "\.(?:ini|htaccess)$">
Order allow,deny
Deny from all
</FilesMatch>
?>
up
1
eciruam35 at gmail dot com
5 months ago
fix a little bug (here) in function 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){
//--->>> Here $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;
}
up
0
manngo
4 months ago
Securing your .ini file:

“ini files are generally treated as plain text by web servers and thus served to browsers if requested. That means for security you must either keep your ini files outside of your docroot or reconfigure your web server to not serve them. Failure to do either of those may introduce a security risk.”

Alternatively, you can save you file as:

stuff.ini.php

add this to the beginning:

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

The semicolon at the beginning is treated as comment, so this line has no effect on the ini file.

Since the file has a .php extension, it will run through the PHP interpreter if you attempt to access this file directly, and the php block will be processed and exit.

The file extension has no ill effect on the parse_ini_file() function, and the .ini part is, of course, a matter of taste.
up
0
jbricci at ya-right dot com
8 years ago
This core function won't handle ini key[][] = value(s), (multidimensional arrays), so if you need to support that kind of setup you will need to write your own function. one way to do it is to convert all the key = value(s) to array string [key][][]=value(s), then use parse_str() to convert all those [key][][]=value(s) that way you just read the ini file line by line, instead of doing crazy foreach() loops to handle those (multidimensional arrays) in each section, example...

ini file...... config.php

<?php

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

[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" );

results in...

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

Here it simple function that handles (multidimensional arrays) without looping each key[][]= value(s)

<?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'];
}

// usage...

$sections = TRUE;

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

?>
To Top