php-src/pear/Config/README.Config

429 lines
14 KiB
Plaintext

Documentation and Tutorial for PEAR-Config
by Alexander Merz
$Id$
A first example
For beginning we start with a useful script example:
----- example.php ------
<?php
require_once( "config.php" ) ;
$path = "c:/windows/system/" ; // change this to the location of $file
$file = "php.ini" ; // filename to parse
$options["cc"] = ';' ; // set the comment char
$blocks = array() ; // contains all blocknames
$data = $array() ; // contains all key-value-pairs
$conf = new Config( "IniFile") ; // Data container is a ini file
$conf -> 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
?>
<html>
<head>
<title>Test for PEAR - Config</title>
</head>
<body>
<table>
<?php
foreach( $data as $d) {
echo "<tr><td colspan=\"2\">Block: $d</td></tr>" ;
foreach( $d as $k => $v ) {
echo "<tr><td>$k</td><td>$v</td></tr>" ;
}
}
?>
</table>
</body>
----- 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 <chregu@phant.ch>)
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
<?xml version="1.0"?>
<block1 key1="value1">
<block2 key2="value2" key3="value3"/>
</block1>
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:
...
<block1>This is content</block1>
...
$data = $conf->getValues("/block1/");
would give us
$data[content] = "This is content";
Be aware:
<block1>This is content<block2> and this also</block2></block1>
...
$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.
...
<block1 key1="value1">
<block2 key2="value2" key3="value3"/>
<block3 key4="value2" key5="value3"/>
</block1>
...
$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:
<block2 key2="value2" key3="value3"/>
<block2 key2="value3" key4="value4"/>
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