Documentation and Tutorial for PEAR-Config by Alexander Merz $Id$ A first example For beginning we start with a useful script example: ----- example.php ------ parseInput( $path.$file, $options) ; $blocks = $conf -> getBlocks( "/" ) ; foreach( $blocks as $block ) { // read the k-v-p of every block $data[$block] = $conf -> getValues( "/".$block ) ; } // output ?> Test for PEAR - Config " ; foreach( $d as $k => $v ) { echo "" ; } } ?>
Block: $d
$k$v
----- example.php ------ This script parses the php.ini and creates a table containing the name of all blocks and the key-value-pairs of every block. Now, lets cut up the script. require_once( "config.php" ) ; First of all, to use the Config-API you have to include "config.php". If you have a regular PHP installation including PEAR, there should be no problem for PHP to find the file. Unfortunatly a large number of ISP didn't installed PEAR or have a older installation, where Config isn't present. In this case, we have good news for you. Config is "pure" PHP. This means you can download "config.php" and (important!) the Config directory from cvs.php.net and copy the files to your webspace. Take care of using the correct path to "config.php" in the require statement. Also, go this way, if you perhaps want to use a newer version of Config. $conf = new Config( "IniFile") ; With this line you create a new instance of the Config class. The constructor requires the declaration of the type of the container, which contains the configuration data. Check the 'Implementations' section in this documentation the see which containers are avaible at the moment. "php.ini" is a typical example for a ini file and should be present on your system, if you have installed PHP ( else this document should be a bit useless for you!?). So, to work with this file, we have to say Config to parse this file. $conf -> parseInput( $path.$file, $options) ; Normaly this function reads the data container and writes the data into an internal data structure. How to adress specific the container depends on the implemention, IniFile requires an existing file. The second parameter contains a set of options. Which options exist and/ or required depends on the type of the container. In this case, Ini files have often comments, which should not be parsed, "php.ini" uses the semicolon to mark up the start of a comment. At this point, we can start to accessing the configuration data. To accessing the data, you should know something about how Config 'structurize' the data. Config distinguish three types of elements: keys, values and blocks. Take a look on "php.ini". The first 'key' is "engine". Keys are names of options and/or of data elements. To every key belongs a 'value'. The value of the key "engine" could be "on" or "off". "on" or "off" are data of the key. Take care, also missing of such data, ie. a empty string is a value. Often, ie. "php.ini", the data container contains a huge number of key-value pairs. Sometimes it isn't possible to avoid two or more options with the same key name, ie. you want to save the access data for databases with different usernames, passwords and tablenames. To separate them, you can edge them in a 'block'. Another typical use of blocks is to summarize key-values pairs which belong together in a block, as you can see in "php.ini". Especially, if a data container should be editable be humans without a special programm, you should use blocks to structurize the data. The data in "php.ini" is completly separate into blocks, so as the first access, we want the names of the blocks. $blocks = $conf -> getBlocks( "/" ) ; getBlocks() returns an array containing all block names. You maybe wonder about the argument. getBlocks requires a 'blockpath'. Config structurize the data as a tree comparable to a file system. Think blocks as directories and key-value pairs as files. You can store a file in the root dir ( "/" under Unix-like systems) or in a directory ( ie. ( "/usr/" ) or subdirectories ( ie. "/usr/bin/" ). According to this, there are implementations which support sub-blocks in blocks. IniFile doesn't support block nesting, only blocks in the first level, the 'root' level and the root level is adressed with a single slash. Take care: If you want all sub blocks of ie. the block named "db_accessdata", the blockpath is "/db_accessdata/" - don't forget the leading root slash! Also, if you need to address key-value-pairs, as you can see later in this manual, which are not in a block, you have to use "/" as blockpath. As the next we want all key-value pairs of every block. To get them we use $data[$block] = $conf -> getValues( "/".$block ) ; to recieve them. getValues() returns a hash with all key-value pairs in the given block path. The key will used as hash key containing the value of the key, ie: $data[ 'PHP' ][ 'engine' ] = "on". So thats all, what would be worthy to talk about the script! Now a little exercise for you: You should able to rewrite the script to print out the content of every configuration data container including key-value-pairs in subblocks. Getting and Setting getValues is a possibility to get all config data of a block. But often you need only a few of them and/ or you want more influence oft the returned data. To only get the value of one key, you can use getValue(). getValue() requires the blockpath as the first argument like dicussed above, as the next the name of the key as a string. getValue() has a third optional parameter. If the key in the named block doesn't exists, the key and if neccessary the block will be created and the third parameter will be assigned to them and returned by getValue(). The counterpart of getValue() is setValue(). setValue() requires a blockpath, the name of the key too, but as the third argument the value, which should be assigned to the key. The behavior of setValue, if the key or the block not exists, is the same like getValue(). setValue() returns the assigned value too. Saving changes If you changed values of keys or adding keys or blocks, this changes only influence the internal data structure of Config. So changes will lost during finishing the script. To save them permantly, you have to call writeInput(). writeInput has two optional arguments. The first is the name of the data container, where the data should be saved. If you left this part empty, writeInput() use the data container given in parseInput() as destination. The second optional argument orders writeInput() to save the data preserving the content and format of the original container, as good as possible, if the argument is true. This option makes in the most cases only sense in file-based containers like IniFile. Normaly configuration files contains ie. comments, a lot of whitespaces to make the files editable by humans. This data will not be parsed into the internal data struture and so cannot be written back to the container. If the preserving argument is true, writeInput() takes the original container and tries to copy the content, and changes only different values and adds new keys and blocks keeping the original file content including comments and whitespace. Implementations IniFile The container is a file with following format ... ; comment [blockname] ; comment key=value ; comment key="value with whitespaces; and the comment char" ; comment ... Comments are marked by a special starting comment char and can stay on a single line or after a value, but not between a key-value assignment. Blocks are marked between brackets and the block name between them. There is no block end markup. A block ist finish by the end of the file or a new block markup. Block nesting is not possible. Only one key-value assignment per line is allowed. The assignment consist of the keyname, a equal sign and the value. If the value contains whitespace or the comment char, you have to set the value between double marks. Options for parseInput() are: "cc" - defines the comment char XML (by Christian Stocker ) The main advantage of the XML-Container is, that it knows Sub-blocks. So you can have nested blocks, which I have to use from time to time. The XML-Container depends on the domxml implementation of PHP, therefore you have to compile you're PHP with the option --with-domxml (or ask you're provider to do so...) An example XML-file looks this way The XML-File has to be well-formed, otherwise you get an error. The Constructor has to be called the following way $conf = new Config( "xml") ; accessing these values works the same as in the IniFile-Container, except for Sub-blocks you can use the Directory-structure mentioned above. For example, if you want the values of Block2: $conf->getValues("/block1/block2/"); Options (default value in brackets): IncludeContent [True] Since an xml-tags also can have content (not only attributes), this flag indicates if we want to take this as a value for the block. example: ... This is content ... $data = $conf->getValues("/block1/"); would give us $data[content] = "This is content"; Be aware: This is content and this also ... $data = $conf->getValues("/block1/"); gives you $data[content] = "This is content and this also"; IncludeChildren [True] For more flexibility in parsing your config files, there's an array containin all the names of the sub- blocks of one block, if you set this. ... ... $data = $conf->getValues("/block1/"); gives you an array with the values: [key1] => value1 [children] => Array ( [0] => block2 [1] => block3 ) you can then get the values of block2 and block3 with a simple foreach-loop: foreach ($data[children] as $childname) { $childdata = $conf->getValues("/block1/".$childname); } MasterAttribute [Null] You can assign one attribute of a block as a MasterAttribute, then the value of this attribute will be assigned to the parent-block with the name of the sub-block (which have the MasterAttribute) as the key and the value of the MasterAttribute. You can also set "content" as the MasterAttribute. Example: MasterAttribute = "key2"; $data = $conf->getValues("/block1/"); gives you an array with the values: [key1] => value1 [block2] => value2 IncludeMasterAttribute [True] If you want to include the MasterAttribute also i n the subblocks, set this flag. MasterAttribute = "key2"; $data = $conf->getValues("/block1/block2"); gives you an array with the values: [key2] => value2 [key3] => value3 if you set the flag False, then [key2] will not be included. Limitations: There can't be 2 Blocks on the same level with the same name. The following will not reasonably work: Writing is not supported yet. you can't write back the changes you made. Since xml files can be written in different ways meaning almost the same, it's hard to preserve the old format. But it's certainly possible.. DB you can store you're config data also in a Database. This implementation uses the Pear::DB Classes, so any Database supported within pear should be supported here also. the table in the Database has to look the following way (the length of the varchar does not matter and additional fields can be included.) CREATE TABLE config ( datasrc varchar(50) NOT NULL, block varchar(50) NOT NULL, name varchar(50) NOT NULL, value varchar(50) NOT NULL ); Calling the constructor: $conf = new Config("db","mysql://username:password@localhost/dbname") ; the second parameter is the dsn, as described in the pear-db documentation. The rest is quite the same as in the IniFile-Implementation. Just try to replace the constructor-line in the examples for the IniFile-Container and the rest should work. datasrc: it's the equivalent to the filename. so you can have different "ini-files" in the same db-table (for example to store different settings for different users) block/name/value: has the same meaning as in the IniFile-Container. Writing back the data is also supported. Sub-blocks are not supported. Options: Table [config] The name of the db-table, where the keys/values/etc are stored. API-Reference Config($storage_driver,$storage_options = "") Constructor Parameters storage_driver - name of the data container storage_options - n/a array getBlocks( $block = "/") returns all blocknames of the given blockpath Parameters block - existing blockpath Return array - array containing all blocknames mixed getValue( $block = "/", $key, $default = "") returns the value of the key in the block Parameters block - blockpath key - key name value - default value, if key not found Return mixed - the value of the key or the default value array getValues( $block = "/") returns all key-value-pairs of the given blockpath Parameters block - existing blockpath Return array - hash containing the key-value-pairs mixed setValue( $block = "/", $key, $value = "") sets the key in the block to the given value Parameters block - blockpath key - key name value - value to assign Return mixed - the given value mixed parseInput ($src ,$options = array() ) set the data source to parse Parameters src - Source to parse ooptions - array of the settings Return mixed - true on success, else PEAR_ERROR mixed writeInput( $dest = "", $preserve = True ) writes the data to dest Parameters dest - Destination for writing preserve - if true, try to preserve writing Return mixed - true if success, else PEAR_ERROR