Skip to content

Instantly share code, notes, and snippets.

@msegu
Last active July 10, 2018 20:02
Show Gist options
  • Save msegu/c43a871c5a874a1d9bff978b448a0aa4 to your computer and use it in GitHub Desktop.
Save msegu/c43a871c5a874a1d9bff978b448a0aa4 to your computer and use it in GitHub Desktop.
php parse_ini_string() fix
<?php
/*
php parse_ini_string() extension
With function below you can:
- fix unvalued fields ('key' (invalid) ==> 'key=' (OK) )
- fix unquotted values with equal sign '=' ('key=value_part1=value_part2' ==> 'key="value_part1=value_part2"')
- fix (solve) multidimensional arrays (makes 'key[key1][key2]=value' valid)
- fix any reading errors (wrong lines, they may be later rawurldecoded with md5 checking)
*/
function parse_ini_stringM($str, $process_sections = FALSE, $scanner_mode = INI_SCANNER_NORMAL) {
$str = explode("\n",
str_replace(
array("\r\n", "\n\r", "\r"),
array("\n".($rep['rn']=md5(rand().rand().rand()))."\n",
"\n".($rep['nr']=md5(rand().rand().rand()))."\n",
"\n".($rep['r']=md5(rand().rand().rand()))."\n"),
$str)
);
$rep['multi']=md5(rand().rand().rand());
foreach ($str as &$line_) {
$line = explode('=', $line_, 2);
if ( (strpos($line_, "\0")!==FALSE) || ( (($tilde=strpos($line_, '~'))!==FALSE) && ($tilde<strpos($line_, '=')) ) ) {
// Fix reading errors! (wrong lines)
$line_ = str_replace('~', '%7e', rawurlencode($line_)).'='.md5($line_); // (tilde '~' may cause FALSE)
} else {
if ($line[0]!='') {
if (!isset($line[1])) {
// Fix unvalued options (e.g. 'key' ==> 'key=')
if ((!in_array($line[0], $rep, TRUE))&&(substr(trim($line[0]), 0, 1)!='[')) $line[1]='';
} else {
$value = trim($line[1]);
// Fix unquotted strings (e.g. 'key=value' ==> 'key="value"')
//if (defined($value)) ;
//else if (is_numeric($value)) ;
//else
// Fix unquotted strings with equal sign '=' (e.g. 'key=value_part1=value_part2' ==> 'key="value_part1=value_part2"')
if (strpos($line[1],'=')!==FALSE)
if (($value!='')&&($value[0]!='"')&&($value[0]!="'")) $line[1]='"'.$line[1].'"';
}
}
// Prepare multidimensional arrays: lock "multi-keys" (e.g. key[key1][key2][key3] ==> key[key1####key2####key3], where #### is delimiter string $rep['multi'])
$line[0]=preg_replace('/\]\s*\[/', $rep['multi'].md5(rand().rand().rand()), $line[0]);
$line = implode('=', $line);
// Last checking of this line
if (parse_ini_string("[a]\n".$line)===FALSE) {
$line_ = str_replace('~', '%7e', rawurlencode($line_)).'='.md5($line_); // (tilde '~' may cause FALSE)
} else $line_ = $line;
}
}
unset($line_);
$str =
str_replace(
array("\n".$rep['rn']."\n", "\n".$rep['nr']."\n", "\n".$rep['r']."\n"),
array("\r\n", "\n\r", "\r"),
implode("\n", $str)
);
// Parse prepared string
$str = parse_ini_string($str, $process_sections, $scanner_mode);
// Solve multidimensional arrays
foreach ($str as &$section) {
if (is_array($section)) {
foreach ($section as &$key) {
if (is_array($key)) {
// 2-dimensional array
foreach ($key as $multikey => $value) {
if (strpos($multikey, $rep['multi'])!==FALSE) {
// Multidimensional array - resolving !
$mkey=-1;$line=$multikey;while (($mkey=strpos($line, $rep['multi'], $mkey+1))!==FALSE) $line=substr_replace($line, '', $mkey+32, 32);
$mkey = explode($rep['multi'], $line);
if (!function_exists('parse_ini_stringM_mult')) {
function parse_ini_stringM_mult($mkey /* key(s) to create */, $value /* final value */, &$key /* base */, $delimiter) {
//checking for "empty key" ( key[]=... ) and integers
if (trim($mkey[0])=='') $new=$key[$delimiter]+0;
elseif (ctype_digit(strval($mkey[0]))) $new=(int)$mkey[0]; // see http://php.net/manual/en/function.is-int.php#82857 and below, https://stackoverflow.com/questions/6416763/checking-if-a-variable-is-an-integer-in-php
if (isset($new)) $key[$delimiter]=$new+1; //setting (saving counter) for next "empty key"
else $new=$mkey[0];
if (count($mkey)==1) $key[$new] = $value;
else {
if (!isset($key[$new])) $key[$new]=array();
parse_ini_stringM_mult(array_slice($mkey, 1), $value, $key[$new], $delimiter);
}
}
}
parse_ini_stringM_mult($mkey, $value, $key, $rep['multi']);
unset($key[$multikey]);
}
}
// Removing key[$delimiter] (used as counter)
if (!function_exists('parse_ini_stringM_del')) {
function parse_ini_stringM_del(&$key, $delimiter) {
foreach ($key as $mkey => &$value)
if ($mkey===$delimiter) unset($key[$mkey]);
else if (is_array($value)) parse_ini_stringM_del($value, $delimiter);
else if (strpos($value, $delimiter)!==FALSE) $value=str_replace($delimiter, '', $value);// @TODO: checking int vs. string of int...
}
}
parse_ini_stringM_del($key, $rep['multi']);
}
}
unset($key);
}
}
unset($section);
return $str;
}
// -----------------------------------------------------
// Example:
$ini = '[a]
%hello
b
c=d
e=';
var_export(parse_ini_string($ini, TRUE)); /* array (
'a' =>
array (
'c' => 'd',
'e' => '',
),
)
*/
$ini .= '
f[g][2]=h
f[g][i]=j
f[g][][]=k
m=n=o
pq=r=s'.chr(1).chr(0).chr(255).'
f[g][[=t
'
.implode('',array_map('chr', range(0, 255)))
.'
pq=rs'.chr(1).chr(0).chr(255).'
u=~v
x=y~z
bye';
var_export(parse_ini_string($ini, TRUE)); // false
var_export(parse_ini_stringM($ini, TRUE)); /* array (
'a' =>
array (
'%hello' => '',
'b' => '',
'c' => 'd',
'e' => '',
'f' =>
array (
'g' =>
array (
2 => 'h',
'i' => 'j',
3 =>
array (
0 => 'k',
),
),
),
'm' => 'n=o',
'pq%3Dr%3Ds%01%00%FF' => '78eb5730c13ec3dc2ac1fc7500538994',
'f%5Bg%5D%5B%5B%3Dt' => 'b22e0e464a28518d270c7f446bc5923d',
'%00%01%02%03%04%05%06%07%08%09' => 'c56bd5480f6e5413cb62a0ad9666613a',
"\x0b\x0c" => '',
'%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7e%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF' => '1704281b8f7975a90eac3dec1916c364',
'pq%3Drs%01%00%FF' => '8c989cdc972a8c093f07d7acfd43dac5',
'u' => '-1',
'x%3Dy%7ez' => 'c5fb15f7ed0c5bca9dc8819b8b2c8918',
'bye' => '',
),
)
*/
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment