<?php
/**
*
* @author Benjamin Gillissen <hide@address.com>
*
* **************************************************************
Copyright (C) 2009 Benjamin Gillissen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details at:
http://www.gnu.org/copyleft/gpl.html
* **************************************************************
*/
class configs {
const speed = TRUE;
private static $CONF=Array();
private static $LOADED=Array();
private static $OVERLAY=Array();
public static function get($file, $ref=NULL, $subs=NULL, $type='opt'){
//echo "Config::get($file, $ref, ".print_r($subs, TRUE).")<br/>";
$base = self::read($file, $type);
if ( isset(self::$OVERLAY[$file]) ){
//echo "Overlay is present<br/>";
$over = &self::$OVERLAY[$file];
} else {
$over = Array();
}
if ( $base === FALSE ){
//echo 'nobase<br/>';
return FALSE;
}
if ( $ref === NULL ){ return array_merge($over, $base); }
if ( !isset($base[$ref]) AND !isset($over[$ref]) ){
//echo 'nobase, noover a first level<br/>';
return FALSE;
}
if ( $subs === NULL ){
if ( isset($over[$ref]) ){
if ( is_array($over[$ref]) ){
if ( isset($base[$ref]) ){ return array_merge($base[$ref], $over[$ref]); }
}
return $over[$ref];
}
if ( !isset($base[$ref]) ){ return FALSE; }
return $base[$ref];
} elseif ( !is_array($subs) ){
//echo 'subs is not an array<br/>';
if ( isset($over[$ref][$subs]) ){
//echo 'returning overlay value<br/>';
return $over[$ref][$subs];
}
if ( !isset($base[$ref][$subs]) ){
//echo 'returning false, not set<br/>';
return FALSE;
}
//echo 'returning base value<br/>';
return $base[$ref][$subs];
} else {
if ( isset($base[$ref]) ){ $btmp = $base[$ref]; } else { $btmp = Array(); }
if ( isset($over[$ref]) ){ $otmp = $over[$ref]; }
unset($base);
//echo 'Recursive search for '.print_r($subs, TRUE)."<br/>\n";
foreach($subs as $depth => $key ){
if ( isset($btmp[$key]) ){
$btmp = $btmp[$key];
} else {
unset($btmp);
}
//echo "$depth] $key checking overlay<br/>\n";
if ( isset($otmp[$key]) ){
$otmp = $otmp[$key];
} else {
unset($otmp);
}
}
if ( isset($otmp) ){ return $otmp; }
if ( isset($btmp) ){ return $btmp; }
return FALSE;
}
}
public static function set($file, $ref, $val, $subs=NULL, $type='opt'){
//define new value into overlay, will not set something that is set in file conf,
//but check only last depth. so i can define new channel
$base = self::read($file, $type);
if ( $subs === NULL ){
if ( isset($base[$ref]) ){
if ( !is_array($base[$ref]) OR !is_array($val) ){
//errors::raise('Configuration runtime overwrite is not allowed !', CORE_LOG_ERROR, 'CONF');
return FALSE;
}
}
self::$OVERLAY[$file][$ref] = $val;
return TRUE;
} elseif ( !is_array($subs) ){
if ( isset($base[$ref][$subs]) ){
errors::raise('Configuration runtime overwrite is not allowed !', CORE_LOG_ERROR, 'CONF');
return FALSE;
}
self::$OVERLAY[$file][$ref][$subs] = $val;
return TRUE;
} else {
if ( isset($base[$ref]) ){ $btmp = $base[$ref]; } else { $btmp = Array(); }//$btmp = $base[$ref];
unset($base);
foreach($subs as $depth => $key ){
if ( isset($btmp[$key]) ){ $btmp = $btmp[$key]; } else { unset($btmp); }
}
if ( isset($btmp) ){
errors::raise('Configuration runtime overwrite is not allowed !', CORE_LOG_ERROR, 'CONF');
return FALSE;
}
if ( !isset(self::$OVERLAY[$file][$ref]) ){ self::$OVERLAY[$file][$ref] = Array(); }
$tmp = & self::$OVERLAY[$file][$ref];
foreach($subs as $depth => $key ){
if ( $depth == count($subs)-1 ){
$tmp[$key] = $val;
return TRUE;
} elseif ( !isset($tmp[$key]) ){
$tmp[$key] = Array();
}
$tmp = & $tmp[$key];
}
}
return FALSE;
}
private static function read($file, $type='opt'){
if ( isset(self::$LOADED[$file]) ){
if ( self::$LOADED[$file] === FALSE ) {
return FALSE;
} elseif (self::speed ){
return unserialize(self::$CONF[$file]);
}
}
if ( $type === 'opt' ){
$p = CORE::getdeps(PATH_OPTS, $file, NULL, 'opt', 'php');
} elseif ( $type === 'cnf' ){
$p = CORE::getdeps(PATH_OPTS, $file, NULL, 'cnf', 'php');
} else {
errors::raise("Option : Invalid file type '$type', only 'opt' and 'cnf' are valid !", CORE_LOG_ERROR, 'CONF');
return FALSE;
}
if ( FALSE === $p ){
//echo "config: $file notfound, send event<br/>\n";
self::$LOADED[$file] = FALSE;
errors::raise("Option : missing file $file.opt.php, not found in ".PATH_OPTS." !", CORE_LOG_WARNING, 'CONF');
return FALSE;
} elseif ( !is_readable($p) ){
//echo "config: $file noread, send event<br/>\n";
self::$LOADED[$file] = FALSE;
errors::raise("Option : file $file is not readable !", CORE_LOG_WARNING, 'CONF');
return FALSE;
} elseif ( REDIRECT_PHP_ERRORS ){
if ( ! assert('(FALSE !== ($buf = include($p)) )') ){
//echo "config: $file assertfailure, send event<br/>\n";
self::$LOADED[$file] = FALSE;
errors::raise("Option : assert failed for file $file !", CORE_LOG_ERROR, 'CONF');
return FALSE;
}
} else {
$buf = include($p);
}
self::$LOADED[$file] = is_array($buf);
if ( FALSE === self::$LOADED[$file] ){
errors::raise("Option : file $file didn't return an array !", CORE_LOG_ERROR, 'CONF');
return FALSE;
}
if ( self::speed ){
self::$CONF[$file] = serialize($buf);
unset($buf);
}
//errors::raise('Configuration : "'.$file.'" has been loaded', CORE_LOG_DEBUG, 'CONF');
if ( self::speed ){
//errors::raise("$file configuration is using ".round(strlen(self::$CONF[$file])/1024, 2)."KBytes of memory", CORE_LOG_NOTICE, 'CONF');
return self::read($file, $type);
}
return $buf;
}
public static function loaded(){
foreach(self::$LOADED as $file => $null){ $o[] = $file; }
if ( !isset($o) ){ return Array(); }
return $o;
}
}