Tere, en nyt löytänyt oikein sopivia paikkoja suomessa, minne voisi laittaa omia tekeleitä testattavaksi, joten ajattelin kokeilla ohjelmointiputkaa.
Kyseessä on luokka, joka lukee ja kirjoittaa nimi-arvopareja tekstitiedostosta ja muuttaa ne php:n ymmärtämiksi muuttujiksi. Muuttujiin pääsee käsiksi suorilla olion kenttämuuttujien viittauksilla. Koodi on kovasti kommentoitu, mutta toistaiseksi vain englanniksi.
Löydättekö vakavia puutteita, bugeja ja kommentoitavaa? Kaikki palaute on arvokasta. Koodi on jaossa vapaana lähdekoodina, joten sitä voi käyttää ja muokkailla mielin määrin omiin tarpeisiin, muttei myydä kaupallisessa mielessä.
Jos härveli tuli nyt kirjoitettua väärään paikkaan, niin olettehan ystävällisiä... :)
Paketti esimerkkeineen ladattavissa:
http://www.hmv-systems.fi/marko/ConfigTool/
Itse luokka:
<?php /** * Online Web Application Builder Classes * @package OWAB */ /** * ConfigTool * * Part of OWAB (Online Web Application Builder) class set. * * ConfigTool reads normal text file to get all name value pairs, that are ment * to use on anykind of application. In addition to read files, separate comments, * automatic variable type scanning through prefix in keys, ConfigTool can be used to * add, edit and delete key value pairs and save them to the file. * * One additional usage with the class is to get language specific information from * the external text file. Then you can make straight object references to the * variables. Please see language_example.php for more information * * Special features * * By starting key name in a config.txt file with one of the four predefined prefixes * user can make automatic key conversion to different data types. Four prefixes are: * b_ like boolean, s_ like string, a_ like array and i_ like integer. * * {@internal Now, if AUTOBOOLEAN, AUTOSTRING, AUTOARRAY and AUTOINTEGER are set * true in field variables (as they are by default), class converts the value accordant * to the key to proper data type.}} * * Normally all values are in string format on text file. * With boolean you can use one of the four values to get boolean work on automatic * conversion: true/false, on/off, yes/no, 1/0. So use these values on a text file. More * about configuration file format is described on {@link test_config.txt} file. * Commenting is also discussed there more precisely. * * To debug and check key value pair, user can use getConfigLines() method to get * an array presentation of all lines with or without comments. * * Here is a small example, how to use this class: * <code> * <?php * include( "path/to/class/ConfigTool.php" ); * $conf = new ConfigTool(); * $conf->setConfigFromFile( "config.txt" ); * // now you can get key value by direct reference * echo $conf->name_of_variable; * // to get all config lines for checking and debugging use: * $ar = $conf->getConfigLines(); * // other useful methods are adding, updating, deleting and saving modified * // please see function descriptions, tests, and examples to know better, how * // they work. * ?> * </code> * * Remember to set CHMOD to write level on your config.txt file! * * @author Marko Manninen <marko.manninen@hmv-systems.fi> * @copyright Copyright (c) 2004, Marko Manninen * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @version 0.01 * @todo Set keys after add, update, delete to the global scope. * Tie comments and their key value pairs together. Optimize code * @package OWAB */ class ConfigTool { /** * Empty spaces between key string and value string * Thought too obvious to mention, = mark is between them * @access private * @var int */ var $INDENT; /** * Path and name of the configuration file * @access private * @var string */ var $FILENAME; /**#@+ * @access private */ /** * All lines in array that are read from the configuration file * @var array */ var $LINES; /** * Reserved words list, that will be checked runtime * These words cannot be used in configuration file! * @var array */ var $RESERVED_WORDS; /**#@-*/ /**#@+ * @access private */ /** * Convert key type to boolean if key starts with b_ * @var bool */ var $AUTOBOOL; /** * Convert key type to integer if key starts with i_ * @var bool */ var $AUTOINTEGER; /** * Convert key type to array if key starts with a_ * @var bool */ var $AUTOARRAY; /** * Convert key type to string if key starts with s_ * @var bool */ var $AUTOSTRING; /**#@-*/ /** * ConfigTool * * @internal Constructor inits the class fields with wanted values. * Reserved words should be changed by the developer only. */ function ConfigTool() { $this->LINES = array(); $this->FILENAME = ""; // if any new fields are inserted to the class // the name of the filed must be added to the RESERVED_WORD list! $this->RESERVED_WORDS = array( "LINES", "INDENT", "FILENAME", "RESERVED_WORDS", "AUTOBOOL", "AUTOINTEGER", "AUTOARRAY", "AUTOSTRING" ); $this->INDENT = 25; $this->AUTOBOOL = true; $this->AUTOINTEGER = true; $this->AUTOARRAY = true; $this->AUTOSTRING = true; } /** * Set flags * Internal key type conversion is activated throught these values * If defauld flags are to be changed, flags must be set before calling * setConfigFromFile() method * @access public * @param bool $pAutoBool * @param bool $pAutoInteger * @param bool $pAutoArray * @param bool $pAutoString */ function setFlags( $pAutoBool = true, $pAutoInteger = true, $pAutoArray = true, $pAutoString = true ) { $this->AUTOBOOL = $pAutoBool; $this->AUTOINTEGER = $pAutoInteger; $this->AUTOARRAY = $pAutoArray; $this->AUTOSTRING = $pAutoString; } /** * Get indent, the number of empty spaces between key name and value * With this value, you can set configuration file variables to look * visually better. That means, it's easier to read. * @access public * @return integer */ function getIndent() { return $this->INDENT; } /** * Set indent, the number of empty spaces between key name and value * With this value, you can set configuration file variables to look * visually better. That means, it's easier to read. * @access public * @param string $pIndent */ function setIndent( $pIndent ) { $this->INDENT = $pIndent; } /** * Get configuration file lines. * Method gives all the read lines from the configuration file. This is useful * when debugging and checking all the name value pairs from the file. Additional parameter * is used to get either all lines with comments, or lines without comments, or only comment lines. * So parameters can be: 1. all 2. "" that is same as 3. configs 4. comment * @access public * @param string $pStr * @return array */ function getConfigLines( $pStr = "" ) { $temp_array = array(); // return all rows if( $pStr == "all" ) $temp_array = $this->LINES; // return only configuration rows if( $pStr == "configs" || $pStr == "" ) { for( $i=0; $i < count( $this->LINES ); $i++ ) { if ( eregi( "^[A-Z]", $this->LINES[$i] ) ) { array_push( $temp_array, $this->LINES[$i] ); } } } // return only comment rows if( $pStr == "comments" ) { for( $i=0; $i < count( $this->LINES ); $i++ ) { if ( !eregi( "^[A-Z]", $this->LINES[$i] ) ) { array_push( $temp_array, $this->LINES[$i] ); } } } // return $temp_array; }//END OF FUNCTION getConfigLines /** * Set configurations from the file * This is the main method for getting and setting configuration variables * Parameter given is the relative path and exact name of the configuration file * Method checks if file name is specified, exists and contains valueable data. * Comments are not counted as valuable data, so to keep method working, you need * at least one name value pair in your configuration file. If everything goes well * method returns boolean true. Else false is returned * * @access public * @param string $pFileName * @return bool */ function setConfigFromFile( $pFileName ) { $this->FILENAME = $pFileName; // if( empty( $this->FILENAME ) ) { trigger_error( "File not specified!", E_USER_ERROR ); return false; } if( !file_exists( $this->FILENAME ) ) { trigger_error( "File [$file_name] does not exist!", E_USER_ERROR ); return false; } // $fp = fopen( $this->FILENAME, "r" ); // if( ( !$fp) || ( empty( $fp ) ) ) { trigger_error( "File opening error!", E_USER_ERROR ); return false; } // $r = 0; while( !feof( $fp ) ) { $line = fgets( $fp, 4096 ); // trim lines from leading and trailing whitespaces and line-endings $this->LINES[$r] = trim( $line ); $r++; } // if( count( $this->getConfigLines() ) == 0 ) { trigger_error( "Config file [$this->FILENAME] doesn't contain any key value pairs!", E_USER_ERROR ); return false; } return $this->_parseConfig(); }//END OF FUNCTION _setConfigFromFile /** * Parse configuration lines from the LINES array * If line start with alphabeth, it is tranported to the * _parseConfig() method. Line that start with anything else * like # / ; or other marks are not touched. * If everything goes well, return true * @see _setConfig() * @access private * @return boolean */ function _parseConfig() { for( $i=0; $i < count( $this->LINES ); $i++ ) { // if line starts with a-Z alphabeth, it is supposed to be // a configuration name value pair if ( eregi( "^[A-Z]", $this->LINES[$i] ) ) { $this->_setConfig( $this->LINES[$i] ); } } return true; }//END OF FUNCTION _parseConfig /** * Set configuration line. With this function line is separated to the * key value pairs and class scope is filled with keys. Automatic key type * concersion is made now. Return true, if everything is done right * @see _parseConfig() * @access private * @param string $line * @return boolean */ function _setConfig( $line ) { // check, if there are any occurence of = marks in the line // at least one must be founded to make name value to work if( substr_count( $line, "=" ) < 1 ) trigger_error( "There was no = -marks on the line: " . $line . " in file: " . $this->FILENAME . ". Please set at least one = -mark to separate name from value.", E_USER_WARNING ); // separate line with = list ( $key, $val ) = split( "=", $line ); // remove all white spaces from the key $key = ereg_replace( "[ ]", "", $key ); // remove white spaces before and after val $val = trim( $val ); // then check '-marks at line start if ( !ereg( "^'", $val ) && !preg_match( "/a_/i", $key ) ) { $val = ereg_replace( "[ ]", "", $val ); } else { // remove the leading ' and trailing ' $val = ereg_replace( "^'", "", $val ); $val = ereg_replace( "'$", "", $val ); } // if key is not defined in the object scope // set up new key with new value if( !$this->$key ) { $this->$key = $val; } else { // if dublicate configuration variable is found, set fatal error! trigger_error( "Initialization error. Dublicate variable (key: " . $key . ") was found from the configuration file! Please change the name in the file: " .$this->FILENAME, E_USER_WARNING ); } if( $this->isReserved( $key ) ) { trigger_error( "Key word is in reserved word list (key: " . $key . ")! Please change the name in the file: " .$this->FILENAME, E_USER_ERROR ); } // check autotypes: boolean, integer, string and array $this->_checkAutoTypes( $key ); // set key value pair to the debug array return true; }//END OF FUNCTION _setConfig /** * Deletes key and value from the config array. * Key name is checked, if it is defined in ConfigTool object. Then it's deleted. * You must call saveToFile() method, if you need to save changes to the text file. * @see saveToFile() * @access public * @param string $pKey * @return boolean */ function deleteKey( $pKey ) { if( $pKey == "" || $pKey == NULL ) { trigger_error( "Delete error. Key was not defined.", E_USER_WARNING ); return false; } if( $this->isReserved( $pKey ) ) { trigger_error( "Delete error. Key is on reserved word list and cannot be deleted.", E_USER_WARNING ); return false; } // $temp_array = array(); $r = 0; // if( $this->$pKey ) { $ar = $this->getConfigLines( "all" ); for( $i=0; $i < count( $ar ); $i++ ) { list ( $key, $val ) = split( "=", $ar[$i] ); $key = ereg_replace( "[ ]", "", $key ); if ( $key != $pKey ) { $temp_array[$r] = $ar[$i]; $r++; } } $this->LINES = $temp_array; unset( $this->$pKey ); unset( $temp_array ); return true; } else { trigger_error( "Delete error. Name ($pKey) is was not found from the configuration file and couldn't be deleted!", E_USER_WARNING ); return false; } }//END OF FUNCTION deleteKey /** * Saves all config variables to the file * All variables and comments are saved to the file. File name is defined when you * make the object and call setConfigFromFile( $pFileName ) * @see setConfigFromFile( $pFileName ) * @access public * @return boolean */ function saveToFile() { $contents = $this->_arrayToString( $this->LINES, "\n" ); // $res = fopen( $this->FILENAME, 'w' ); if( !is_resource( $res ) ) { trigger_error( "Saving error. Could not open configuration file " . $this->FILENAME, E_USER_ERROR ); return false; } fwrite( $res, $contents, 4096 ); /* if( !is_resource( $res ) ) { trigger_error( "Saving error. Could not save to configuration file " . $this->FILENAME, E_USER_ERROR ); return false; } */ fclose( $res ); return true; }//END OF FUNCTION saveToFile /** * Add key value pair. * * Method checks if key is already defined or is in reserved word list and then * adds key value pair{@internal as a string presentation to the global line array}}. * Long string values must be started and ended with ' marks! * See config_definitions to learn, how to make ConfigTool compatible configurations * name value pairs. * You must call saveToFile() method, if you need to save changes to the text file. * @see saveToFile() * @access public * @param string $pKey * @param string $pVal * @return boolean */ function addKeyValue( $pKey, $pVal ) { if( $pKey == "" || $pKey == NULL ) { trigger_error( "Add error. Key was not defined.", E_USER_WARNING ); return false; } if( $this->isReserved( $pKey ) ) { trigger_error( "Add error. Key is on reserved word list. Change the key name.", E_USER_WARNING ); return false; } if( !$this->isDefined( $pKey ) ) { $pVal = $this->_checkType( $pKey, $pVal ); $line = $pKey . str_pad( " ", $this->INDENT - strlen( $pKey ) ) . " = " . $pVal; array_push( $this->LINES, $line ); // if value starts with ', remove them from object value // however, ' marks are left in array, because // array is saved to the file, and long strings // must be surrounded by ' marks to work properly if ( ereg( "^'", $pVal ) ) { $pVal = ereg_replace( "^'", "", $pVal ); $pVal = ereg_replace( "'$", "", $pVal ); } $this->$pKey = $pVal; $this->_checkAutoTypes( $pKey ); return true; } else { trigger_error( "Add error. Name ($pKey) is already defined in configuration file. Please choose another name!", E_USER_WARNING ); return false; } }//END OF FUNCTION addKeyValue /** * Check type of key and value and return correct value back * @see addKeyValue() * @access private * @param string $pKey * @param string $pVal * @return string */ function _checkType( $pKey, $pVal ) { // boolean must start with b_ if ( preg_match( "/^b_/i", $pKey ) ) { if( gettype( $pVal ) == "boolean" ) return $this->_booleanToString( $pVal ); else { $pattern = array( "true","yes","1","on","false","no","0","off" ); for( $i=0; $i < count( $pattern ); $i++) { if( $pattern[$i] == $pVal ) return $pVal; } trigger_error( "Boolean error. Specified boolean value ($pVal) is not accepted. Use (true|yes|1|on) or (false|no|0|off) values only.", E_USER_WARNING ); } } // array must start with a_ else if ( preg_match( "/a_/i", $pKey ) ) { if( gettype( $pVal ) == "array" ) return $this->_arrayToString( $pVal ); else return $pVal; } // integer must start with i_ else if ( preg_match( "/i_/i", $pKey ) ) { return $pVal; } // string must start with s_ else if ( preg_match( "/s_/i", $pKey ) ) { return $this->_stringToString( $pVal ); } // everything else is handled as a string else { return $pVal; } }//END OF FUNCTION _checkType /** * Checks, if key word is defined * * This is more presice method than trying to refer straight to * the class scope keys. Expecially boolean keys and values * may cause problems with straight object referings * @access public * @param string $pKey * @return bool */ function isDefined( $pKey ) { $ar = $this->getConfigLines(); for( $i=0; $i< count( $ar ); $i++ ) { $line = $ar[$i]; list ( $key, $val ) = split( "=", $line ); $key = ereg_replace( "[ ]", "", $key ); if( $pKey == $key ) return true; } return false; }//END OF FUNCTION isDefined /** * Checks, if key word is in reserved word list * @access public * @param string $pKey * @return bool */ function isReserved( $pKey ) { for( $i=0;$i< count( $this->RESERVED_WORDS ); $i++ ) if( $pKey == $this->RESERVED_WORDS ) return true; return false; }//END OF FUNCTION isReserved /** * Update excisting key value pair * Long string values must be started and ended with ' marks! * See config_definitions to learn, how to make ConfigTool * compatible configurations name value pairs. * @access public * @param string $pKey * @param string $pVal * @return bool */ function updateKeyValue( $pKey, $pVal ) { $temp_array = array(); // $pVal = $this->_checkType( $pKey, $pVal ); // if( $this->isDefined( $pKey ) ) { $ar = $this->getConfigLines( "all" ); for( $i=0; $i < count( $ar ); $i++ ) { list ( $key, $val ) = split( "=", $ar[$i] ); $key = ereg_replace( "[ ]", "", $key ); if ( $key == $pKey ) $line = $pKey . str_pad( " ", $this->INDENT - strlen( $pKey ) ) . " = " . $pVal; else $line = $ar[$i]; // $temp_array[$i] = $line; } $this->LINES = $temp_array; // if value starts with ', remove them from object value // however, ' marks are left in array, because // array is saved to the file, and long strings // must be surrounded by ' marks to work properly if ( ereg( "^'", $pVal ) ) { $pVal = ereg_replace( "^'", "", $pVal ); $pVal = ereg_replace( "'$", "", $pVal ); } $this->$pKey = $pVal; $this->_checkAutoTypes( $pKey ); unset( $temp_array ); return true; } else { unset( $temp_array ); trigger_error( "Update error. Name ($pKey) was not found from the configuration file. Please choose another name!", E_USER_WARNING ); return false; } }//END OF FUNCTION updateKeyValue /** * Check, if string starts with specified symbol (b_, i_, a_, s_) * @access private * @param string $key */ function _checkAutoTypes( $key ) { // boolean must start with b_ if ( $this->AUTOBOOL && preg_match( "/^b_/i", $key ) ) { $this->_toBoolean( $key ); } // array must start with a_ else if ( $this->AUTOARRAY && preg_match( "/a_/i", $key ) ) { $this->_toArray( $key ); } // integer must start with i_ else if ( $this->AUTOINTEGER && preg_match( "/i_/i", $key ) ) { $this->_toInteger( $key ); } // string must start with s_ else if ( $this->AUTOSTRING && preg_match( "/s_/i", $key ) ) { $this->_toString( $key ); } // everything else is handled as a string else { $this->_toString( $key ); } }//END OF FUNCTION _checkAutoTypes /** * Set key to boolean from string presentation * @access private * @param string $key * @return boolean */ function _toBoolean( $key ) { $val = $this->$key; if( eregi( "(true|yes|1|on)", $val ) ) { $this->$key = true; return true; } else if( eregi( "(false|no|0|off)", $val ) ) { $this->$key = false; return true; } else { trigger_error( "_toBoolean operation failed. Value couldn't be detected (" . $key . " = " . $val . ").Please check the value in the configuration file.", E_USER_ERROR ); unset( $this->$key ); return false; } }//END OF FUNCTION _toBoolean /** * Set key to array from string presentation * @access private * @param string $key */ function _toArray( $key ) { $ar = array(); //$this->$key = str_replace( " ", "", $this->$key ); $ar = split( ",", $this->$key ); $this->$key = $ar; unset ( $ar ); }//END OF FUNCTION _toArray /** * Set key to string from string presentation * @access private * @param string $key */ function _toString( $key ) { //echo "<br />S: " . $ConfigKey; }//END OF FUNCTION _toString /** * Set key to integer from string presentation * @access private * @param string $key */ function _toInteger( $key ) { settype( $this->$key, "integer" ); }//END OF FUNCTION _toInteger /** * Set value to boolean from string presentation * @access private * @param bool $b * @return string */ function _booleanToString( $b ) { if( $b ) return "true"; else return "false"; }//END OF FUNCTION _booleanToString /** * Set value from string to string presentation * @access private * @param string $str * @return string $str */ function _stringToString( $str ) { return "$str"; }//END OF FUNCTION _stringToString /** * Convert array to comma separated string. Other separator can be * defined in parameter * @access private * @param array $array * @param string $separ * @return string $str */ function _arrayToString( $array, $separ = "," ) { $str = ""; for( $i=0; $i < count( $array ) - 1; $i++ ) { $str .= $array[$i] . $separ; } $str .= $array[$i]; return $str; }//END OF FUNCTION _arrayToString }//END OF CLASS ConfigTool ?>
Muokkaa tohon koodiphp-tagit, pls. Tulee vähän paremman näköseksi.
En kyllä löydä aktiivista muokkauslinkkiä tältä sivulta,... pitääkö laittaa vastaus uudella koodilla vai kirjoittaa uusi aloitus?
Ps. tätä viestiä pystyn muokkamaan, mutta alkuperäistä en. Jostakin syystä.
Viestiä pystyy muokkaamaan muistaakseni vielä noin puolisen tuntia kirjoittamisen jälkeen. Mutta jos oikein ylpeä olet tekeleestäsi ja mielestäsi se on julkaisemisen arvoinen, pistä ihmeessä koodivinkiksi. Laaksosen Antti sen sitten viime kädessä päättää, julkaistaanko vinkki vai ei.
No laitetaampas sitten sinne. Mutta jokatapauksessa täytyisi vielä tarkastella luokan toimivuus useammassa kädessä. Täytyy muistaa seuraavalla kerralla toi koodiphp tagi. Ylpeys hiukka kärsii nyt. :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.