Skip to main content

Process XML configuration files with PHP

Easily configure PHP applications and objects using XML configuration files

Vikram Vaswani, Founder, Melonfire
Vikram Vaswani is the founder and CEO of Melonfire, a consulting services firm with special expertise in open-source tools and technologies. He is also the author of the books PHP Programming Solutions and How to do Everything with PHP and MySQL.

Summary:  XML provides a convenient, easy-to-use expression language for an application's configuration files. To extract this information into a PHP script can sometimes pose a challenge. That's where the XJConf for PHP package comes in: It provides an API to read XML-encoded information and directly use it to configure PHP data structures like scalars, arrays and PHP objects. This article introduces the package and demonstrates some useful real-world applications of its usage, including configuring complex class trees and building a Web-based configuration interface.

Date:  06 Nov 2007
Level:  Intermediate
Activity:  5681 views

Introduction

As a general rule, when you develop any reasonably-complex piece of software, it's a good idea to take time to identify the product's key configuration variables, and then separate these from the standard variable namespace and place them in a separate area. With this process, you can create a centralized repository of application configuration information and simplify the task of modifying the product to work in different environment. It can also help increase a developer's familiarity with, and understanding of, the key pieces of information needed to get the product up and running.

Traditionally, configuration variables are stored in one (or more) configuration files. The variables are often expressed using XML, which provides a flexible framework for document authors to describe content using custom tags and markup. In most cases, developers also need to construct a user interface to interact with these XML configuration files, to read and use the configuration data contained therein.

XJConf for PHP helps PHP developers with this task. This open-source package provides an API to extract XML-encoded information from a configuration file and turn it into a native data structure, for immediate use within an application. As such, it provides a robust, easy-to-use widget for any PHP application.


Install required software

The XJConf package is maintained by Frank Kleine and Stephan Schmidt, and released to the PHP community under the GNU LGPL. It requires PHP 5.0 (or better), and the easiest way to install it is with the automated PEAR installer, which should have been included by default with your PHP build. To install it, simply issue the following commands at your shell prompt:

shell> pear channel-discover pear.php-tools.net

shell> pear install pat/XJConfForPHP-alpha

The PEAR installer will now connect to the new channel, download the package, and install it to the appropriate location on your system. This article uses XJConf for PHP V. 0.2.0.

To install the package manually, visit its home page, download the source code archive, and manually uncompress the files to the desired location. You'll find links to the package home page, as well as to in-development builds, in the Resources of this article. Note that this manual installation process presupposes some knowledge of PEAR's package organization structure.

One final dependency: the XJConf for PHP package requires that you enable the xmlreader extension of PHP. This extension is enabled by default in PHP 5.1.0 or later. Users of older PHP versions can obtain detailed information and activation instructions from the appropriate section of the PHP manual (see Resources for links).

This article assumes that you have a working knowledge of PHP and XML, and are comfortable using PHP's simple and complex data types. It assumes a reasonable degree of knowledge of both general OOP concepts and the specific class model used by PHP 5, as well as some knowledge of XML tree generation with PHP's Document Object Model (DOM) extension.


Understand basic usage

XJConf provides PHP application developers with an API that reads XML-formatted configuration files and converts the data within them to native PHP data types or custom objects. These data types or objects can then be used within a PHP script in the normal fashion. Any XJConf-based program has three components:

  • The XML-formatted configuration file
  • A PHP script that parses and extracts data from the configuration file
  • A definition file, which maps elements from the configuration file into native PHP structures

The best way to illustrate the interaction of these three components is with an example. Consider Listing 1, which shows an XML configuration file for a pet housecat:


Listing 1. An XML configuration file (cat.xml)
                        
<?xml version='1.0'?>
<cat>
    <name>Martha</name>
    <age>4</age>
    <breed>Siamese</breed>
</cat>
        

Now, suppose you need to read these configuration values into your PHP application. The first step is to create a definition file, which maps each element from Listing 1 to a native PHP data type. Listing 2 illustrates such a file:


Listing 2. An XJConf definition file (defs.xml)
                        
<defines>
	<tag name="name" type="string"/>
	<tag name="breed" type="string"/>
	<tag name="age" type="integer"/>
</defines>
        

Take a moment to study the structure of this definition file, because understanding it will be critical for all subsequent examples in this article. An outer <defines> element encloses a series of <tag> elements, each of which represents an element from the XML configuration file. Each <tag> must have at least the name and type attributes. The name attribute specifies an element name from the configuration file, while the type attribute specifies the corresponding PHP data type. Common primitive types are string, integer and boolean; however, as you'll see a little further along in this article, you can also map an element to an array or a custom class.

All that's left now is a PHP script to initialize an instance of XJConf and use the definitions in Listing 2 to retrieve configuration data. Listing 3 illustrates the required PHP code:


Listing 3. A PHP script to read XML configuration data
                        
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// load facade
XJConfLoader::load('XJConfFacade');
$conf = new XJConfFacade();

// attach definitions to parser
$conf->addDefinition('defs.xml');

// parse XML
$conf->parse('cat.xml');

// access XML element values
echo $conf->getConfigValue('name') . " is " . $conf->getConfigValue('breed') 
. " and " . $conf->getConfigValue('age') . " year(s) old.";
?>
        

Listing 4 illustrates the output of this script:


Listing 4. The output generated by Listing 3
                        
Martha is Siamese and 4 year(s) old.
        

Look closely at Listing 3, and it's easy to understand what it does. The listing first reads in the required class definition files, and then loads and initializes an XJConf facade object. In XJConf, this object provides a common interface to the DefinitionParser method, which handles the definition file in Listing 2; and the XMLParser method, which handles the XML-formatted configuration file in Listing 1.

First, the script calls the addDefinition() method of the XJConfFacade object to read the various tag definitions from Listing 2 and attach these definitions to the object. Next, the parse() method of the object parses the configuration data file in Listing 1. During this parsing process, the elements and data in the configuration file are converted into key-value pairs, similar to that found in a PHP associative array.

Once parsing is complete (the process will stop with an error message if your XML file definition has an error), you can access the keys and values with the getConfigValue() method of the XJConfFacade object, which accepts a key name as argument and returns the corresponding value. Thus, in Listing 4, a call to getConfigValue('name') returns the value of the <name> element from the configuration file cat.xml (Listing 1), which in this case happens to be Martha.

Now, try to edit the values in the configuration file (Listing 1) such that it looks like Listing 5:


Listing 5. A revised configuration file
                        
<?xml version='1.0'?>
<cat>
    <name>Tom</name>
    <age>1</age>
    <breed>Norwegian</breed>
</cat>
        

And now, when you re-run the PHP script in Listing 4, you'll see the revised output shown in Listing 6:


Listing 6. The revised output of Listing 4
                        
Tom is Norwegian and 1 year(s) old.
        

Notice that you didn't have to change a single line of Listing 4 to access the revised configuration data. Thus, the benefits of storing configuration variables in a separate file and using a tool like XJConf to access them should be clear: Global changes become as simple as altering a single file, with the changes reflecting instantly across the application.


Configure arrays

Simple data types are just the tip of the iceberg—XJConf also lets you define collections of related configuration variables, and converts these into native PHP arrays. XJConf supports both numerically-indexed and associative arrays.

To see how this works, consider Listing 7, which sets up a configuration file containing a collection of values:


Listing 7. A data file containing a collection of related items (collection.xml)
                        
<?xml version='1.0'?>
<root>
    <collection>
        <item letter="a">apples</item>
        <item letter="p">pears</item>
        <item letter="o">oranges</item>
    </collection>
</root>
        

Listing 8 contains the corresponding definition file:


Listing 8. A definition file (defs.xml)
                        
<defines>
    <tag name="collection" type="array" />
    <tag name="item" type="string" keyAttribute="letter" />
</defines>
        

Notice the values of the type attribute in this definition file: The <collection> element is mapped to an array, while the nested <item>s are mapped to simple string values. Notice also a new attribute introduced in this listing: The keyAttribute attribute, which tells XJConf which element attribute to consider when it sets the keys of the output associative array.

Listing 9 has the PHP code that parses and displays the configuration data:


Listing 9. A PHP script to read XML configuration data into a PHP array
                        
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// load facade
XJConfLoader::load('XJConfFacade');
$xml = new XJConfFacade();

// attach definitions to parser
$xml->addDefinition('defs.xml');

// parse XML
$xml->parse('collection.xml');

// access XML element values
print_r($xml->getConfigValue('collection'));
?>
        

Listing 10 displays the output:


Listing 10. The output of Listing 9
                        
Array
(
    [a] => apples
    [p] => pears
    [o] => oranges
)
        

By setting the keyAttribute to letter, XJConf automatically assigns the value of the letter attribute of every <item> element to the corresponding key of the output associative array.

Prefer a regular numerically-indexed array? Simply alter the definition file and set the value of the keyAttribute to the special symbol __none:


Listing 11. The revised definition file (defs.xml)
                        
<defines>
    <tag name="collection" type="array" />
    <tag name="item" type="string" keyAttribute="__none" />
</defines>
        

And Listing 12 now displays the revised output:


Listing 12. The revised output of Listing 9
                        
Array
(
    [0] => apples
    [1] => pears
    [2] => oranges
)
        

Now consider a realistic application of this feature: Configuring a database connection from variables present in an XML configuration file. Assume that the configuration file looks something like Listing 13:


Listing 13. A XML database configuration file (conf.xml)
                        
<?xml version='1.0'?>
<conf>
    <database>
        <user>root</user>
        <pass>mysql123</pass>
        <host>localhost</host>
        <db>test</db>
    </database>
</conf>

Further, assume that the task is to read these configuration values into an array, and then use this array to connect to a MySQL database server. The first step, then, is to map the XML into an array using a definitions file like the one in Listing 14:


Listing 14. A definition file (defs.xml)
                        
<defines>
    <tag name="database" type="array">
        <tag name="user" type="string" />
        <tag name="pass" type="string" />
        <tag name="host" type="string" />
        <tag name="db" type="string" />
    </tag>
</defines>
        

Listing 15 has the PHP script that uses this data to attempt a MySQL database connection:


Listing 15. A PHP script to read and use database configuration data from an XML file
                        
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// load facade
XJConfLoader::load('XJConfFacade');
$xml = new XJConfFacade();

// attach definitions to parser
$xml->addDefinition('defs.xml');

// parse XML
$xml->parse('conf.xml');

// access database configuration array
$db = $xml->getConfigValue('database');

// test MySQL connection
$conn = mysql_connect($db['host'], $db['user'], $db['pass']) 
or die('Connection error!');
mysql_select_db($db['db'], $conn) or die('Database selection error!');
mysql_close($conn);
echo 'Database test successful';
?>
        

Listing 15 uses XJConf to create and populate an array named $db with data from the configuration file conf.xml. This array is then used to open a connection to the MySQL database server and select a database for use. As explained in earlier examples, the key to the script lies in the definition file, defs.xml, which tells XJConf how to map elements from the configuration file into a PHP array.


Configure classes and objects

One of the most powerful features in XJConf, however, lies in its support for PHP classes and objects. With XJConf, it's quite simple to instantiate custom objects from an XML configuration file, and even configure the properties of said object using the data present in the configuration file.

To illustrate this, let's first define a simple RectangularObject class, which exposes three key properties to the configuration API: the length, width, and height. This class also exposes a getVolume() method, which uses these properties to calculate the volume of the object. Listing 16 has the code:


Listing 16. A PHP class definition (RectangularObject.php)
                                
<?php
class RectangularObject {

    // declare properties
    private $length;
    private $height;
    private $width;
    
    // declare constructor
    function __construct() {
        return true;    
    }
    
    // declare setter methods
    function setLength($l) {
        $this->length = $l;
    }
    
    function setHeight($h) {
        $this->height = $h;
    }
    
    function setWidth($w) {
        $this->width = $w;
    }
    
    // declare other methods
    function getVolume() {
        return ($this->length * $this->width * $this->height);
    }
}
?>
        

Listing 17 contains XML-formatted configuration data for one such RectangularObject class:


Listing 17. An XML configuration file (data.xml)
                                
<?xml version='1.0'?>
<conf>
    <rectangularobject>
        <height>20</height>
        <width>15</width>
        <length>10</length>
    </rectangularobject>
</conf>
        

Mapping data into an object instance is fairly easy. All you need to do is set the type attribute to the name of the class you wish to instantiate. Listing 18 illustrates the corresponding definition:


Listing 18. An XJConf definition file (defs.xml)
                                
<defines>
    <tag name="rectangularobject" type="RectangularObject">
        <tag name="length" type="integer"/>
        <tag name="width" type="integer"/>
        <tag name="height" type="integer"/>    
    </tag>
</defines>
        

Assuming that the setter methods are correctly named, XJConf will do two things

  1. Instantiate an object of that class.
  2. Call setter methods for each nested element to automatically configure the properties of the object.

Thus, the setLength() method is automatically invoked for the <length> element, the setHeight() method for the <height> element, and so on.

Listings 19 and 20 illustrate the PHP code and output respectively:


Listing 19. A PHP script to instantiate and configure an object from XML data
                                
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// load class definition
include_once 'RectangularObject.php';

// load facade
XJConfLoader::load('XJConfFacade');
$xml = new XJConfFacade();

// attach definitions to parser
$xml->addDefinition('defs.xml');

// parse XML
$xml->parse('data.xml');

// access object instance
$instance = $xml->getConfigValue('rectangularobject');
print 'The volume of the object is: ' . $instance->getVolume() . ' units';
?>
        

Listing 20 displays the output:


Listing 20. The output of Listing 19
                                
The volume of the object is: 3000 units
        


Configure default and mandatory Values

You can write an XML configuration file using attributes instead of nested tags, and use these attributes to configure an object instance. To see how this works in practice, first revise Listing 17 such that it uses attributes instead of nested elements:


Listing 21. The revised XML configuration file (data.xml)
                                
<?xml version='1.0'?>
<conf>
    <rectangularobject height="20" width="15" length="10" />
</conf>
        

Obviously, this necessitates a change in the definition file as well:


Listing 22. The revised XJConf definition file (defs.xml)
                                
<defines>
    <tag name="rectangularobject" type="RectangularObject">
        <attribute name="length" type="integer"/>
        <attribute name="width" type="integer"/>
        <attribute name="height" type="integer"/>    
    </tag>
</defines>
        

This change consists of replacing the <tag> elements with <attribute> elements, thus telling XJConf to consider attributes of the named tag when setting object properties, rather than the CDATA content of its child elements.

You can also possible to set default values for a particular configuration variable, or mark a certain configuration variable as mandatory, through skillful use of the default and required attributes in the definition file. Consider Listing 23, which makes the length and width configuration variables mandatory and sets a default value for the height:


Listing 23. An XJConf definition file with 'default' and 'required' constraints
                                
<defines>
    <tag name="rectangularobject" type="RectangularObject">
        <attribute name="length" type="integer" required="true" />
        <attribute name="width" type="integer" required="true" />
        <attribute name="height" type="integer" default="10" />    
    </tag>
</defines>
        

If you now try to read a configuration file which is missing a required value, XJConf will throw a MissingAttributeException (Figure 1):


Figure 1. An XJConf exception thrown when a required attribute is missing
An XJConf exception thrown when a required attribute is missing

In previous examples, you saw that XJConf can automatically call the appropriate setter methods to configure object instances. This automatic invocation of setter methods depends greatly on the correct naming of the setter methods for easy identification and mapping to element/attribute names. If you don't like this, you can also explicitly define the setter method for each element/attribute, with the setter attribute in the definition file. Listing 24 illustrates this use of custom setter methods for the length and width attributes:


Listing 24. An XJConf definition file with custom setter methods
                                
<defines>
    <tag name="rectangularobject" type="RectangularObject">
        <attribute name="length" setter="setL" />
        <attribute name="width" setter="setW" />
        <attribute name="height" />    
    </tag>
</defines>
        

As you might know, a new feature in PHP 5 is the introduction of the special __set() and __get() overloading methods, which you can use to set object properties even if a setter or getter method is not explicitly defined for that property. Listing 25 revises the class definition from Listing 16 to illustrate how this works in practice:


Listing 25. A PHP class definition with __set() and __get()
                                
<?php
class RectangularObject {

    // declare properties
    public $length;
    public $height;
    public $width;
    
    // declare constructor
    function __construct() {
        return true;    
    }
    
    // declare generic setter method
    public function __set($property, $value) {
        $this->$property = $value;
    }
    
    // declare generic getter method
    public function __get($property) {
        return $this->property;
    }
    
    // declare other methods
    function getVolume() {
        return ($this->length * $this->width * $this->height);
    }
}
?>
        

Assume the same data and definition files as in Listing 17 and Listing 18 respectively and try to run the PHP script in Listing 26:


Listing 26. A PHP script to configure an object using an XJConf configuration file
                                
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// load class definition
include_once 'RectangularObject.php';

// load facade
XJConfLoader::load('XJConfFacade');
$xml = new XJConfFacade();

// attach definitions to parser
$xml->addDefinition('defs.xml');

// parse XML
$xml->parse('data.xml');

// access object instance
$instance = $xml->getConfigValue('rectangularobject');
print 'The volume of the object is: ' . $instance->getVolume() . ' units';
?>
        

You should see the following output:


Listing 27. The output of Listing 26
                                
The volume of the object is: 3000 units
        

You'll notice that despite the lack of explicitly-defined setter methods in the class definition, XJConf was still able to configure the object's properties through the __set() method. This feature can, again, significantly reduce the length of your class definitions and make your application code simpler to maintain and easier to read.

In versions of XJConf for PHP prior to V. 0.2.0, these special overloading methods are not supported and attempts to use them will generate a fatal error in your PHP script.

Finally, you'll see that all the previous listings explicitly load the class definition files, before parsing the XML definitions and data. XJConf can automatically do this task for you using its own class loader as needed; examples illustrating this feature are available in the XJConf for PHP package (See Resources). You should definitely look at them if you work with numerous classes in your application.


Project: Configure a complex class tree

As the previous listings demonstrated, XJConf can use either attributes or child elements to correctly configure an instantiated object. In all cases but one, therefore, it is your relative comfort level with these two techniques that will define your approach. However, in one case, the use of child elements offers an advantage over attributes: When you link one or more objects to another in a complex tree.

To illustrate, consider Listing 28, which defines some classes:


Listing 28. Some PHP class definitions (App.php)
                                
<?php
// configuration class
class Config {
    // declare properties
    private $host;
    private $port;
    private $user;
    private $pass;
    
    // declare methods
    function setConfig($confArray) {
        if (isset($confArray['host'])) {
            $this->host = $confArray['host'];
        }    
        if (isset($confArray['port'])) {
            $this->port = $confArray['port'];
        }    
        if (isset($confArray['user'])) {
            $this->user = $confArray['user'];
        }    
        if (isset($confArray['pass'])) {
            $this->pass = $confArray['pass'];
        }    
    }    
}

// these inherit from the Config class
class DBConfig extends Config {
}

class SMTPConfig extends Config {
}

// application class
class App {
    // declare properties
    public $DBConfig;
    public $SMTPConfig;
    
    // declare constructor
    public function __construct() {
        return true;    
    }
    
    // declare setter methods
    function setDBConfig($db) {
        $this->DBConfig = $db;    
    }    
    function setSMTPConfig($smtp) {
        $this->SMTPConfig = $smtp;    
    }    
    
    // declare getter methods
    function getDBConfig() {
        return $this->DBConfig;    
    }    
    function getSMTPConfig() {
        return $this->SMTPConfig;    
    }    
}
?>
        

Listing 28 begins with the Config class, which exposes a generic API to receive an associative array of server access parameters. The DBConfig and SMTPConfig classes are sub-classes of this Config class, and are intended specifically to store access parameters for a database server and an SMTP server respectively. DBConfig and SMTPConfig objects are, in turn, used by the App class, which represents an application. This App class exposes setter and getter methods to set and retrieve the corresponding Config class as needed.

Configuration of these classes occurs through an XML configuration file, such as the one in Listing 29:


Listing 29. An XML configuration file (conf.xml)
                                
<?xml version='1.0'?>
<configuration>
  <app>
    <db>
      <array>
        <host>localhost</host>
        <user>guest</user>
        <pass>mysql123</pass>
      </array>
    </db>
    
    <smtp>
      <array>
        <host>mail.domain.com</host>
        <user>sluggo</user>
        <pass>mypass</pass>
        <port>25</port>
      </array>
    </smtp>
  </app>
</configuration>
        

The glue needed to convert the XML data in Listing 29 into a fully-configured App object instance lies in the definition file (Listing 30) and the corresponding PHP script (Listing 31). Look at the definition file first:


Listing 30. An XJConf definition file (defs.xml)
                                
<defines>
  <tag name="app" type="App">  
    <tag name="db" type="DBConfig" setter="setDBConfig">
        <tag name="array" type="array" keyAttribute="name" setter="setConfig">
            <tag name="host" type="string" />
            <tag name="user" type="string" />
            <tag name="pass" type="string" />
        </tag>
    </tag>
    <tag name="smtp" type="SMTPConfig" setter="setSMTPConfig">
        <tag name="array" type="array" keyAttribute="name" setter="setConfig">
            <tag name="host" type="string" />
            <tag name="port" type="integer" />
            <tag name="user" type="string" />
            <tag name="pass" type="string" />
        </tag>
    </tag>
  </tag>
</defines>
        

How does this work? It's not really as difficult as it looks:

  1. When XJConf encounters an <app> element in the configuration file, it instantiates an App object instance. From the class definitions in Listing 28, you'll see that this App object exposes the setDBConfig() and setSMTPConfig() methods.
  2. When XJConf next encounters a <db> or <smtp> element, it instantiates a DBConfig or SMTPConfig object and invokes the setConfig() setter method of the object. The input to this setter method is an array of configuration parameters, which is natively created from the <array> element and its children.
  3. The DBConfig and SMTPConfig objects created in step 2 are then attached back to the App object through the setter methods setDBConfig() and setSMTPConfig(). You'll notice that these methods are also named in the definition file through the setter attribute.

    The resulting App object instance is then retrieved from within a PHP script by calling getConfigValue(). In a similar vein, the instantiated and configured DBConfig and SMTPConfig objects can also be retrieved, by calling App::getDBConfig() or App::getSMTPConfig(). You can see this in Listing 31:


Listing 31. A PHP script to configure a complex class tree
                                
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

// include class file
include_once 'App.php';

// load facade
XJConfLoader::load('XJConfFacade');
$xml = new XJConfFacade();

// attach definitions to parser
$xml->addDefinition('defs.xml');

// parse XML
$xml->parse('conf.xml');

// access objects
$app = $xml->getConfigValue('app');
$db = $app->getDBConfig();
$smtp = $app->getSMTPConfig();

// display App object
print_r($app);
?>
        

Listing 32 displays the output:


Listing 32. The output of Listing 31
                                
App Object
(
    [DBConfig] => DBConfig Object
        (
            [host:private] => localhost
            [port:private] => 
            [user:private] => guest
            [pass:private] => mysql123
        )

    [SMTPConfig] => SMTPConfig Object
        (
            [host:private] => mail.domain.com
            [port:private] => 25
            [user:private] => sluggo
            [pass:private] => mypass
        )

)
        


Project: Build a web-based configuration interface

Another common real-world requirement for many projects is a Web-based configuration tool, which allows users to input configuration data through a Web form and saves this to a file in XML format. XJConf has limited usefulness in this context. While the package provides a full-featured API to read XML-formatted configuration data into PHP data structures, it does not offer any methods to write data back to a file. Thus, in these situations, it is necessary to supplement XJConf with the DOM extension in PHP, which provides an API to dynamically construct an XML tree and write it to a file.

Listing 33 demonstrates the use of these two tools:


Listing 33. A PHP script to edit and save configuration data to a file
                                
<?php
// include XJConf class file
include_once 'XJConf/XJConfLoader.php';

$dataFile = 'config.xml';
$defsFile = 'defs.xml';
    
// if form is not submitted
if (!isset($_POST['submit'])) {
    
    // check to see if config file exists
    if (file_exists($dataFile)) {

        // load facade
        XJConfLoader::load('XJConfFacade');
        $xml = new XJConfFacade();

        // attach definitions to parser
        $xml->addDefinition($defsFile);

        // parse XML
        $xml->parse($dataFile);
    } 
?>
<html>
 <head><basefont face="Arial"></head>
 <body>
  <h2>Configuration</h2>
  <table border="0" cellspacing="5" cellpadding="5">
   <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
    <tr>
     <td>POP3 host name</td>
     <td><input type="text" name="pop3_host" 
     value="<?php echo (isset($xml)) ? $xml->getConfigValue('host') : null; ?>"
     ></td>
    </tr>
    <tr>
     <td>POP3 port</td>
     <td><input type="text" name="pop3_port" 
     value="<?php echo (isset($xml)) ? $xml->getConfigValue('port') : null; ?>"
     ></td>
    </tr>
    <tr>
     <td>POP3 user name</td>
     <td><input type="text" name="pop3_user" 
     value="<?php echo (isset($xml)) ? $xml->getConfigValue('user') : null; ?>"
     ></td>
    </tr>
    <tr>
     <td>POP3 user password</td>
     <td><input type="text" name="pop3_pass" 
     value="<?php echo (isset($xml)) ? $xml->getConfigValue('pass') : null; ?>"
     ></td>
    </tr>
    <tr>
     <td colspan="2" align="center"><input type="submit" name="submit" 
     value="Save Configuration"></td>
    </tr>
   </form>
  </table>           
 </body>
</html>
<?php
} else {
    // do some input validation here
    
    // write the submitted values to a configuration file
    // generate DOM tree and root node
    $dom = new DOMDocument('1.0', 'iso-8859-1');
    $conf = $dom->createElement('conf');
    $dom->appendChild($conf);    
    
    // attach child nodes
    $host = new DOMElement('host', $_POST['pop3_host']);
    $port = new DOMElement('port', $_POST['pop3_port']);
    $user = new DOMElement('user', $_POST['pop3_user']);
    $pass = new DOMElement('pass', $_POST['pop3_pass']);
    $conf->appendChild($host);
    $conf->appendChild($port);
    $conf->appendChild($user);
    $conf->appendChild($pass);
    
    // save to configuration file
    $dom->formatOutput = true;
    if ($dom->save($dataFile)) {
        echo 'Configuration successfully saved!';
    }
}
?>
        

Listing 33 is divided into two parts: a form which displays the current configuration (if available) and allows the user to edit it, and a form processor, which accepts the new configuration and saves it to a file. XJConf is used in the first half of the script, to parse the XML configuration file and retrieve its contents into PHP variables; these variables are then used to pre-fill the fields of the Web form.

Listing 34 contains the simple definition file used by Listing 33:


Listing 34. An XJConf definition file (defs.xml)
                                
<defines>
  <tag name="host" type="string"/>  
  <tag name="port" type="integer"/>  
  <tag name="user" type="string"/>  
  <tag name="pass" type="string"/>  
</defines>
        

Once the form is submitted, the DOM extension in PHP takes over. A DOMDocument instance is created, and child elements are attached to it holding the configuration values input by the user. Once the entire DOM tree has been constructed, it's written back to the configuration file using the DOMDocument::save() method.

Figure 2 illustrates what the form looks like:


Figure 2. A Web form to edit and save configuration data
A Web form to edit and save configuration data

And Listing 35 demonstrates one such configuration file written by this script:


Listing 35. An example file created by Listing 34
                                
<?xml version="1.0" encoding="iso-8859-1"?>
<conf>
  <host>localhost</host>
  <port>110</port>
  <user>joelle</user>
  <pass>guessme</pass>
</conf>
            

As the previous listings illustrate, the XJConf package provides an easy-to-use, flexible API that reads XML-formatted configuration files and converts the values found therein into PHP data structures. In addition to simple string and numeric values, it also supports the use of arrays and objects, and includes built-in intelligence to automatically configure newly-instantiated objects through setter methods. For all these reasons, it's a worthy addition to the toolkit of any PHP developer. Try it out the next time you need a interface between your PHP application and your XML configuration file, and see for yourself!


Resources

Learn

Get products and technologies

Discuss

About the author

Vikram Vaswani is the founder and CEO of Melonfire, a consulting services firm with special expertise in open-source tools and technologies. He is also the author of the books PHP Programming Solutions and How to do Everything with PHP and MySQL.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Open source
ArticleID=265194
ArticleTitle=Process XML configuration files with PHP
publish-date=11062007
author1-email=vikram.melonfire@gmail.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers