This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Reading and Writing Configuration Files
Most of my functions depends on settings.
As of now I'm storing my setting values in database.
For example to display ad in a page i'm checking my database whether to display ad or not
I mean like this
$display_ad = 'get value from database';
if ($display_ad) {
echo 'Ad code goes here';
}
This is fine. But the fact is I have more than 100 settings. So I think my databse load will be reduced if I define the value in a settings.php file like
define('DISPLAY_AD', true);
if (DISPLAY_AD) {
echo 'Ad code goes here';
}
But I'm not sure this is the right way. Is define() is the correct solution. Or is there any better and faster solution available?
Several options, like those mentioned, include .ini files (using parse_ini_file(), etc.), XML (some concoction with SimpleXML perhaps) but I prefer keeping config in native PHP.
The include() construct allows for one to return from the included file. This allows you to:
config.php
return [
'foo' => [
'bar' => [
'qux' => true,
],
'zip' => false,
],
];
elsewhere.php
function loadConfig($file) {
if (!is_file($file)) {
return false;
}
return (array) call_user_func(function() use($file) {
// I always re-scope for such inclusions, however PHP 5.4 introduced
// $this rebinding on closures so it's up to you
return include($file);
});
}
$config = loadConfig('config.php');
if ($config['foo']['bar']['qux']) {
// yeop
}
if ($config['foo']['zip']) {
// nope
}
Special care needs to be taken, as when you try to dereference a non-existent dimension, PHP will poop on you:
if ($config['i']['am']['not']['here']) { // poop
}
Creating a wrapper class/functions to manage configuration to your needs is reasonably trivial though. You can add support for cascading configuration (a la web.config in the ASP world), caching, etc.
define() is quite a good way of doing things. An alternative is to define a global array. such as
$config['display_ad']=true;
$config['something_else']='a value';
//...
function doSomething() {
global $config;
if ($config['display_ad']) echo 'Ad code goes here';
}
The latter way is what many projects use, such as phpmyadmin, the reason could be, that you cannot define() a non-scalar value, e.g. define('SOME_ARRAY',array('a','b')) is invalid.
The simplest thing to execute would be an ini file. You create a file that looks like this:
value1 = foo
value2 = bar
value3 = baz
Then, from PHP, you can execute this:
$iniList = get_ini_file("/path/to/ini/file/you/just/made");
if ($iniList['value1'] == 'foo') {
print "This will print because the value was set from get_ini_file."
}
If you have a lot of similar constants, that's better than dozens of define methods and quicker than database fetches.
you can allso make a class like here:
php.net
Related
I have Googled for the past couple hours trying to figure out how to do this. I just want to be clear that my issue is not this issue or that issue, because I am not trying to check inside the script if the variables are set. I am trying to check outside it, to see if they're set / passed to the included file before they're interpreted, or at least meaningfully interpreted to the point where an error is thrown. Let me explain.
A little Background
I am creating a utility package for internal usage at the company I work for. I have chosen to render templates one of two ways: including them or outputting the rendered string.
public function render($context = array()) {
do_action(self::TAG_CLASS_NAME.'_render_view', $this, $context);
if ( empty( $this->html ) ) {
ob_start();
$this->checkContext($context);
extract( $context );
require_once $this->getFullPath();
$renderedView = ob_get_contents();
ob_end_clean();
$this->html = $renderedView;
return $renderedView;
} else {
return $this->html;
}
}
public function includeView($context = array()) {
do_action(self::TAG_CLASS_NAME.'_include_view', $this, $context);
extract( $context );
include $this->getFullPath();
}
The problem
Inside of the render method, I start some output buffering. This is so I can have the interpreter evaluate the code and output the HTML as a string (without taking the eval() hit. Inside my unit tests, I experiemented with what would happen if I left out a context that was inside the template itself. For example: If I have a context array that looks like:
$context = array(
'message' => 'Morning'
);
And an associated template that looks like this:
<?php echo "Hello ".$name."! Good ".$message; ?>
Or this
<p>Hello <?php echo $name; ?>! Good <?php echo $message; ?></p>
Doesn't matter how it's formatted, as long as the context vars are passed to it correctly. Anyway, leaving out the $name in the context will result in a "Undefined variable: $name" E_NOTICE message. Which makes sense. How do you 'capture' that undefined variable before it creates the notice?
I have tried to use:
$rh = fopen($this->getFullPath(), 'r');
$contents = fread($rh, filesize($this->getFullPath()));
fclose($rh);
Where $contents outputs:
"<?php echo sprintf("Hello %s, Good %s.", $name, $greeting); ?>"
The next logical step (for me anyway, thus the question) is to extract the vars in that string. So I briefly started down the road of creating a regex to match on that string and capture the variables, but ended up on here, because I felt like I was duplicating work. I mean, the PHP interpreter already does this effectively, so there must be a way to utilize the built-in functionality. Maybe?
All this to say, I want to do something similar to this psuedo code:
protected function checkContext($context) {
require $filename;
$availVars = get_defined_vars()
if ( $availVars !== $context ) {
setUnDefinedVar = null
}
}
Having said that, this may not even be the right way to do it, but what is? Do I let the interpreter fail on an undefined variable upon inclusion of the file? If I let it fail, am I exposing myself to any security vulnerabilities? Note: I am not setting any variables in templates via $_GET or $_POST.
Any answers are much appreciated. Thank you ahead of time.
I recommend using getters and setters within your class. There may be a better solution but this is how I do it. Since you're trying to access variables in the global scope you would add the following method to the class calling the included file:
public function __get($variable)
{
if (array_key_exists( $variable, $GLOBALS ))
return $GLOBALS[$variable];
return null;
}
So now in your included file you would access variables by using the
$this->{$variableName}
In your specific case, it would look like...
<?php echo "Hello ".$this->name."! Good ".$this->message; ?>
However please note, if the variable requested is defined in the scope of the calling class then that particular member variable will be returned. Not one defined in the global scope.
A better explanation of this overloading operator may be found here PHP Magic Methods
I want to create a config file for my PHP project, but I'm not sure what the best way to do this is.
I have 3 ideas so far.
1-Use Variable
$config['hostname'] = "localhost";
$config['dbuser'] = "dbuser";
$config['dbpassword'] = "dbpassword";
$config['dbname'] = "dbname";
$config['sitetitle'] = "sitetitle";
2-Use Const
define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
define('TITLE', 'sitetitle');
3-Use Database
I will be using the config in classes so I'm not sure which way would be the best or if there is a better way.
One simple but elegant way is to create a config.php file (or whatever you call it) that just returns an array:
<?php
return array(
'host' => 'localhost',
'username' => 'root',
);
And then:
$configs = include('config.php');
Use an INI file is a flexible and powerful solution! PHP has a native function to handle it properly. For example, it is possible to create an INI file like this:
app.ini
[database]
db_name = mydatabase
db_user = myuser
db_password = mypassword
[application]
app_email = mailer#myapp.com
app_url = myapp.com
So the only thing you need to do is call:
$ini = parse_ini_file('app.ini');
Then you can access the definitions easily using the $ini array.
echo $ini['db_name']; // mydatabase
echo $ini['db_user']; // myuser
echo $ini['db_password']; // mypassword
echo $ini['app_email']; // mailer#myapp.com
IMPORTANT: For security reasons the INI file must be in a non public folder
I use a slight evolution of #hugo_leonardo 's solution:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db'
);
?>
This allows you to use the object syntax when you include the php : $configs->host instead of $configs['host'].
Also, if your app has configs you need on the client side (like for an Angular app), you can have this config.php file contain all your configs (centralized in one file instead of one for JavaScript and one for PHP). The trick would then be to have another PHP file that would echo only the client side info (to avoid showing info you don't want to show like database connection string). Call it say get_app_info.php :
<?php
$configs = include('config.php');
echo json_encode($configs->app_info);
?>
The above assuming your config.php contains an app_info parameter:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db',
'app_info' => array(
'appName'=>"App Name",
'appURL'=> "http://yourURL/#/"
)
);
?>
So your database's info stays on the server side, but your app info is accessible from your JavaScript, with for example a $http.get('get_app_info.php').then(...); type of call.
The options I see with relative merits / weaknesses are:
File based mechanisms
These require that your code look in specific locations to find the ini file. This is a difficult problem to solve and one which always crops up in large PHP applications. However you will likely need to solve the problem in order to find the PHP code which gets incorporated / re-used at runtime.
Common approaches to this are to always use relative directories, or to search from the current directory upwards to find a file exclusively named in the base directory of the application.
Common file formats used for config files are PHP code, ini formatted files, JSON, XML, YAML and serialized PHP
PHP code
This provides a huge amount of flexibility for representing different data structures, and (assuming it is processed via include or require) the parsed code will be available from the opcode cache - giving a performance benefit.
The include_path provides a means for abstracting the potential locations of the file without relying on additional code.
On the other hand, one of the main reasons for separating configuration from code is to separate responsibilities. It provides a route for injecting additional code into the runtime.
If the configuration is created from a tool, it may be possible to validate the data in the tool, but there is no standard function to escape data for embedding into PHP code as exists for HTML, URLs, MySQL statements, shell commands....
Serialized data
This is relatively efficient for small amounts of configuration (up to around 200 items) and allows for use of any PHP data structure. It requires very little code to create/parse the data file (so you can instead expend your efforts on ensuring that the file is only written with appropriate authorization).
Escaping of content written to the file is handled automatically.
Since you can serialize objects, it does create an opportunity for invoking code simply by reading the configuration file (the __wakeup magic method).
Structured file
Storing it as a INI file as suggested by Marcel or JSON or XML also provides a simple api to map the file into a PHP data structure (and with the exception of XML, to escape the data and create the file) while eliminating the code invocation vulnerability using serialized PHP data.
It will have similar performance characteristics to the serialized data.
Database storage
This is best considered where you have a huge amount of configuration but are selective in what is needed for the current task - I was surprised to find that at around 150 data items, it was quicker to retrieve the data from a local MySQL instance than to unserialize a datafile.
OTOH its not a good place to store the credentials you use to connect to your database!
The execution environment
You can set values in the execution environment PHP is running in.
This removes any requirement for the PHP code to look in a specific place for the config. OTOH it does not scale well to large amounts of data and is difficult to change universally at runtime.
On the client
One place I've not mentioned for storing configuration data is at the client. Again the network overhead means that this does not scale well to large amounts of configuration. And since the end user has control over the data it must be stored in a format where any tampering is detectable (i.e. with a cryptographic signature) and should not contain any information which is compromised by its disclosure (i.e. reversibly encrypted).
Conversely, this has a lot of benefits for storing sensitive information which is owned by the end user - if you are not storing this on the server, it cannot be stolen from there.
Network Directories
Another interesting place to store configuration information is in DNS / LDAP. This will work for a small number of small pieces of information - but you don't need to stick to 1st normal form - consider, for example SPF.
The infrastucture supports caching, replication and distribution. Hence it works well for very large infrastructures.
Version Control systems
Configuration, like code should be managed and version controlled - hence getting the configuration directly from your VC system is a viable solution. But often this comes with a significant performance overhead hence caching may be advisable.
Well - it would be sort of difficult to store your database configuration data in a database - don't ya think?
But really, this is a pretty heavily opinionated question because any style works really and it's all a matter of preference. Personally, I'd go for a configuration variable rather than constants - generally because I don't like things in the global space unless necessary. None of the functions in my codebase should be able to easily access my database password (except my database connection logic) - so I'd use it there and then likely destroy it.
Edit: to answer your comment - none of the parsing mechanisms would be the fastest (ini, json, etc) - but they're also not the parts of your application that you'd really need to focus on optimizing since the speed difference would be negligible on such small files.
You can create a config class witch static properties
class Config
{
static $dbHost = 'localhost';
static $dbUsername = 'user';
static $dbPassword = 'pass';
}
then you can simple use it:
Config::$dbHost
Sometimes in my projects I use a design pattern SINGLETON to access configuration data. It's very comfortable in use.
Why?
For example you have 2 data source in your project. And you can choose witch of them is enabled.
mysql
json
Somewhere in config file you choose:
$dataSource = 'mysql' // or 'json'
When you change source whole app shoud switch to new data source, work fine and dont need change in code.
Example:
Config:
class Config
{
// ....
static $dataSource = 'mysql';
/ .....
}
Singleton class:
class AppConfig
{
private static $instance;
private $dataSource;
private function __construct()
{
$this->init();
}
private function init()
{
switch (Config::$dataSource)
{
case 'mysql':
$this->dataSource = new StorageMysql();
break;
case 'json':
$this->dataSource = new StorageJson();
break;
default:
$this->dataSource = new StorageMysql();
}
}
public static function getInstance()
{
if (empty(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function getDataSource()
{
return $this->dataSource;
}
}
... and somewhere in your code (eg. in some service class):
$container->getItemsLoader(AppConfig::getInstance()->getDataSource()) // getItemsLoader need Object of specific data source class by dependency injection
We can obtain an AppConfig object from any place in the system and always get the same copy (thanks to static). The init () method of the class is called
In the constructor, which guarantees only one execution. Init() body checks
The value of the config $dataSource, and create new object of specific data source class. Now our script can get object and operate on it, not knowing
even which specific implementation actually exists.
Define will make the constant available everywhere in your class without needing to use global, while the variable requires global in the class, I would use DEFINE. but again, if the db params should change during program execution you might want to stick with variable.
If you think you'll be using more than 1 db for any reason, go with the variable because you'll be able to change one parameter to switch to an entirely different db. I.e. for testing , autobackup, etc.
Here is my way.
<?php
define('DEBUG',0);
define('PRODUCTION',1);
#development_mode : DEBUG / PRODUCTION
$development_mode = PRODUCTION;
#Website root path for links
$app_path = 'http://192.168.0.234/dealer/';
#User interface files path
$ui_path = 'ui/';
#Image gallery path
$gallery_path = 'ui/gallery/';
$mysqlserver = "localhost";
$mysqluser = "root";
$mysqlpass = "";
$mysqldb = "dealer_plus";
?>
Any doubts please comment
One of the simplest form to use config with multiple files is like this:
Files hierarchy:
config
- mail.php
- database.php
mail.php
return [
'smtp_debug' => 0,
];
A helper function:
function config($configFilename, $key)
{
$path = sprintf("config/%s.php", $configFilename);
if (file_exists($path)) {
$config = include sprintf("config/%s.php", $configFilename);
if (isset($config[$key])) {
return $config[$key];
}
}
return '';
}
And you can call it in elegant way:
config('mail','smtp_debug')
I normally end up creating a single conn.php file that has my database connections.
Then i include that file in all files that require database queries.
What about something like this ?
class Configuration
{
private $config;
public function __construct($configIniFilePath)
{
$this->config = parse_ini_file($configIniFilePath, true);
}
/**
* Gets the value for the specified setting name.
*
* #param string $name the setting name
* #param string $section optional, the name of the section containing the
* setting
* #return string|null the value of the setting, or null if it doesn't exist
*/
public function getConfiguration($name, $section = null)
{
$configValue = null;
if ($section === null) {
if (array_key_exists($name, $this->config)) {
$configValue = $this->config[$name];
}
} else {
if (array_key_exists($section, $this->config)) {
$sectionSettings = $this->config[$section];
if (array_key_exists($name, $sectionSettings)) {
$configValue = $sectionSettings[$name];
}
}
}
return $configValue;
}
}
if i have a config file like config.conf (it can be htttp://example.com/config.conf)
user=cacom
version = 2021608
status= true
this is my function:
function readFileConfig($UrlOrFilePath){
$lines = file($UrlOrFilePath);
$config = array();
foreach ($lines as $l) {
preg_match("/^(?P<key>.*)=(\s+)?(?P<value>.*)/", $l, $matches);
if (isset($matches['key'])) {
$config[trim($matches['key'])] = trim($matches['value']);
}
}
return $config;
}
we can use:
$urlRemote = 'http://example.com/default-config.conf';
$localConfigFile = "/home/domain/public_html/config.conf";
$localConfigFile2 = "config.conf";
print_r(readFileConfig($localConfigFile2));
print_r(readFileConfig($localConfigFile));
print_r(readFileConfig($urlRemote));
You can use this simple one:
define('someprop', 0);
and
echo someprop; // output 0
Here it is
<?php
$server = "localhost";
$username = "root";
$password = "";
$db = "your_db_name";
$conn = mysqli_connect($server, $username, $password, $db);
if(!$conn){
die('Error in connecting to server or Database');
}
?>
This question already has answers here:
Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?
(3 answers)
Closed 9 years ago.
I am trying to get figure this out and haven't been able to. I'm trying to create a function that will include different config files into the script when needed. I want to store all the variables in arrays and then use a function to include them.
Example
Config.php
$array = array(
'var1' => 'something',
'var2' => 'something else'
);
uses.php
class uses{
public static function file($directory, $file){
if(is_dir($directory))
{
if(is_file($directory.$file))
{
include $directory.$file;
}
else
{
echo "File Not Found $directory$file";
}
}
else
{
echo 'Dir Not Found';
}
}
}
index.php after I've included uses the file
uses::file(Config.php);
print_r($array);
I know if you include a file inside a function they won't reach past the scope of the function. This would be loaded in by an auto loader so I would be able to use it anywhere inside my script.
Thanks in advance, if you need any more information please let me know.
It appears to me you may be going about this the wrong way. But first off the problems with the code you presented. Your code appears to be asking for two parameters but you are only passing in one. This will make your is_dir / is_file calls always fail because both of the conditions will never be true at the same time so your file isn't include.
Also you don't appear to be assigning the returned value to anything that has a lifetime greater then that of run time of your static function so even if the file was included your config variable would end up being thrown away.
To clean up your existing code you could do something along these lines.
<?php
class Config {
static public $config;
public static function load($path, $file){
if (file_exists($path.$file) && is_file($path.$file)){
self::$config = include ($path.file);
}
}
}
Then you would change your included file to return the data instead of assigning it to a variable. Like
<?php
return array(
'var1' => 'something',
'var2' => 'something else'
);
Then you would be able to use it like this.
Config::load("/path/to/config/", "Config.php");
echo Config::$config["var1"];
While this will make the code behave the way you are trying to do it this is probably a bad idea. You should be using Dependency injection within your other classes instead of invoking the static property with your other classes. This will afford you a seam when doing testing and also allow your methods and classes to document in the constructor and method signatures exactly what is needed to perform a given task. See this video for more information on what DI is, and this google clean code talk to help understand why using statics like this is a bad idea.
Take a look at this: http://php.net/manual/en/function.parse-ini-file.php
But in simple terms you could so this:
config.inc.php
$config['var1'] = 'Hello';
$config['var2'] = 'World';
Then in your php:
include_once('config.inc.php');
or you could use this for an INI style include file: http://php.net/manual/en/function.parse-ini-file.php
config.inc.php
[first_section]
one = 1
five = 5
animal = BIRD
[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username"
Then in your php:
$ini_array = parse_ini_file("sample.ini", true);
print_r($ini_array);
Let me put the requirement to satisfy first
A PHP gateway, and a set of request handlers which uses many constants which currently i am defining in a constants.php with define('conts','value');
I can define this constants in a property file like
const1 =val1
const2 = val2
const3 = val3
in some external file say gateway.properties and load it to define() at runtime. Can this be a one-time action, so that as many threads created by the php can access this constant further, with out reloading it again?
I dont know if this is really possible, i want an expert advice.
Thanks
I would handle this by stuffing the resulting object in memcached.
There is obviously some overhead with this. You will need to weigh whether or not it makes sense for your situation. For 3 variables, it won't make sense at all. For 300,000, maybe it will. Test it and see.
In PHP it is preferred to use .ini files and use
http://php.net/manual/en/function.parse-ini-file.php
or php.net/manual/en/function.parse-ini-string.php if you have read the file to a string already.
You can use apc to cache it in memory with a fallback to reading a file if not already cached and then cache it.
<?php
$ini = apc_fetch('configuration');
if (!$ini) {
$ini = file_get_contents('path/to/ini.ini');
if ($ini) {
apc_store('configuration',$ini);
}
}
$config = parse_ini_string($ini);
You could read each line, parse out the = and define in a for loop.
The easiest way to do this is to store your values in a .ini file, and then read the file in with parse_ini_file(). The ini file would look like:
var1 = 'blah blah blah'
var2 = 'more blah'
PHP reads these files pretty quickly. I suggest that, rather than turn all the values into constants, you store the associative array you get from the .ini file in a single global variable. Let work, same visibility.
If you're really set on caching, you could use the APC cache. It'll save a few miliseconds, but it won't make a difference unless you're talking about a pretty large set of values. And you'll still have to call define() for each value, if you're going to insist on turning them all into constants. Still much faster to save a single global associative array.
Consider using a static class which is globally easy to access.
You can create a class with only public static members and CLASS::init() calls an optional configuration file to replace the variables.
If the value is missing it will stay at it's default.
So you can access the configuration from everywhere using CLASS:$STATIC_VAR
The init function:
$vars = parse_ini_file(dirname(__FILE__) .'/'. $filename,true,INI_SCANNER_TYPED);
if ($vars)
{
foreach ($vars as $key => $val)
{
if (property_exists(get_called_class(),$key)) self::$$key=$val;
}
}
I am trying to decide on the best way to store my applications configuration settings. There are so many options.
The majority of applications I have seen have used a simple require and a PHP file that contains variables. There seem to be far more advanced techniques out there.
What have you used?
What is most efficient?
What is most secure?
We use a file called Local.php which is excluded from the SCM system. It contains several constants or global variables. For example:
// Local.php
class Setting
{
const URL = 'http://www.foo.com';
const DB_User = 'websmith';
}
And it can be referred to anywhere simply by:
Setting::URL
If you need the settings to be writable at runtime, I suggest you use public static variables instead.
The best thing you can do is the simplest thing that could possibly work (php variables) and wrap it up in a class. That way you can change the implementation later without changing any client code. Create an interface that the configuration class implements and make the client code use the interface methods. If you later decide to store configuration in a database or JSON or whatever, you can simply swap out the existing implementation with a new one. Make sure your configuration class is testable and write unit tests.
Try to use php-arrays config files using technique described here: http://www.dasprids.de/blog/2009/05/08/writing-powerful-and-easy-config-files-with-php-arrays
This method allows you to write app configuration in this way:
app.config.php
<?php
return array(
'appname' => 'My Application Name',
'database' => array(
'type' => 'mysql',
'host' => 'localhost',
'user' => 'root',
'pass' => 'none',
'db' => 'mydb',
),
);
This method is secure, cache-able by opcode cachers (APC, XCACHE).
How about:
; <?php die('Direct access not allowed ;') ?>
; The above is for security, do not remove
[database]
name = testing
host = localhost
user = root
pass =
[soap]
enableCache = 1
cacheTtl = 30
Save as config.php (or something like that, must have php extention), and then just load it with:
parse_ini_file('config.php', true);
And you could use
array_merge_recursive(parse_ini_file('config-default.php', true), parse_ini_file('config.php', true))
to merge a default config file with a more specific config file.
The point here is that you can use the very readable ini format, but still be able to have your config file in a public directory.
When you open the file with your browser, php will parse it first and give you the result, which will just be "; Direct access not allowed ;". When you parse the file directly as an ini file, the php die statement will be commented out according to the ini syntax (;) so it will not have any effect then.
I find Zend_Config to be a good solution. You can load the configuration from a simple array, from an INI style file, or from an XML document. Whichever you choose, the configuration object is the same, so you can switch storage formats freely. Zend_Config objects can also be merged, depending on your application this may be useful (a server config, then a per site/installation config).
As with most (or all) things in the Zend Framework, you can easily use Zend_Config by itself.
Considering efficiency, I'd say the fastest method would be to use an array, since that requires less (in this case no) string parsing. However, a INI/XML format may be easier for some to maintain. Of course some caching would give you the best of both worlds.
Also, using INI files with Zend_Config allow you to define sections of configurations that inherit from each other. The most common use is a 'development' section that inherits from the 'production' section, then redefines the DB/debugging settings.
As for security, keeping the config file out of the web root is the first step. Making it read only and limiting access could make it more secure; however, depending on your hosting/server configuration you may be limited in what can be done there.
Just an example of how to implement a central XML/Xpath configuration.
class Config {
private static $_singleton;
private $xml;
static function getInstance() {
if(is_null (self::$_singleton) ) {
self::$_singleton = new self;
}
return self::$_singleton;
}
function open($xml_file) {
$this->xml = simplexml_load_file($xml_file);
return $this;
}
public function getConfig($path=null) {
if (!is_object($this->xml)) {
return false;
}
if (!$path) {
return $this->xml;
}
$xml = $this->xml->xpath($path);
if (is_array($xml)) {
if (count($xml) == 1) {
return (string)$xml[0];
}
if (count($xml) == 0) {
return false;
}
}
return $xml;
}
}
Example call
Config::getInstance()
->open('settings.xml')
->getConfig('/settings/module/section/item');
In my view good solution would be ini files.
I don't prefer config file using arrays/variables for storing settings; here is why:
What if a user accidently re-named your setting variable?
What if a variable with similar name is defined elsewhere too by the user?
Variables in config file may be overwritten some where deep in the script or even included files.
and possibly more problems....
I like to use ini file for setting of my php apps. Here is why:
It is section based
It is easier
You can set values by friendly names
You don't have to worry about variables being overwritten because there are no ones.
No conflict of variables of course.
It allows more flexibility in specifying the types of values.
Note: You need to use parse_ini_file function to read ini files.
It is best to do any core configuration in PHP itself, but if you are using a database and don't mind the extra overhead - you may find some flexibility in storing some settings in the database with a single extra query (assuming you organize it properly).
Either way, storing this data in JSON, INI, XL, etc is just another unneeded abstraction that is done way too much nowadays on the web. Your best bet is pure PHP, unless you like the flexibility of some settings being in the database.
The only reason I can think of to not use php vars as others are suggesting is if you need to switch between configurations in a controlled manner, so there data/behavior consistency during the switch. For example, if you're switching databases, then the system could write locked until the switch-over occurs (to prevent ghost-writes, but dirty reads are still possible).
If things like this are a concern, then you could write a special admin page in your app(pref local access only for security) that locks the system temporarily, then reads and deploys all your changes before unlocking.
If you're running a high traffic site where consistency matters, this is something you'll want to consider. If you can deploy during off hours when there is little/no traffic, then php vars or other standard text formats will be fine.
I like the idea of having "namespaces" or some kind of tree
so you can have:
db.default.user
or
db.readonly.user
and so on.
now regarding code what I did was an interface for the config readers: so you can have a memory reader, array reader, db reader, etc.
and a config class that uses those readers and allow you have a config from any kind of source