first commit
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\Engine\Util;
|
||||
|
||||
defined('AKEEBAENGINE') || die();
|
||||
|
||||
/**
|
||||
* A utility class to parse INI files.
|
||||
*
|
||||
* This is marked deprecated since Akeeba Engine 6.4.1. The configuration of the engine is no longer stored as INI data.
|
||||
* Moreover, we will be migrating away from the current INI files used for defining engine and GUI configuration
|
||||
* parameters.
|
||||
*
|
||||
* @package Akeeba\Engine\Util
|
||||
*
|
||||
* @deprecated 6.4.1
|
||||
*/
|
||||
abstract class ParseIni
|
||||
{
|
||||
/**
|
||||
* Parse an INI file and return an associative array. This monstrosity is required because some so-called hosts
|
||||
* have disabled PHP's parse_ini_file() function for "security reasons". Apparently their blatant ignorance doesn't
|
||||
* allow them to discern between the innocuous parse_ini_file and the potentially dangerous ini_set, leading them to
|
||||
* disable the former and let the latter enabled.
|
||||
*
|
||||
* @param string $file The file name or raw INI data to process
|
||||
* @param bool $process_sections True to also process INI sections
|
||||
* @param bool $rawdata Is this raw INI data? False when $file is a filepath.
|
||||
* @param bool $forcePHP Should I force the use of the pure-PHP INI file parser?
|
||||
*
|
||||
* @return array An associative array of sections, keys and values
|
||||
*/
|
||||
public static function parse_ini_file($file, $process_sections = false, $rawdata = false, $forcePHP = false)
|
||||
{
|
||||
/**
|
||||
* WARNING: DO NOT USE INI_SCANNER_RAW IN THE parse_ini_string / parse_ini_file FUNCTION CALLS WITHOUT POST-
|
||||
* PROCESSING!
|
||||
*
|
||||
* Sometimes we need to save data which is either multiline or has double quotes in the Engine's
|
||||
* configuration. For this reason we have to manually escape \r, \n, \t and \" in
|
||||
* Akeeba\Engine\Configuration::dumpObject(). If we don't we end up with multiline INI values which
|
||||
* won't work. However, if we are using INI_SCANNER_RAW these characters are not escaped back to their
|
||||
* original form. As a result we end up with broken data which cause various problems, the most visible
|
||||
* of which is that Google Storage integration is broken since the JSON data included in the config is
|
||||
* now unparseable.
|
||||
*
|
||||
* However, not using raw mode introduces other problems. For example, the sequence \$ is converted to $ because
|
||||
* it's assumed to be an escaped dollar sign. Things like $foo are addressed as variable interpolation, i.e.
|
||||
* "This is ${foo} wrong" results in "This is wrong" because $foo is considered as an interpolated variable.
|
||||
*
|
||||
* The solution to that is to use raw mode to parse the INI files and THEN unescape the variables. However, we
|
||||
* cannot simply use stripslashes/stripcslashes because we could end up replacing more than we should (unlike
|
||||
* addcslashes we cannot specify a list of escaped characters to consider). We have to do a slower string
|
||||
* replace instead.
|
||||
*
|
||||
* The next problem to consider is that when $process_sections is true some of the values generated are arrays
|
||||
* or even nested arrays. If you try to string replace on them hilarity ensues. Therefore we have the recursive
|
||||
* unescape method which takes care of that. To make things faster and maintain the array keys we use array_map
|
||||
* to apply recursiveUnescape to the array.
|
||||
*/
|
||||
|
||||
if ($rawdata)
|
||||
{
|
||||
if (!function_exists('parse_ini_string'))
|
||||
{
|
||||
return self::parse_ini_file_php($file, $process_sections, $rawdata);
|
||||
}
|
||||
|
||||
// !!! VERY IMPORTANT !!! Read the warning above before touching this line
|
||||
return array_map([
|
||||
__CLASS__, 'recursiveUnescape',
|
||||
], parse_ini_string($file, $process_sections, INI_SCANNER_RAW));
|
||||
}
|
||||
|
||||
if (!function_exists('parse_ini_file'))
|
||||
{
|
||||
return self::parse_ini_file_php($file, $process_sections);
|
||||
}
|
||||
|
||||
// !!! VERY IMPORTANT !!! Read the warning above before touching this line
|
||||
return array_map([__CLASS__, 'recursiveUnescape'], parse_ini_file($file, $process_sections, INI_SCANNER_RAW));
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively unescape values which have been escaped by Akeeba\Engine\Configuration::dumpObject().
|
||||
*
|
||||
* @param string|array $value
|
||||
*
|
||||
* @return string|array Unescaped result
|
||||
*/
|
||||
static function recursiveUnescape($value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
return array_map([__CLASS__, 'recursiveUnescape'], $value);
|
||||
}
|
||||
|
||||
return str_replace(['\r', '\n', '\t', '\"'], ["\r", "\n", "\t", '"'], $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A PHP based INI file parser.
|
||||
*
|
||||
* Thanks to asohn ~at~ aircanopy ~dot~ net for posting this handy function on
|
||||
* the parse_ini_file page on http://gr.php.net/parse_ini_file
|
||||
*
|
||||
* @param string $file Filename to process
|
||||
* @param bool $process_sections True to also process INI sections
|
||||
* @param bool $rawdata If true, the $file contains raw INI data, not a filename
|
||||
*
|
||||
* @return array An associative array of sections, keys and values
|
||||
*/
|
||||
static function parse_ini_file_php($file, $process_sections = false, $rawdata = false)
|
||||
{
|
||||
$process_sections = ($process_sections !== true) ? false : true;
|
||||
|
||||
if (!$rawdata)
|
||||
{
|
||||
$ini = file($file);
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = str_replace("\r", "", $file);
|
||||
$ini = explode("\n", $file);
|
||||
}
|
||||
|
||||
if (!is_array($ini))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (count($ini) == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$sections = [];
|
||||
$values = [];
|
||||
$result = [];
|
||||
$globals = [];
|
||||
$i = 0;
|
||||
foreach ($ini as $line)
|
||||
{
|
||||
$line = trim($line);
|
||||
$line = str_replace("\t", " ", $line);
|
||||
|
||||
// Comments
|
||||
if (!preg_match('/^[a-zA-Z0-9[]/', $line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sections
|
||||
if ($line[0] == '[')
|
||||
{
|
||||
$tmp = explode(']', $line);
|
||||
$sections[] = trim(substr($tmp[0], 1));
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Key-value pair
|
||||
$lineParts = explode('=', $line, 2);
|
||||
if (count($lineParts) != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$key = trim($lineParts[0]);
|
||||
$value = trim($lineParts[1]);
|
||||
unset($lineParts);
|
||||
|
||||
if (strstr($value, ";"))
|
||||
{
|
||||
$tmp = explode(';', $value);
|
||||
if (count($tmp) == 2)
|
||||
{
|
||||
if ((($value[0] != '"') && ($value[0] != "'")) ||
|
||||
preg_match('/^".*"\s*;/', $value) || preg_match('/^".*;[^"]*$/', $value) ||
|
||||
preg_match("/^'.*'\s*;/", $value) || preg_match("/^'.*;[^']*$/", $value)
|
||||
)
|
||||
{
|
||||
$value = $tmp[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($value[0] == '"')
|
||||
{
|
||||
$value = preg_replace('/^"(.*)".*/', '$1', $value);
|
||||
}
|
||||
elseif ($value[0] == "'")
|
||||
{
|
||||
$value = preg_replace("/^'(.*)'.*/", '$1', $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $tmp[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = trim($value);
|
||||
$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++)
|
||||
{
|
||||
if ($process_sections === true)
|
||||
{
|
||||
if (isset($sections[$j]) && isset($values[$j]))
|
||||
{
|
||||
$result[$sections[$j]] = $values[$j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($values[$j]))
|
||||
{
|
||||
$result[] = $values[$j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result + $globals;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user