From 82ee59779ea9a5d2d9234e622f56cfcc4c22ff3a Mon Sep 17 00:00:00 2001 From: Christian Weiske Date: Thu, 21 Jul 2011 21:32:48 +0200 Subject: [PATCH] support global and per-host configuration files --- src/SemanticScuttle/Config.php | 109 ++++++++++++++ src/SemanticScuttle/header.php | 17 ++- tests/SemanticScuttle/ConfigTest.php | 206 +++++++++++++++++++++++++++ 3 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 src/SemanticScuttle/Config.php create mode 100644 tests/SemanticScuttle/ConfigTest.php diff --git a/src/SemanticScuttle/Config.php b/src/SemanticScuttle/Config.php new file mode 100644 index 0000000..0773310 --- /dev/null +++ b/src/SemanticScuttle/Config.php @@ -0,0 +1,109 @@ + + * @license AGPL http://www.gnu.org/licenses/agpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * Configuration handling + * + * @category Bookmarking + * @package SemanticScuttle + * @author Christian Weiske + * @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); + } +} + +?> \ No newline at end of file diff --git a/src/SemanticScuttle/header.php b/src/SemanticScuttle/header.php index 6c0d4df..9252300 100644 --- a/src/SemanticScuttle/header.php +++ b/src/SemanticScuttle/header.php @@ -25,8 +25,19 @@ if ('@data_dir@' == '@' . 'data_dir@') { //FIXME: when you have multiple installations, the www_dir will be wrong $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'); die( '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) -require_once $datadir . '/config.default.php'; -require_once $datadir . '/config.php'; +require_once $defaultfile; +require_once $configfile; if (isset($_GET['unittestMode']) && $_GET['unittestMode'] == 1 ) { diff --git a/tests/SemanticScuttle/ConfigTest.php b/tests/SemanticScuttle/ConfigTest.php new file mode 100644 index 0000000..670f82a --- /dev/null +++ b/tests/SemanticScuttle/ConfigTest.php @@ -0,0 +1,206 @@ +_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() + ); + } + +} + +?> \ No newline at end of file