ACC SHELL
<?php
/**
* This file is part of the Nette Framework (http://nette.org)
*
* Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
namespace Nette\Config;
use Nette;
/**
* Reading and writing INI files.
*
* @author David Grudl
*/
final class IniAdapter implements IAdapter
{
/** @var string key nesting separator (key1> key2> key3) */
public static $keySeparator = '.';
/** @var string section inheriting separator (section < parent) */
public static $sectionSeparator = ' < ';
/** @var string raw section marker */
public static $rawSection = '!';
/**
* Static class - cannot be instantiated.
*/
final public function __construct()
{
throw new Nette\StaticClassException;
}
/**
* Reads configuration from INI file.
* @param string file name
* @return array
* @throws Nette\InvalidStateException
*/
public static function load($file)
{
if (!is_file($file) || !is_readable($file)) {
throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
}
Nette\Diagnostics\Debugger::tryError();
$ini = parse_ini_file($file, TRUE);
if (Nette\Diagnostics\Debugger::catchError($e)) {
throw new Nette\InvalidStateException('parse_ini_file(): ' . $e->getMessage(), 0, $e);
}
$separator = trim(self::$sectionSeparator);
$data = array();
foreach ($ini as $secName => $secData) {
// is section?
if (is_array($secData)) {
if (substr($secName, -1) === self::$rawSection) {
$secName = substr($secName, 0, -1);
} elseif (self::$keySeparator) {
// process key separators (key1> key2> key3)
$tmp = array();
foreach ($secData as $key => $val) {
$cursor = & $tmp;
foreach (explode(self::$keySeparator, $key) as $part) {
if (!isset($cursor[$part]) || is_array($cursor[$part])) {
$cursor = & $cursor[$part];
} else {
throw new Nette\InvalidStateException("Invalid key '$key' in section [$secName] in file '$file'.");
}
}
$cursor = $val;
}
$secData = $tmp;
}
// process extends sections like [staging < production] (with special support for separator ':')
$parts = $separator ? explode($separator, strtr($secName, ':', $separator)) : array($secName);
if (count($parts) > 1) {
$parent = trim($parts[1]);
if (!isset($data[$parent]) || !is_array($data[$parent])) {
throw new Nette\InvalidStateException("Missing parent section [$parent] in file '$file'.");
}
$secData = array_reverse(Nette\Utils\Arrays::mergeTree(array_reverse($secData, TRUE), array_reverse($data[$parent], TRUE)), TRUE);
$secName = trim($parts[0]);
if ($secName === '') {
throw new Nette\InvalidStateException("Invalid empty section name in file '$file'.");
}
}
}
if (self::$keySeparator) {
$cursor = & $data;
foreach (explode(self::$keySeparator, $secName) as $part) {
if (!isset($cursor[$part]) || is_array($cursor[$part])) {
$cursor = & $cursor[$part];
} else {
throw new Nette\InvalidStateException("Invalid section [$secName] in file '$file'.");
}
}
} else {
$cursor = & $data[$secName];
}
if (is_array($secData) && is_array($cursor)) {
$secData = Nette\Utils\Arrays::mergeTree($secData, $cursor);
}
$cursor = $secData;
}
return $data;
}
/**
* Write INI file.
* @param mixed
* @param string file
* @return void
*/
public static function save($config, $file)
{
$output = array();
$output[] = '; generated by Nette';// at ' . @strftime('%c');
$output[] = '';
foreach ($config as $secName => $secData) {
if (!(is_array($secData) || $secData instanceof \Traversable)) {
throw new Nette\InvalidStateException("Invalid section '$secName'.");
}
$output[] = "[$secName]";
self::build($secData, $output, '');
$output[] = '';
}
if (!file_put_contents($file, implode(PHP_EOL, $output))) {
throw new Nette\IOException("Cannot write file '$file'.");
}
}
/**
* Recursive builds INI list.
* @param array|\Traversable
* @param array
* @param string
* @return void
*/
private static function build($input, & $output, $prefix)
{
foreach ($input as $key => $val) {
if (is_array($val) || $val instanceof \Traversable) {
self::build($val, $output, $prefix . $key . self::$keySeparator);
} elseif (is_bool($val)) {
$output[] = "$prefix$key = " . ($val ? 'true' : 'false');
} elseif (is_numeric($val)) {
$output[] = "$prefix$key = $val";
} elseif (is_string($val)) {
$output[] = "$prefix$key = \"$val\"";
} else {
throw new Nette\InvalidArgumentException("The '$prefix$key' item must be scalar or array, " . gettype($val) ." given.");
}
}
}
}
ACC SHELL 2018