support global and per-host configuration files

This commit is contained in:
Christian Weiske 2011-07-21 21:32:48 +02:00
parent 846e3a38cf
commit 82ee59779e
3 changed files with 329 additions and 3 deletions

View file

@ -0,0 +1,109 @@
<?php
/**
* SemanticScuttle - your social bookmark manager.
*
* PHP version 5.
*
* @category Bookmarking
* @package SemanticScuttle
* @author Christian Weiske <cweiske@cweiske.de>
* @license AGPL http://www.gnu.org/licenses/agpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
/**
* Configuration handling
*
* @category Bookmarking
* @package SemanticScuttle
* @author Christian Weiske <cweiske@cweiske.de>
* @license AGPL http://www.gnu.org/licenses/agpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
class SemanticScuttle_Config
{
/**
* Prefix for configuration files.
* Used to inject stream wrapper protocol for unit testing
*
* @var string
*/
public $filePrefix = '';
/**
* Finds the correct data directory
*
* @return string Full path to the data directory with a trailing slash
*/
protected function getDataDir()
{
if ('@data_dir@' == '@' . 'data_dir@') {
//non pear-install
$datadir = dirname(__FILE__) . '/../../data/';
} else {
//pear installation; files are in include path
$datadir = '@data_dir@/SemanticScuttle/';
}
return $datadir;
}
/**
* Tries to find a configuration file by looking in different
* places:
* - pear data_dir/SemanticScuttle/config-$hostname.php
* - pear data_dir/SemanticScuttle/config.php
* - /etc/semanticscuttle/config-$hostname.php
* - /etc/semanticscuttle/config.php
*
* Paths with host name have priority.
*
* @return array Array with config file path as first value
* and default config file path as second value.
* Any may be NULL if not found
*/
public function findFiles()
{
//use basename to prevent path injection
$host = basename($_SERVER['HTTP_HOST']);
$datadir = $this->getDataDir();
$arFiles = array(
$datadir . 'config.' . $host . '.php',
'/etc/semanticscuttle/config.' . $host . '.php',
$datadir . 'config.php',
'/etc/semanticscuttle/config.php',
);
$configfile = null;
foreach ($arFiles as $file) {
if (file_exists($this->filePrefix . $file)) {
$configfile = $file;
break;
}
}
//find default file
$arDefaultFiles = array_unique(
array(
substr($configfile, 0, -3) . 'default.php',
$datadir . 'config.default.php',
'/etc/semanticscuttle/config.default.php',
)
);
$defaultfile = null;
foreach ($arDefaultFiles as $file) {
if (file_exists($this->filePrefix . $file)) {
$defaultfile = $file;
break;
}
}
return array($configfile, $defaultfile);
}
}
?>

View file

@ -25,8 +25,19 @@ if ('@data_dir@' == '@' . 'data_dir@') {
//FIXME: when you have multiple installations, the www_dir will be wrong //FIXME: when you have multiple installations, the www_dir will be wrong
$wwwdir = '@www_dir@/SemanticScuttle/'; $wwwdir = '@www_dir@/SemanticScuttle/';
} }
require_once dirname(__FILE__) . '/Config.php';
if (!file_exists($datadir . '/config.php')) { $cfg = new SemanticScuttle_Config();
list($configfile, $defaultfile) = $cfg->findFiles();
if ($defaultfile === null) {
header('HTTP/1.0 500 Internal Server Error');
die(
'No default configuration file config.default.php found.'
. ' This is really, really strange'
. "\n"
);
}
if ($configfile === null) {
header('HTTP/1.0 500 Internal Server Error'); header('HTTP/1.0 500 Internal Server Error');
die( die(
'Please copy "config.php.dist" to "config.php" in data/ folder.' 'Please copy "config.php.dist" to "config.php" in data/ folder.'
@ -39,8 +50,8 @@ set_include_path(
); );
// 1 // First requirements part (before debug management) // 1 // First requirements part (before debug management)
require_once $datadir . '/config.default.php'; require_once $defaultfile;
require_once $datadir . '/config.php'; require_once $configfile;
if (isset($_GET['unittestMode']) && $_GET['unittestMode'] == 1 if (isset($_GET['unittestMode']) && $_GET['unittestMode'] == 1
) { ) {

View file

@ -0,0 +1,206 @@
<?php
//that's PEAR's Stream_Var package
require_once 'Stream/Var.php';
class SemanticScuttle_ConfigTest_StreamVar extends Stream_Var {
public function url_stat($path, $flags)
{
$url = parse_url($path);
$scope = $url['host'];
if (isset($url['path'])) {
$varpath = substr($url['path'], 1);
} else {
$varpath = '';
}
if (!$this->_setPointer($scope, $varpath)) {
return false;
}
return parent::url_stat($path, $flags);
}
}
class SemanticScuttle_ConfigTest extends PHPUnit_Framework_TestCase
{
/**
* Configuration object to test
*/
protected $cfg;
public function setUpWrapper()
{
if (!in_array('unittest', stream_get_wrappers())) {
stream_wrapper_register(
'unittest', 'SemanticScuttle_ConfigTest_StreamVar'
);
}
$this->cfg = $this->getMock(
'SemanticScuttle_Config',
array('getDataDir')
);
$this->cfg->expects($this->once())
->method('getDataDir')
->will($this->returnValue('/data-dir/'));
$this->cfg->filePrefix = 'unittest://GLOBALS/unittest-dir';
}
public function testFindLocalData()
{
$this->setUpWrapper();
$GLOBALS['unittest-dir']['data-dir'] = array(
'config.php' => 'content',
'config.default.php' => 'content'
);
$this->assertEquals(
array(
'/data-dir/config.php',
'/data-dir/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindHostPreferredOverNonHostConfig()
{
$this->setUpWrapper();
$_SERVER['HTTP_HOST'] = 'foo.example.org';
$GLOBALS['unittest-dir']['data-dir'] = array(
'config.php' => 'content',
'config.foo.example.org.php' => 'content',
'config.default.php' => 'content'
);
$this->assertEquals(
array(
'/data-dir/config.foo.example.org.php',
'/data-dir/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindEtcHostPreferredOverLocalConfigPhp()
{
$this->setUpWrapper();
$_SERVER['HTTP_HOST'] = 'foo.example.org';
$GLOBALS['unittest-dir'] = array(
'etc' => array(
'semanticscuttle' => array(
'config.foo.example.org.php' => 'content',
)
),
'data-dir' => array(
'config.php' => 'content',
'config.default.php' => 'content'
)
);
$this->assertEquals(
array(
'/etc/semanticscuttle/config.foo.example.org.php',
'/data-dir/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindEtcConfig()
{
$this->setUpWrapper();
$GLOBALS['unittest-dir'] = array(
'etc' => array(
'semanticscuttle' => array(
'config.php' => 'content'
)
),
'data-dir' => array(
'config.default.php' => 'content'
)
);
$this->assertEquals(
array(
'/etc/semanticscuttle/config.php',
'/data-dir/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindEtcDefaultConfig()
{
$this->setUpWrapper();
$GLOBALS['unittest-dir'] = array(
'etc' => array(
'semanticscuttle' => array(
'config.php' => 'content',
'config.default.php' => 'content'
)
),
);
$this->assertEquals(
array(
'/etc/semanticscuttle/config.php',
'/etc/semanticscuttle/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindLocalDefaultPreferredOverEtcDefault()
{
$this->setUpWrapper();
$GLOBALS['unittest-dir'] = array(
'etc' => array(
'semanticscuttle' => array(
'config.php' => 'content',
'config.default.php' => 'content'
)
),
'data-dir' => array(
'config.php' => 'content',
'config.default.php' => 'content'
)
);
$this->assertEquals(
array(
'/data-dir/config.php',
'/data-dir/config.default.php'
),
$this->cfg->findFiles()
);
}
public function testFindSameDirDefaultPreferred()
{
$this->setUpWrapper();
$GLOBALS['unittest-dir'] = array(
'etc' => array(
'semanticscuttle' => array(
'config.php' => 'content',
'config.default.php' => 'content'
)
),
'data-dir' => array(
'config.default.php' => 'content'
)
);
$this->assertEquals(
array(
'/etc/semanticscuttle/config.php',
'/etc/semanticscuttle/config.default.php'
),
$this->cfg->findFiles()
);
}
}
?>