Custom Configuration Files

Custom Configuration Files

Many applications, including Web-based applications written in PHP, have "installation variables'' that need to be set by the systems administrator. These variables usually switch features on and off, specify limits and ranges, server hostnames, and addresses, and define server paths to features.

The way to allow these values to be changed is to specify one or more configuration files for your installation. These will be modified by the systems administrator at the time of deployment to make your application work correctly. These can be implemented in a number of ways, including using native PHP and external XML and INI files.

Using PHP

In some cases, you will be the systems administrator, in which case it is perfectly acceptable to include a file named constants.phpm and specify constant declarations one by one, as in the example following:

   <?    # Hostname or IP address of the Windows SQL Server    define("DATABASE_HOST", "winsqldb");    # Username and password for database    define("DATABASE_USER", "xyz");    define("DATABASE_PASS", "abc");    # Database name    define("DATABASE_NAME", "def");    ?> 

You can then access these properties directly from your code by referring to the name of the constant, as shown in the following code excerpt, in which a connection is established using those constants if a valid connection handle does not already exist:

   if (!(array_key_exists("db", $GLOBALS))) {     $GLOBALS["db"] = mssql_connect(DATABASE_HOST, DATABASE_USER, DATABASE_PASS);     mssql_select_db(DATABASE_NAME);    }; 

This approach is remarkably simple, but you are exposing yourself to problems if there is a requirement for anybody other than a PHP-literate individual to modify the configuration file. Many systems administrators working for your clients' IS departments will be perfectly able to modify a configuration file but could easily make errors such as omitting a semicolon when modifying PHP. In these environments, using PHP as the basis for your configuration files will not be appropriate.

Using XML

Given that PHP5 has excellent support for parsing XML, there is some argument for using it as a configuration file syntax, as shown in the following example, which you might name config.xml:

   <database>      <hostname>winsqldb</hostname>      <hostusername>xyz</hostusername>      <hostpassword>abc</hostpassword>      <hostdbname>def</hostdbname>    </database> 

This could be relatively easily parsed using Simple XML:

   $confFileObject = simplexml_load_file("config.xml");    $strDatabaseHostname = $confFileObject->hostname; 

This approach has advantages over using straight PHP in that it is immune to accidental invalidation through ignorance of PHP. However, the same problem manifests itself to a lesser extent in that some knowledge of XML is still required, especially when dealing with more complex structures. It is by no means obvious, for example, even to the most seasoned expert, which characters have to be escaped before they can be included in a valid XML document.

Another disadvantage is that it can be relatively difficult to read XML on-screen, especially if your configuration file has large amounts of it. Comments guiding the editor are almost impossible to include in any detail, too.

Using INI Files

The final and preferred approach is to use an .INI file. This is a somewhat arbitrary format that has sprung up over the years but which has been adapted as an informal standard, helped in particular by the popularity of Windows. Windows formerly used INI files in its 16-bit incarnations prior to the invention of the Windows Registry.

INI files are incredibly simple to read and edit, and they allow comments to be easily injected to help with the editing process. The nature of comments means that one can easily comment out an objectionable parameter with a simple keystroke.

The Universal Format for INI Files

There is an accepted format for INI files that looks something like the following. You might name this file config.ini:

   ; This is a sample configuration file using INI format    [database]    ; Hostname or IP address of the Windows SQL Server    DATABASE_HOST = winsqldb    ; Username and password for database    DATABASE_USER = xyz    DATABASE_PASS = abc    # Database name    DATABASE_NAME = def    [server_paths]    installation_path = /home/ed/public_html/application    public_url = "" 

Note that all parameters are specified using the format

   NAME = value 

The name of the parameter should not contain spaces. A space should follow the name of the parameter, followed by the equal sign, followed by another space and then the value. Values may not span more than one line.

Different sections may be specified in the INI file to allow your user tasked with modifying it to find his or her way around more easily. These are delineated using an opening square bracket, the name of the section, and a closing square bracket. Finally, comments may be specified in the INI file using a semicolon to start a line.

Parsing INI Files using PHP's Built-In Methods

Given that PHP's own INI file is written in this format, and that PHP must parse it in order to function correctly, PHP's authors sensibly decided to make this routine available to you, the programmer. These routines are in fact written using the Finite State Machine methodology you met in the first half of this chapter.

The routine is called parse_ini_file, and takes two parameters one showing the path to the INI file (which must be local) and the other establishing whether the names of sections should be included in the output array. If this second parameter is set to true, a multidimensional array is generated that resembles the following:

   Array    (        [database] => Array            (                [DATABASE_HOST] => winsqldb                [DATABASE_USER] => xyz                [DATABASE_PASS] => abc                [DATABASE_NAME] => def            )        [server_paths] => Array            (                [installation_path] => /home/ed/public_html/application                [public_url] =>            )    ) 

If it is set to false, a single-dimensional associative array is created that ignores section headers. In this case, the output resembles the following:

   Array    (          [DATABASE_HOST] => winsqldb          [DATABASE_USER] => xyz          [DATABASE_PASS] => abc          [DATABASE_NAME] => def          [installation_path] => /home/ed/public_html/application          [public_url] =>    ) 

Be aware that if you do instruct PHP to ignore sections, you must ensure that all parameter names are unique across all sections.

In practice, you use this in your code as follows:

   $confFileArray = parse_ini_file("config.ini");    $strDatabaseHostname = $confFileArray["database"]["DATABASE_HOST"]; 

You may want to pass the parsing of the configuration file into a separate class, which makes native PHP constants available for referral throughout your application.

The Config PEAR Class

Although PHP's built-in routine allows for very simple configuration file parsing, a PEAR class known simply as Config allows for far more sophisticated and flexible parsing of various types of files.

The package is installed in the normal way, but keep in mind that the XML_Util class is a dependency, which must be installed first.

   root@genesis:/scripts# pear install XML_Util    downloading XML_Util-0.5.2.tgz ...    Starting to download XML_Util-0.5.2.tgz (6,540 bytes)    .....done: 6,540 bytes    install ok: XML_Util 0.5.2    root@ genesis:/scripts# pear install Config    downloading Config-1.10.tgz ...    Starting to download Config-1.10.tgz (17,577 bytes)    ......done: 17,577 bytes    install ok: Config 1.10    root@genesis:/scripts# 

Full documentation on the package can be found at, but it's worth looking briefly at some of the more notable features.

Parsing INI Files using Config

Parsing a traditional INI file using the Config class isn't much harder (or any more useful) than using PHP's built-in routine:

   $c = new Config();    $root = &$c->parseConfig("config.ini", "IniFile");    $strDatabaseHostname = $root["DATABASE_HOST"]; 

Note that the parseConfig method takes two parameters. The first is the path to the configuration file you want to parse. The second of these is a string constant specifying the method to use to parse the configuration file.

Parsing XML Files using Config

One thing the Config class can do that PHP can't is natively parse XML configuration files.

   $c = new Config();    $root = &$c->parseConfig("config.xml", "XML");    $strDatabaseHostname = $root["DATABASE_HOST"]; 

Writing Configuration Files using Config

The Config class is also able to write the contents of an associative array to a configuration file, in the format of your choice:

   $myConfig = array("foo" => "bar");    $c = new Config();    $root =& $c->parseConfig($myConfig, "PHPArray");    $c->writeConfig("my.conf", "IniFile"); 

This is an immensely powerful bit of functionality but is arguably open to abuse (discussed in the next section).

Configuration File Best Practice

Configuration files provide an easy way to make your application portable from one deployment to another, without worrying that others may be modifying your PHP code. However, as with all gifts to the PHP programmer, it can be misused.

Don't Write; Just Read

Your own application should concern itself only with reading configuration files, never writing them. If you find that your application has some need to write some piece of data to a configuration file at runtime, you should be using a proper relational database such as PostgreSQL to store that piece of data.

The exception to the rule is if you have provided some form of auto-configuration script for use by your client's IS department. This may legitimately challenge with questions in order to generate a configuration file. This script could quite feasibly be written in PHP, although a shell script might be a better choice.

Cache Me If You Can

Reading a configuration file written in anything other than native PHP has performance implications. Given the stateless nature of HTTP, every single request could quite easily cause this parsing to take place. On a busy site, this could have quite serious implications.

If possible, therefore, you should implement some kind of caching mechanism. The underlying configuration file is not likely to change frequently, so you should consider implementing some means of translating an INI or XML file into native PHP using the Config PEAR class, and then simply including that native PHP in your application. You could implement a timestamp check on the native INI file to determine whether it has changed since its last translation and then force a translation only if it has in fact changed.

Keep it Simple

Try to keep the configuration file to an absolute minimum. If a given parameter can be calculated using, for example, the $_SERVER object, do so. This is far better than relying on the systems administrator of your deployment platform to get it right. Second, ask yourself whether there is likely to be any commercial desire to ever change any nonserver specific constants, ranges, or limits found in the configuration file. If the answer is no, then don't include them. Hard-code them instead.

Professional PHP5 (Programmer to Programmer Series)
Professional PHP5 (Programmer to Programmer Series)
Year: 2003
Pages: 182
BUY ON AMAZON © 2008-2017.
If you may any questions please contact us: