views:

604

answers:

10

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?

+5  A: 

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.

Asaph
A: 

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.

monokrome
+2  A: 

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.

Tim Lytle
+4  A: 

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.

gahooa
I like this approach so I can use autoloading for the settings, I wish class const could be set from another variable though like $_SERVER['REMOTE_ADDR']
jasondavis
If you use `SetEnv` in the apache configuration, you can set environment variables which will appear in `$_SERVER`.
gahooa
+1  A: 

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).

Sergey Kuznetsov
A: 

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.

Dana the Sane
+1  A: 

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');
Peter Lindqvist
What about speed? I suppose XPath is not so fast.
Kuroki Kaze
Speed? It depends on your application and how you implement it of course. Zend framework uses XML configuration (among others). Everything is relative.
Peter Lindqvist
A: 

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

Gabriel Sosa
A: 

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.

xyking
+1  A: 

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.

Sarfraz