Mega Code Archive

 
Categories / Php / File Directory
 

Bs_IniHandler

<?php define('BS_INIHANDLER_VERSION', '4.0.$x$'); define('BS_INIHANDLER_UNQUOTE_NONE', 0); define('BS_INIHANDLER_UNQUOTE_DOUBLE', 1); define('BS_INIHANDLER_UNQUOTE_SINGLE', 2); define('BS_INIHANDLER_UNQUOTE_ALL', 3); class Bs_IniHandler extends Bs_Object { /** * specifies which chars at the start of a line define a comment line. * the line is left-trimmed before the comparison is made. * * default: '#', '/', ';' * * note: you can only specify chars, not strings. so if you want '//' as * comment char, you need to define '/'. (which is done by default) * * @access public * @var array $commentChars (vector) */ var $commentChars = array('#', '/', ';'); /** * should quoted values be unquoted? * * 0 = no * BS_INIHANDLER_UNQUOTE_SINGLE = only single-quotes 'like this' * BS_INIHANDLER_UNQUOTE_DOUBLE = only double-quotes "like this" * BS_INIHANDLER_UNQUOTE_ALL = single and double quotes (default) * * @access public * @var int $unQuote */ var $unQuote = BS_INIHANDLER_UNQUOTE_ALL; /** * vector with the sections as strings. * * note: since this var is not really needed, and all information is available in * $this->_params, this internal var may disappear in the future. * * @access private * @var array $_sections */ var $_sections; /** * 2-dim hash where the first dim is a hash with the section names, the 2nd * is the key/value pair hash. * @access private * @var array $_params */ var $_params; /** * @todo make private */ var $comments; /** * the fullpath to the currently used file. * @var string $_fileFullPath */ var $_fileFullPath; /** * the last error message of the error that occured. not set = no error. * @access private * @var string $_lastError */ var $_lastError; /** * Constructor. * WARNING: please do not use the param $fileFullPath here, better call loadFile() yourself * because otherwise you won't know if it worked or not. * @param string $fileFullPath */ function Bs_IniHandler($fileFullPath='') { parent::Bs_Object(__FILE__); //call parent constructor. if (!empty($fileFullPath)) { $this->loadFile($fileFullPath); } } /** * Loads the given file (read in and parse). * @access public * @param string $fileFullPath (a fullpath to the desired file.) * @return bool (see getLastError()) */ function loadFile($fileFullPath) { $this->reset(); if (!file_exists($fileFullPath)) { $this->_lastError = "File doesn't exists: '{$fileFullPath}'"; return FALSE; } if (!is_readable($fileFullPath)) { $this->_lastError = "File is not readable: '{$fileFullPath}'"; return FALSE; } $this->_fileFullPath = $fileFullPath; $fileContent = file($fileFullPath); $this->_parseFromArray($fileContent); return TRUE; } /** * loads the ini stuff from the given string instead of a file (read in and parse). * @access public * @param string $str * @return bool (see getLastError()) */ function loadString($str) { $this->reset(); $arr = explode("\n", $str); $this->_parseFromArray($arr); return TRUE; } /** * sets the quote handling. * @access public * @param int $mode (see constants) * @return void */ function setQuoteHandling($mode=BS_INIHANDLER_UNQUOTE_ALL) { $this->unQuote = $mode; } /** * gets called from loadFile() and loadString() to parse the data. * @access private * @param array (vector filled with strings (lines)) * @return void */ function _parseFromArray($arr) { $this->comments = array(); $comment = array(); $section = ''; foreach($arr as $line) { $sectionFound = $valueFound = FALSE; $param = array('key'=>'', 'val'=>''); do { // try $line = trim($line); # Skip empty lines if (empty($line)) break; // try # Comment if (in_array($line[0], $this->commentChars)) { $comment[] = $line; break; // try } # Section if (preg_match('/\[(.*)\]/', $line, $ar)) { $section = $ar[1]; $sectionFound = TRUE; break; // try } # Parameter // split 1x at first '=' $tmp = explode('=', $line); if (!is_array($tmp)) break; // try if (sizeOf($tmp) < 2) { //invalid comment line, whatever. //no good if we arrive here. that's some crappy line that should not be in the file. //we could issue a warning here. $comment[] = @$tmp[0]; break; } $param['key'] = trim($tmp[0]); array_shift($tmp); if (sizeOf($tmp)>1) $tmp[0] = implode('=', $tmp); $param['val'] = isSet($tmp[0]) ? trim($tmp[0]) : ''; if (empty($param['val'])) { $valueFound = TRUE; break; // try } $unQuote = ''; if ($this->unQuote & BS_INIHANDLER_UNQUOTE_DOUBLE) $unQuote .= '"'; if ($this->unQuote & BS_INIHANDLER_UNQUOTE_SINGLE) $unQuote .= "'"; if (empty($unQuote)) { $valueFound = TRUE; break; // try } // trim quote $regEx = '/^(['.$unQuote.']?)(.*)\1$/'; if (preg_match($regEx, $param['val'], $ar)) { $param['val'] = $ar[2]; $valueFound = TRUE; break; // try } else { //the value had unmatching quotes, like "here' or 'here" break; // try } } while(FALSE); if ($sectionFound) { $this->_sections[] = $section; if (!empty($comment)) $this->comments[$section] = $comment; $comment = array(); } else if ($valueFound) { $this->_params[$section][$param['key']] = $param['val']; if (!empty($comment)) $this->comments[$section .'__'. $param['key']] = $comment; $comment = array(); } } // foreach if (!empty($comment)) $this->comments['__LastComment__'] = $comment; } /** * */ function toString() { $outStr = "# Bs_IniHandler"; foreach ($this->_params as $section => $params) { if (isSet($this->comments[$section])) { foreach ($this->comments[$section] as $comment) $outStr .= "{$comment}\n"; } $outStr .= "[".$section."]\n"; foreach ($params as $key => $value) { if (isSet($this->comments[$section .'__'. $key])) { foreach ($this->comments[$section .'__'. $key] as $comment) $outStr .= " {$comment}\n"; } $outStr .= " " .$key. " = " .$value. "\n"; } $outStr .= "\n"; } if (isSet($this->comments['__LastComment__'])) { foreach ($this->comments['__LastComment__'] as $comment) $outStr .= "{$comment}\n"; } return $outStr; } /** * saves the ini settings to the file specified. * @access public * @param string $fileFullPath (see above) * @return bool (see getLastError()) * @see saveString() */ function saveFile($fileFullPath) { $outStr = $this->toString(); if (!$fp = fopen($this->_fileFullPath, 'wb')) { $this->_lastError = "Failed open the file for writing: '{$fileFullPath}'"; return FALSE; } if (!fwrite($fp, $outStr)){ $this->_lastError = "Failed to write (but was able to open) the file: '{$fileFullPath}'"; return FALSE; } @fclose($fp); return TRUE; } /** * resets this object so we can re-use it for something else. * some setting vars are not reset. * * resets: * _sections * _params * _fileFullPath * _lastError * * keeps: * commentChars * unQuote * * @access public * @return void */ function reset() { unset($this->_sections); unset($this->_params); unset($this->_fileFullPath); unset($this->_lastError); } /** * returns [all parameters|parameter] [for the given section]. * * examples: * get() => returns all sections with all params as 2-D hash. * array of [<section>][<key>] => <string> * get('section') => returns all params for the section specified as 1-D hash. * array of [<key>] => <string> * get('section', 'key') => returns the param specified of the section specified as string. * * note: if a param is defined in the 'global scope', use an empty string for the * $section name. example: get('', 'key') * * @access public * @param string $section if not given returns all sections * @param string $key if not given returns all keys * @return mixed (see above) * @throws null (if the given section or key does not exist) */ function get($section=NULL, $key=NULL) { if (is_null($section)) return $this->_params; if (!isSet($this->_params[$section])) return NULL; //throw if (is_null($key)) return $this->_params[$section]; if (!isSet($this->_params[$section][$key])) return NULL; //throw return $this->_params[$section][$key]; } /** * tells if the section or key specified is set. * * examples: * has('mySection') => tells if 'mySection' is set * has('mySection', 'myKey' => tells if myKey in mySection is set. * * note: case matters! * * @access public * @param string $section * @param string $key (default is NULL) * @return bool */ function has($section, $key=NULL) { if (is_null($key)) { return (isSet($this->_params[$section])); //using _params instead of _sections cause it's a hash. in_array is slower. } else { return (isSet($this->_params[$section]) && isSet($this->_params[$section][$key])); } } /** * returns the text message of the last error that occured. * * call this function if something failed, for example after getting * bool FALSE back from loadFile(). * * @access public * @return mixed (string last error, or NULL if no error occured.) */ function getLastError() { if (is_null($this->_lastError)) return NULL; return $this->_lastError; } } # SELF - Test if (basename($_SERVER['PHP_SELF']) == 'Bs_IniHandler.class.php') { $testData =<<<EOD # Comment 1 # comment 2 [] globalData = foo # comment A [Some test data] # comment B one = hallo two = "hallo" # comment C food = "Tom's Pizza = 'good stuff'" more food = Sam's Pizza's = 'best stuff' empty = "" noVal = # comment D [more test data] one = hi two = 'hi' food = 'Pizza = "good"' empty = '' noVal # comment E EOD; $iniHandler = new Bs_IniHandler(); $iniHandler->loadString($testData); #XR_dump($iniHandler->comments, __LINE__, '', __FILE__); XR_dump($iniHandler->toString(), __LINE__, '', __FILE__); } ?>