Browse Source

Moved Config-Package from Experimental to main-directory, since noone complained about it ;)

experimental/pre_new_hash_func
Christian Stocker 25 years ago
parent
commit
a65e4e91a1
  1. 329
      pear/Config.php
  2. 171
      pear/Config/Container.php
  3. 219
      pear/Config/Container/IniFile.php
  4. 175
      pear/Config/Container/db.php
  5. 154
      pear/Config/Container/xml.php
  6. 428
      pear/Config/README.Config

329
pear/Config.php

@ -0,0 +1,329 @@
<?php
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Alexander Merz <alexander.merz@t-online.de> |
// | Christian Stocker <chregu@phant.ch> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once( "PEAR.php") ;
/**
* Partly implementation of the Config-Interface-API
*
* This class implements a part of the API for working on configuration data
* ConfigDefault implements getValues(), getBlocks(), getValue(), setValue()
* The data is internally saved in a nested array.
*
* Example:
* include("Config.php");
* $i = new Config("IniFile");
* $i -> parseInput( "yourfile.ini");
* $ret = $i->getValues('/section');
*
*
* @author Alexander Merz <alexander.merz@t-online.de>
* @access public
* @version $Id$
* @package Config
*/
class Config {
/**
* contains the data source given by parseInput
* @var string
*/
var $datasrc ;
/**
* contains the internal data structure
* @var array
*/
var $data = array() ;
/**
* Constructor
*
* requires the type of the data container, if the container needs
* special parameters during creation, set them with $storage_options
*
* @access public
* @param string $storage_driver type of container
* @param string $storage_options parameter for container constructor
*/
function Config($storage_driver,$storage_options = "")
{
$storage_class = 'Config_Container_' . $storage_driver;
$storage_classfile = 'Config/Container/' . $storage_driver . '.php';
include_once $storage_classfile;
$this->container = new $storage_class($storage_options);
} // end func Config()
/**
* returns all key-value-pairs of the given block
*
* If the block not exists, a PEAR_Error will returned, else
* a hash: $array["key"] = value
*
* @access public
* @param string $block block path
* @return array returns a hash containing all values, but a PEAR_Error if fails
*/
function getValues( $block = "/")
{
if( !empty( $this -> data ) )
{
// if leading slash was forgotten...
if( "/" != substr( $block, 0, 1) )
{
$block = "/".$block ;
}
if( isset( $this -> data[ $block ] ) )
{
if( is_array( $this -> data[ $block ] ) )
{
$ret = $this -> data[ $block ] ;
}
else
{
$ret = false ;
}
}
else
{
$ret = new PEAR_Error("Block path '".$block."' doesn't exists! Request couldn't be answered.", 12, PEAR_ERROR_RETURN, null, null );
}
}
else
{
$ret = new PEAR_Error("No internal data! Request couldn't be answered.", 11, PEAR_ERROR_RETURN, null, null );
}
return $ret ;
} // end func getValues
/**
* returns all blocks of the given block
*
* If the block not exists, a PEAR_Error will returned, else
* a array containing all child blocks
*
* @access public
* @param string $block block path
* @return array returns a array containing all values, or a PEAR_Error, if fails
*/
function getBlocks( $block = "/")
{
if( !empty( $this -> data ) )
{
// if leading slash was forgotten...
if( "/" != substr( $block, 0, 1) )
{
$block = "/".$block ;
}
$ret = array() ;
foreach( $this -> data as $key => $value)
{
$key = $key."/" ;
if( $block == substr( $key, 0, strlen( $block ) ) )
{
array_push ( $ret, trim( substr( $key, strlen( $block ), strpos( substr( $key, strlen( $block ) ), "/" ) ) ) ) ;
}
}
}
else
{
$ret = new PEAR_Error("No internal data! Request couldn't be answered.", 21, PEAR_ERROR_RETURN, null, null );
}
return $ret ;
} // end func getBlocks
/**
* sets the value of the key of the given block
*
* If the block or the key not exists, both will be created.
* The value will be returned.
*
* @access public
* @param string $block block path
* @param string $key key to set
* @param string $value value for the key
* @return mixed type depends on $value
* @see getValue()
*/
function setValue( $block = "/", $key, $value = "")
{
// if leading slash was forgotten...
if( "/" != substr( $block, 0, 1) )
{
$block = "/".$block ;
}
// check for existing block and key
if( !isset ( $this -> data[ $block ] ) )
{
$this->data[ $block ] = array() ;
}
$kvp = $this -> data[ $block ] ;
$kvp[ $key ] = $value ;
$this -> data[ $block ] = $kvp ;
$ret = $value ;
return $ret ;
} // end func setValue
/**
* return the value of the key of the given block
*
* If the block or the key not exists, both will be created and
* sets on the default.
* The value or if not exists the default will be returned.
*
* @access public
* @param string $block block path
* @param string $key key to set
* @param string $default default value for the key
* @return mixed type depends of the value
*/
function getValue( $block = "/", $key, $default = "")
{
// if leading slash was forgotten...
if( "/" != substr( $block, 0, 1) )
{
$block = "/".$block ;
}
// check for existing block and key
$values = $this -> getValues( $block ) ;
if( PEAR::isError($values) or !in_array( $key, array_keys( $values) ) )
{
$this -> setValue( $block, $key, $default) ;
$values = $this -> getValues( $block ) ;
}
$ret = $values[ $key ] ;
return $ret ;
} // end func getValue
/**
* parses the input of the given data source
*
* The format and required content of $datasrc depends of the implementation.
* If the implemention requires additional data, for example a comment char, it have to
* deliver in a hash as second argument.
*
* @access public
* @param string $files Name of the datasource to parse
* @param array $feature Contains a hash of features depending on the implentation
* @return mixed returns a PEAR_ERROR, if error occurs
*/
function parseInput ($files ,$feature = array() )
{
if (is_array($files)) {
$totaldata = array();
foreach ($files as $datasrc)
{
$this->container->parseInput($datasrc,$feature);
$totaldata = $this->array_merge_clobber($totaldata,$this->container->data);
unset ($this->data);
$this->datasrc = $datasrc;
}
$this->data = $totaldata;
}
else
{
$this->container->parseInput($files,$feature);
$this->data = $this->container->data;
$this->datasrc = $files;
}
} // end func parseInput()
/**
* writes the data to the given data source or if not given to the datasource of parseInput
* If $datasrc was a array, the last file will used.
*
* See parseInput for $datasrc. If the second argument $preserve is true, the implementation
* should try to preserve the original format and data of the source except changed or added values.
* This mean to preserve for example comments in files or so.
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param boolean $preserve preserving behavior
* @return mixed returns PEAR_Error, if fails
* @see parseInput()
*/
function writeInput( $datasrc = "", $preserve = True )
{
if( empty( $datasrc ) ) {
$datasrc = $this -> datasrc ;
}
$this->container->writeInput($datasrc,$preserve);
}
//taken from kc@hireability.com at http://www.php.net/manual/en/function.array-merge-recursive.php
/**
* There seemed to be no built in function that would merge two arrays recursively and clobber
* any existing key/value pairs. Array_Merge() is not recursive, and array_merge_recursive
* seemed to give unsatisfactory results... it would append duplicate key/values.
*
* So here's a cross between array_merge and array_merge_recursive
*
* @param array first array to be merged
* @param array second array to be merged
* @return array merged array
* @acces private
*/
function array_merge_clobber($a1,$a2)
{
if(!is_array($a1) || !is_array($a2)) return false;
$newarray = $a1;
while (list($key, $val) = each($a2))
{
if (is_array($val) && is_array($newarray[$key]))
{
$newarray[$key] = $this->array_merge_clobber($newarray[$key], $val);
}
else
{
$newarray[$key] = $val;
}
}
return $newarray;
}
}; // end class Config
?>

171
pear/Config/Container.php

@ -0,0 +1,171 @@
<?php
// +---------------------------------------------------------------------+
// | PHP version 4.0 |
// +---------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
// +---------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and areunable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +---------------------------------------------------------------------+
// | Authors: Alexander Merz <alexander.merz@t-online.de> |
// | Christian Stocker <chregu@phant.ch> |
// +---------------------------------------------------------------------+
//
// $Id$
/**
* Interface for Config-Classes
*
* This interface provides a API for configuration data
*
* @author Alexander Merz <alexander.merz@t-online.de>
* @access public
* @version $Id$
* @package Config
*/
class Config_Container {
/**
* parses the input of the given data source
*
* The format and required content of $datasrc depends of the implementation.
* If the implemention requires additional data, for example a comment char, it have to
* deliver in a hash as second argument.
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param array $feature Contains a hash of features depending on the implentation
* @return mixed returns a PEAR_ERROR, if error occurs
*/
function parseInput( $datasrc = "", $feature = array() )
{
return new PEAR_Error("parseInput not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func parseInput
/**
* writes the data to the given data source or if not given to the datasource of parseInput
*
* See parseInput for $datasrc. If the second argument $preserve is true, the implementation
* should try to preserve the original format and data of the source except changed or added values.
* This mean to preserve for example comments in files or so.
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param boolean $preserve preserving behavior
* @return mixed returns PEAR_Error, if fails
* @see parseInput()
*/
function writeInput( $datasrc = "", $preserve = true )
{
return new PEAR_Error("writeInput not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func writeInput
/**
* returns all key-value-pairs of the given block
*
* The implementation should returns only the pairs of the given
* block, no names of subblocks.
* Blocks should be looks like this "/rootblock/child_block/grandchild_block/..."
* Take care of the leading slash - this is a "root"-slash according to the "root"-dir
* under Unix. If a config data source contains no blocks or using of blocks makes no sense
* the implementation have to support at least the root-slash.
*
* @access public
* @param string $block block path
* @return array returns a hash containing all values, but a PEAR_Error if fails
*/
function getValues( $block )
{
return new PEAR_Error("getValues not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func getValues
/**
* returns the name of all childblocks
*
* The implementation returns the name of all childblocks in the given block as a array.
* If a childblock contains also childblocks the value of the block have to be also a
* array containing all grandchild-blocks
*
* @access public
* @param string $block block path
* @return array returns a array containing all values, or a PEAR_Error, if fails
* @see getValues()
*/
function getBlocks( $block )
{
return new PEAR_Error("getBlocks not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func getBlocks
/**
* returns the value of the key in the given block
*
* The implementation returns the value of the key in the given block. If the key or the block not exist
* the implementation should return the default-value and create the block with the key and the default-value.
*
* @access public
* @param string $block block path
* @param string $key key
* @param string $default default-value
* @return mixed type depends of the value
* @see getValues()
*/
function getValue( $block, $key, $default = "" )
{
return new PEAR_Error("getValue not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func getValue
/**
* sets the value of the key in the given block
*
* The implementation sets the value of the key in the given block and returns value.
* If the key or the block not exist, the implementation should create the block with
* the key and the value.
*
* @access public
* @param string $block block path
* @param string $key key
* @param string $value value to set
* @return mixed type depends on $value
* @see getValue()
*/
function setValue( $block, $key, $value )
{
return new PEAR_Error("setValue not implemented", 1, PEAR_ERROR_RETURN, null,
null );
} // end func setValue
/**
* Imports the requested datafields as object variables if allowed
*
* @param array List of fields to be imported as object variables
* @param array List of allowed datafields
*/
function setFeatures($requested, $allowed) {
foreach ($allowed as $k => $field)
if (isset($requested[$field]))
$this->feature[$field] = $requested[$field];
} // end func setFeatures
}
?>

219
pear/Config/Container/IniFile.php

@ -0,0 +1,219 @@
<?php
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Alexander Merz <alexander.merz@t-online.de> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once( "Config/Container.php" ) ;
/**
* Config-API-Implemtentation for Ini-Files
*
* This class implements the Config-API based on ConfigDefault
*
* @author Alexander Merz <alexander.merz@t-online.de>
* @access public
* @version $Id$
* @package Config
*/
class Config_Container_IniFile extends Config_Container {
/**
* contains the features given by parseInput
* @var array
* @see parseInput()
*/
var $feature = array() ;
/**
* parses the input of the given data source
*
* The Data Source can be a string with the file or a array of strings with the files to read,
* so datasrc requires a existing file.
* The feature-array have to contain the comment char array("cc" => Comment char)
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param array $feature Contains a hash of features
* @return mixed returns a PEAR_ERROR, if error occurs
*/
function parseInput( $datasrc = "", $feature = array( "cc" => ";") )
{
// Checking if $datasrc is a array, then call parseInput with
// each file
if( is_array( $datasrc) ) {
foreach( $datasrc as $file ) {
$ret = $this -> parseInput( $file, $feature ) ;
if( PEAR::isError( $ret) ) {
return $ret ;
}
}
}
$this -> datasrc = $datasrc ;
$this -> feature = $feature ;
if( file_exists( $datasrc ) )
{
$lines = file( $datasrc ) ;
$block = "/" ;
$zeilennr = 0 ;
foreach( $lines as $line)
{
$value_found = "" ;
$kkey_found = "" ;
$line = trim( $line) ;
// is it a blank line?
if( empty( $line) )
{
$found = 0 ;
}
// checking for data
else
{
$char = substr( $line, 0, 1) ;
// a comment?
if( $char == $this -> feature["cc"] )
{
$found = 0 ;
}
// a block?
elseif( $char == '[' )
{
$found = 1 ;
$block_found = substr( $line, 1, strpos( substr( $line, 1 ), ']' ) ) ;
}
// must be a kvp
else
{
$key = substr( $line, 0, strpos( $line, '=') ) ;
if( !$key )
{
return new PEAR_Error( "Line ".$zeilennr." in '".$datasrc."' seems to be a comment, but comment char is missing!", 41, PEAR_ERROR_RETURN, null, null );
}
$value = (string)trim( (string)substr( (string)$line, strpos( (string)$line, '=') ) ) ;
$value = (string)trim( (string)substr( (string)$value, 1 ) );
// checking for double quoted string
if( '"' == substr( $value, 0, 1) )
{
// value = all until next "
$value_found = substr( $value, 0, strpos( substr( $value, 1 ), '"' ) + 1) ;
$value_found = substr( $value_found, 1, strlen( $value_found) ) ;
}
else
{
// value = all until next space, eol or comment
preg_match( "/([^\s".$this -> feature["cc"]."]*)[\s]*[".$this -> feature["cc"]."]*[\s]*[\S]*[\s]*/", trim( $value ), $match) ;
$value_found = $match[1] ;
}
$key_found = trim( $key ) ;
$found = 2 ;
}
}
// creating the array
switch( $found )
{
case 1 :
$block = '/'.$block_found ;
break ;
case 2 :
$aadd = $this -> data[ $block ] ;
$aadd[ $key_found ] = (string)trim ((string)$value_found ) ;
$this -> data[$block] = $aadd ;
break ;
case 0 :
default :
break ;
}
$zeilennr++ ;
}
}
else
{
return new PEAR_Error( "File '".$datasrc."' doesn't exists!", 31, PEAR_ERROR_RETURN, null, null );
}
} // end func parseInput
/**
* writes the data to the given data source or if not given to the datasource of parseInput
* If $datasrc was a array, the last file will used.
*
* See parseInput for $datasrc. If the second argument $preserve is true, the implementation
* should try to preserve the original format and data of the source except changed or added values.
* This mean to preserve for example comments in files or so.
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param boolean $preserve preserving behavior
* @return object PEAR_Error
* @see parseInput()
*/
function writeInput( $datasrc = "", $preserve = true )
{
if( empty( $datasrc ) ) {
$datasrc = $this -> datasrc ;
}
elseif( !file_exists( $datasrc )) {
return new PEAR_Error("File '$datasrc' doesn't exist", 41, PEAR_ERROR_RETURN, null,
null );
}
if( $preserve ) {
return new PEAR_Error("Preserving not supported", 49, PEAR_ERROR_RETURN, null,
null );
}
else {
$fh = fopen( $datasrc, "w") ;
if( !$fh) {
return new PEAR_Error("Couldn't open '$datasrc' for writing", 42, PEAR_ERROR_RETURN, null,
null );
}
else {
foreach( $this -> data as $block => $blockkv ) {
$block = substr( $block, 1) ;
fwrite( $fh, "[$block]\n" ) ;
foreach( $blockkv as $key => $value ) {
if( strpos ( $value, ' ' )) {
$value = '"'.$value.'"' ;
}
fwrite( $fh, "$key = $value\n" ) ;
}
fwrite( $fh, "\n" ) ;
}
fclose( $fh) ;
}
}
} // end func writeInput
}; // end class Config_IniFile
?>

175
pear/Config/Container/db.php

@ -0,0 +1,175 @@
<?php
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Christian Stocker <chregu@phant.ch> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once( "Config/Container.php" ) ;
/**
* Config-API-Implemtentation for DB-Ini-Entries
*
* This class implements the Config-API based on ConfigDefault
*
* The Table structure should be as follows:
*
* CREATE TABLE config (
* datasrc varchar(50) NOT NULL,
* block varchar(50) NOT NULL,
* name varchar(50) NOT NULL,
* value varchar(50)
* );
*
* You can name the Table other than config, but you have to supply then
* this name in the $feature->array
*
* @author Christian Stocker <chregu@phant.ch>
* @access public
* @version $Id$
* @package Config
*/
class Config_Container_db extends Config_Container {
/**
* contains the features given by parseInput
* @var array
* @see parseInput()
*/
var $feature = array("Table" => "config") ;
/**
* Constructor of the class
*
* Connects to the DB via the PEAR::DB-class
*
* @param $dsn string with PEAR::DB "data source name" or object DB object
*/
function Config_Container_db ($dsn ) {
//if dsn is a string, then we have to connect to the db
if (is_string($dsn))
{
include_once ("DB.php");
$this->db = DB::Connect($dsn);
if (DB::isError($db))
{
print "The given dsn was not valid in file ".__FILE__." at line ".__LINE__."<br>\n";
return new DB_Error($db->code,PEAR_ERROR_DIE);
}
}
//if it's an object, it could be a db_object.
elseif (is_object($dsn) && DB::isError($dsn))
{
print "The given param was not valid in file ".__FILE__." at line ".__LINE__."<br>\n";
return new DB_Error($dsn->code,PEAR_ERROR_DIE);
}
// if parent class is db_common, then it's already a connected identifier
elseif (get_parent_class($dsn) == "db_common")
{
$this->db = $dsn;
}
else {
return new PEAR_Error( "The given dsn ($dsn) was not valid in file ".__FILE__." at line ".__LINE__, 41, PEAR_ERROR_RETURN, null, null );
}
}
/**
* parses the input of the given data source
*
* The Data Source can be a string with field-name of the datasrc field in the db
*
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param array $feature Contains a hash of features
* @return mixed returns a DB_ERROR, if error occurs
*/
function parseInput( $datasrc = "", $feature = array( ) )
{
$this->setFeatures($feature, array_merge($this->allowed_options,array("Table")));
$query = "SELECT block,name,value from ".$this->feature["Table"]." where datasrc = '$datasrc'";
$res = $this->db->query($query);
if (DB::isError($res))
{
return new DB_Error($dsn->code,PEAR_ERROR_DIE);
}
else
{
while ($entry = $res->FetchRow(DB_FETCHMODE_ASSOC))
{
$this->data[$entry[block]][$entry[name]] = $entry[value];
}
}
}
/**
* writes the data to the given data source or if not given to the datasource of parseInput
* If $datasrc was a array, the last file will used.
*
* See parseInput for $datasrc. If the second argument $preserve is true, the implementation
* should try to preserve the original format and data of the source except changed or added values.
* This mean to preserve for example comments in files or so.
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param boolean $preserve preserving behavior
* @return mixed returns a DB_ERROR, if error occurs
* @see parseInput()
*/
function writeInput( $datasrc = "", $preserve = True )
{
$query = "delete from ".$this->feature["Table"]." where datasrc = '$datasrc'";
$res = $this->db->query($query);
if (DB::isError($res))
{
return new DB_Error($dsn->code,PEAR_ERROR_DIE);
}
foreach ($this->data as $block => $blockarray)
{
foreach ($blockarray as $name => $value)
{
$query = "insert into ".$this->feature["Table"]." (datasrc,block,name,value) VALUES
('".addslashes($datasrc)."','".addslashes($block)."','".addslashes($name)."','".addslashes($value)."')";
$res = $this->db->query($query);
if (DB::isError($res))
{
return new DB_Error($dsn->code,PEAR_ERROR_DIE);
}
}
}
}
}
?>

154
pear/Config/Container/xml.php

@ -0,0 +1,154 @@
<?php
//+----------------------------------------------------------------------+
// | PHP version 4.0 |
//+----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
//+----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and areunable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
//+----------------------------------------------------------------------+
// | Authors: Christian Stocker <chregu@phant.ch> |
// | Alexander Merz <alexander.merz@t-online.de> |
//+----------------------------------------------------------------------+
//
require_once( "Config/Container.php" ) ;
/**
* Config-API-Implemtentation for XML-Files
*
* This class implements the Config-API based on ConfigDefault
*
* @author Christian Stocker <chregu@nomad.ch>
* @access public
* @version Config_xml.php, 2000/04/16
* @package Config
*/
class Config_Container_xml extends Config_Container {
/**
* contains the features given by parseInput
* @var array
* @see parseInput()
*/
var $feature = array ("IncludeContent" => True,
"MasterAttribute" => False,
"IncludeMasterAttribute" => True,
"IncludeChildren" => True
);
/**
* parses the input of the given data source
*
* The Data Source is a file, so datasrc requires a existing file.
* The feature-array have to contain the comment char array("cc" => Comment char)
*
* @access public
* @param string $datasrc Name of the datasource to parse
* @param array $feature Contains a hash of features
* @return mixed returns a PEAR_ERROR, if error occurs
*/
function parseInput( $datasrc = "",$feature = array() )
{
$this -> datasrc = $datasrc ;
$this->setFeatures($feature, array_merge($this->allowed_options, array('IncludeContent', 'MasterAttribute','IncludeMasterAttribute','IncludeChildren')));
if( file_exists( $datasrc ) )
{
$xml = xmldocfile($datasrc);
$root = domxml_root($xml);
$this->addAttributes($root);
$this->parseElement($root,"/".$root->name);
}
else
{
return new PEAR_Error( "File '".$datasrc."' doesn't
exists!", 31, PEAR_ERROR_RETURN, null, null );
}
} // end func parseInput
/**
* parses the input of the XML_ELEMENT_NODE into $this->data
*
* @access private
* @param object XML_ELEMENT_NODE $element
* @param string $parent xpath of parent ELEMENT_NODE
*/
function parseElement ($element,$parent = "/") {
foreach(domxml_children($element) as $tag => $value)
{
if (XML_ELEMENT_NODE == $value->type)
{
$this->addAttributes($value,$parent);
if (domxml_children($value))
{
$this->parseElement($value,$parent."/".$value->name);
}
}
}
}
//end func parseElement
/**
* ?? ask Christian
*
* @access private
* @param string $element the element to add perhaps?
* @param object I_dont_know $parent the parent element?
*/
function addAttributes($element,$parent="")
{
if ($parent=="") {
//this is only for the root element
$parentslash ="/";
}
if ($this->feature["IncludeChildren"] )
{
$this->data["$parent"."$parentslash"]["children"][] = $element->name;
}
if (($this->feature["IncludeContent"]|| $this->feature["MasterAttribute"] == "content") && $element->content)
{
if ($this->feature["MasterAttribute"] == "content")
{
$this->data["$parent"."$parentslash"][$element->name] =$element->content;
}
if ($this->feature["IncludeMasterAttribute"] || $this->feature["MasterAttribute"] != "content")
{
$this->data["$parent/".$element->name]["content"] =$element->content;
}
}
if (domxml_attributes($element) )
{
foreach (domxml_attributes($element) as $attribute =>
$attributeObject)
{
if ($this->feature["MasterAttribute"] && $attributeObject->name == $this->feature["MasterAttribute"])
{
$this->data[$parent."$parentslash"][$element->name] = domxml_get_attribute($element,$attributeObject->name);
}
if ($this->feature["IncludeMasterAttribute"] || $attributeObject->name != $this->feature["MasterAttribute"])
{
$this->data["$parent/".$element->name][$attributeObject->name] = domxml_get_attribute($element,$attributeObject->name);
}
}
}
}
//endfunc addAttributes
};
?>

428
pear/Config/README.Config

@ -0,0 +1,428 @@
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
Loading…
Cancel
Save