Login   Register  
PHP Classes
elePHPant
Icontem

File: class.config_reader.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Keyvan Minoukadeh  >  Config Manager  >  class.config_reader.php  >  Download  
File: class.config_reader.php
Role: ???
Content type: text/plain
Description: Class - config reader
Class: Config Manager
Sorry, no longer supported
Author: By
Last change:
Date: 2002-04-09 02:25
Size: 11,615 bytes
 

Contents

Class file image Download
<?php
/* vim: set ai tabstop=4: */
// $Date: 2002/04/09 01:29:38 $
// $Revision: 1.3 $
// +----------------------------------------------------------------------+
// | CONFIG MANAGER 0.1.2 - 09-Apr-2002                                   |
// +----------------------------------------------------------------------+
// | Author: Keyvan Minoukadeh - keyvan@k1m.com - http://www.k1m.com      |
// +----------------------------------------------------------------------+
// | PHP class for managing plain text config files.                      |
// +----------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or        |
// | modify it under the terms of the GNU General Public License          |
// | as published by the Free Software Foundation; either version 2       |
// | of the License, or (at your option) any later version.               |
// |                                                                      |
// | This program is distributed in the hope that it will be useful,      |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
// | GNU General Public License for more details.                         |
// +----------------------------------------------------------------------+

if (defined('CONFIGMAN_DIR')) {
	require_once(CONFIGMAN_DIR.'class.config_base.php');
}

/**
* Config manager reader class
*
* Use this class to read plain text config files.
* This is an extension to the base config class.
*
* @author   Keyvan Minoukadeh <keyvan@k1m.com>
* @version  0.1.2
*/
class config_reader extends config_base
{
	/**
	* fetch mode
	*
	* CONFIGMAN_FETCH_ASSOC = return config vars as associative array
	* CONFIGMAN_FETCH_OBJECT = return config vars as an object
	*/
	var $fetch_mode				= CONFIGMAN_FETCH_ASSOC;

	/**
	* allow serialize?
	*/
	var $cache_config			= false;


	/////////////
	// methods
	/////////////


	/**
	* Constructor
	*
	* @param	string	$config		config file to use
	* @param	int		$fetch_mode	fetch mode
	*/
	function config_reader($config=null, $fetch_mode=null)
	{
		// run base constructor
		if (!is_null($config)) {
			$this->config_base($config);
		}

		if (!is_null($fetch_mode)) {
			$this->fetch_mode = $fetch_mode;
		}
	}

	/**
	* Load config
	*
	* Parse and update class variables with values found in config.
	* Cache file refers to a file containing the serialized values found in the config file,
	* if present it will load the values quicker.
	*
	* @param	int		$fetch_mode	either CONFIGMAN_FETCH_ASSOC or CONFIGMAN_FETCH_OBJECT
	* @param	bool	$reload		if true, will reload values from main config even if cache exists
	* @return	mixed				either associative array, or object
	*/
	function load($fetch_mode=null, $reload=false)
	{
		$func_name = 'load';

		clearstatcache();

		if (!$this->is_file_valid()) {
			if ($this->debug) $this->_debug("$func_name: Invalid config file");
		}

		$config = $this->config;
		$file_cache = $this->config_cache_dir.basename($config).'.cache';
		
		// grab file modification times
		$config_ts = @filemtime($config);
		$file_cache_ts = @filemtime($file_cache);
		
		// check if cache file available
		if (!$reload && file_exists($file_cache) && is_readable($file_cache) && ($config_ts == $file_cache_ts)) {
			if ($this->debug) $this->_debug("$func_name: Loading from cache file");
			// unserialize config cache (returns associative array)
			$fp = fopen($file_cache, 'r');
			// shared lock
			flock($fp, 1);
			$contents = fread($fp, filesize($file_cache));
			// release lock
			flock($fp, 3);
			fclose($fp);
			$config_array = unserialize($contents);
			if (!is_array($config_array)) {
				if ($this->debug) $this->_debug("$func_name: Invalid config cache ($file_cache), remove and try again");
				return false;
			}
			// loop through associative array and update vars
			foreach ($config_array as $key => $val) {
				$this->set_param_from_array($key, $val);
			}
		} elseif (file_exists($config) && is_readable($config)) {
			if ($this->debug) $this->_debug("$func_name: Loading from config file");
			// parse config file
			$this->_process_config(file($config));
			if ($this->cache_config) {
				$this->_write_config_cache($file_cache, filemtime($config));
			}
		} else {
			if ($this->debug) $this->_debug("$func_name: Could not load config file ($config)");
			return false;
		}
		return $this->_return_config_vars($fetch_mode);
	}

	/**
	* Load config from string
	*
	* Same as load() except first parameter will be the string contaning
	* the config lines. (useful if you're not storing the config in a file, eg. using a DB
	* or generating it some way)
	*
	* @param	string	$config		config contents as string
	* @param	int		$fetch_mode	either CONFIGMAN_FETCH_ASSOC or CONFIGMAN_FETCH_OBJECT
	* @return	mixed				either associative array, or object
	*/
	function load_from_string($config, $fetch_mode=null)
	{
		$func_name = 'load_from_string';

		$config = explode("\n", trim($config));
		if (is_array($config) && (count($config) > 0)) {
			$this->_process_config($config);
			return $this->_return_config_vars($fetch_mode);
		} else {
			if ($this->debug) $this->_debug("$func_name: Invalid config contents");
			return false;
		}
	}

	///////////////////////
	// PRIVATE FUNCTIONS //
	///////////////////////

	/**
	* Return config vars
	*
	* @param	int		$fetch_mode	CONFIGMAN_FETCH_ASSOC or CONFIGMAN_FETCH_OBJECT or null for default
	* @return	mixed				array or object, depending on fetch mode
	* @access	private
	*/
	function _return_config_vars($fetch_mode=null)
	{
		$return = array();
		foreach ($this->param as $key => $val) {
			$return["$key"] = $val[(string)key($val)]['value'];
		}
		if (is_null($fetch_mode)) {
			$fetch_mode = $this->fetch_mode;
		}
		if ($fetch_mode === CONFIGMAN_FETCH_OBJECT) {
			return (object)$return;
		} else {
			return $return;
		}
	}

	/**
	* Write config cache
	*
	* @param	string	$file_path	serialize config array and write to disk
	* @param	int		$timestamp	unix timestamp to set as modification time
	* @return	bool
	* @access	private
	* @see		load
	*/
	function _write_config_cache($file_path, $timestamp=null)
	{
		$func_name = '_write_config_cache';
		if ($this->cache_config) {
			$serialized = serialize($this->param);
			$fp = @fopen($file_path, "w");
			if (!$fp) {
				if ($this->debug) $this->_debug("$func_name: Could not create cache file");
				return false;
			} else {
				// exclusive lock
				flock($fp, 2);
				$result = @fwrite($fp, $serialized);
				// release lock
				flock($fp, 3);
				fclose($fp);
				if (!$result) {
					if ($this->debug) $this->_debug("$func_name: Could not write cache file");
					return false;
				} else {
					if ($this->debug) $this->_debug("$func_name: Cache file written");
					// touch file with modification time of main config file (used for comparison)
					touch($file_path, ((is_null($timestamp) || !$timestamp) ? time() : $timestamp));
					@chmod($file_path, 0600);
					return true;
				}
			}
		}
		return false;
	}

	/**
	* Process config
	*
	* @param	array	$config	each line of the config file as a seperate array element
	* @return	bool			true if successfully loaded, false otherwise
	* @access	private
	*/
	function _process_config($config)
	{
		$func_name = "_process_config";

		if (!is_array($config) || (count($config) < 1)) {
			if ($this->debug) $this->_debug("$func_name: Config file is empty, or is not an array");
			return false;
		}

		$var = array();
		$section = $this->default_section;
		$comment = "";
		$line_count = 0;

		foreach ($config as $line) {
			$line_count++;
			$line = trim($line);
			if (empty($line)) {
				continue;
			}
			// plain comment
			if (preg_match('!^'.preg_quote($this->comment).'(.*)$!', $line, $match)) {
				if (trim($match[1]) != '') {
					$comment .= trim($match[1])."\n";
				}
				unset($match);
				continue;
			}
			// variable definition
			if (preg_match('!^'.$this->regex_type.'?('.$this->regex_var.')(\.'.$this->regex_assoc.')?\s*'.preg_quote($this->separator).'\s*(?'.'>(["\'])?)(.*)(?(4)\4)$!i', $line, $match)) {
				if (trim($match[1]) != '') {
					$type = $this->type_prefix[$match[1]];
				} elseif ($this->default_type != 'auto') {
					$type = $this->default_type;
				} elseif ($match[4] == '"' || $match[4] == '\'') {
					$type = CONFIGMAN_TYPE_STRING;
				} else {
					$type = CONFIGMAN_TYPE_INTEGER;
				}
				
				// replace escaped characters (\n \r and \t)
				if ($match[4] == '"') {
					$match[5] = preg_replace(array('/(?<!\\\\)\\\\n/','/(?<!\\\\)\\\\r/','/(?<!\\\\)\\\\t/'), array("\n","\r","\t"), $match[5]);
					$match[5] = str_replace('\\\\', '\\', $match[5]);
				}

				$var[$match[2]][][$type] = array(	'value' => $match[5],
													'comment' => $comment,
													'assoc' => (empty($match[3]) ? null : substr($match[3], 1)));
				$comment = "";
				unset($match);
				continue;
			}
			// section tag (comment)
			if (preg_match('!^\[('.$this->regex_section.')\]!', $line, $match)) {
				if (trim($match[1]) != '') {
					// set previous section vars
					$this->_set_param_from_config($var, $section);
					$var = array();
					$section = trim($match[1]);
				} else {
					$this->_error("Incorrect section tag on line $line_count");
				}
				unset($match);
				continue;
			}
			// unrecognized config syntax
			if ($this->debug) $this->_debug("$func_name: Unrecognised syntax on line $line_count");
		}
		$this->_set_param_from_config($var, $section);
	}

	/**
	* Set params from parsed config
	*
	* Sets parameters for 1 section
	*
	* @param	array	$param		parameters for 1 section passed from _process_config
	* @param	string	$section	section name to enter parameter in
	* @return	bool				true
	* @access	private
	* @see		_process_config
	*/
	function _set_param_from_config($param, $section)
	{
		foreach ($param as $var => $value) {
			// array?
			if (count($value) > 1) {
				// it is an array
				$cur_val = array();
				$cur_comment = '';
				// loop through the array
				foreach ($value as $arr_element) {
					// grab the type
					$cur_type = key($arr_element);
					if (trim($arr_element[$cur_type]['comment']) != '') {
						if ($cur_comment != '') {
							$cur_comment .= "------------------------------\n";
						}
						$cur_comment .= $arr_element[$cur_type]['comment'];
					}
					// is it associative?
					if (!is_null($arr_element[$cur_type]['assoc'])) {
						// store key
						$cur_key = (string)$arr_element[$cur_type]['assoc'];
						// add value
						$cur_val[$cur_key] = $this->_cast_type($arr_element[$cur_type]['value'], $cur_type);
					} else {
						// not associative
						$cur_val[] = $this->_cast_type($arr_element[$cur_type]['value'], $cur_type);
					}
				}
			} else {
				// not array or single assoc array
				$cur_type = key($value[0]);
				$cur_val = $this->_cast_type($value[0][key($value[0])]['value'], $cur_type);
				$cur_comment = $value[0][key($value[0])]['comment'];
				$cur_key = $value[0][key($value[0])]['assoc'];
				if (!is_null($cur_key)) {
					$cur_val = array("$cur_key" => $cur_val);
				}
			}

			$this->set_param($var, $cur_val, $cur_comment, $section);
		}
		return true;
	}

}

?>