parse_ini_file
(PHP 4, PHP 5)
parse_ini_file — Parse a configuration file
Description
$filename
[, bool $process_sections
= false
[, int $scanner_mode
= INI_SCANNER_NORMAL
]] )
parse_ini_file() loads in the
ini file specified in filename
,
and returns the settings in it in an associative array.
The structure of the ini file is the same as the php.ini's.
Parameters
-
filename
-
The filename of the ini file being parsed.
-
process_sections
-
By setting the
process_sections
parameter toTRUE
, you get a multidimensional array, with the section names and settings included. The default forprocess_sections
isFALSE
-
scanner_mode
-
Can either be
INI_SCANNER_NORMAL
(default) orINI_SCANNER_RAW
. IfINI_SCANNER_RAW
is supplied, then option values will not be parsed.
Return Values
The settings are returned as an associative array on success,
and FALSE
on failure.
Changelog
Version | Description |
---|---|
5.3.0 |
Added optional scanner_mode parameter.
Single quotes may now be used around variable assignments.
Hash marks (#) may no longer be used as comments
and will throw a deprecation warning if used.
|
5.2.7 |
On syntax error this function will return FALSE rather than an empty
array.
|
5.2.4 | Keys and section names consisting of numbers are now evaluated as PHP integers thus numbers starting by 0 are evaluated as octals and numbers starting by 0x are evaluated as hexadecimals. |
5.0.0 | Values enclosed in double quotes can contain new lines. |
4.2.1 | This function is now affected by safe mode and open_basedir. |
Examples
Example #1 Contents of 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"
Example #2 parse_ini_file() example
Constants may also be parsed in the ini file so if you define a constant as an ini value before running parse_ini_file(), it will be integrated into the results. Only ini values are evaluated. For example:
<?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);
?>
The above example will output something similar to:
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 ) ) 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 ) ) )
Example #3 parse_ini_file() parsing a php.ini file
<?php
// A simple function used for comparing the results below
function yesno($expression)
{
return($expression ? 'Yes' : 'No');
}
// Get the path to php.ini using the php_ini_loaded_file()
// function available as of PHP 5.2.4
$ini_path = php_ini_loaded_file();
// Parse 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;
?>
The above example will output something similar to:
(parsed) magic_quotes_gpc = Yes (loaded) magic_quotes_gpc = Yes
Notes
Note:
This function has nothing to do with the php.ini file. It is already processed by the time you run your script. This function can be used to read in your own application's configuration files.
Note:
If a value in the ini file contains any non-alphanumeric characters it needs to be enclosed in double-quotes (").
Note: There are reserved words which must not be used as keys for ini files. These include: null, yes, no, true, false, on, off, none. Values null, off, no and false result in "". Values on, yes and true result in "1". Characters ?{}|&~![()^" must not be used anywhere in the key and have a special meaning in the value.
- PHP Руководство
- Функции по категориям
- Индекс функций
- Справочник функций
- Расширения для работы с файловой системой
- Функции для работы с файловой системой
- basename
- chgrp
- chmod
- chown
- clearstatcache
- copy
- delete
- dirname
- disk_free_space
- disk_total_space
- diskfreespace
- fclose
- feof
- fflush
- fgetc
- fgetcsv
- fgets
- fgetss
- file_exists
- file_get_contents
- file_put_contents
- file
- fileatime
- filectime
- filegroup
- fileinode
- filemtime
- fileowner
- fileperms
- filesize
- filetype
- flock
- fnmatch
- fopen
- fpassthru
- fputcsv
- fputs
- fread
- fscanf
- fseek
- fstat
- ftell
- ftruncate
- fwrite
- glob
- is_dir
- is_executable
- is_file
- is_link
- is_readable
- is_uploaded_file
- is_writable
- is_writeable
- lchgrp
- lchown
- link
- linkinfo
- lstat
- mkdir
- move_uploaded_file
- parse_ini_file
- parse_ini_string
- pathinfo
- pclose
- popen
- readfile
- readlink
- realpath_cache_get
- realpath_cache_size
- realpath
- rename
- rewind
- rmdir
- set_file_buffer
- stat
- symlink
- tempnam
- tmpfile
- touch
- umask
- unlink
Коментарии
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
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!
)
?>
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.
*/
?>
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
*/
?>
.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;
}
?>
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
)
)
)
)
?>
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 );
?>
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
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);
}
?>
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.)
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;
}
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.
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>
?>