Login   Register  
PHP Classes
elePHPant
Icontem

File: class.config_webedit.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_webedit.php  >  Download  
File: class.config_webedit.php
Role: ???
Content type: text/plain
Description: Class - config web editor
Class: Config Manager
Sorry, no longer supported
Author: By
Last change:
Date: 2002-04-09 02:24
Size: 13,417 bytes
 

Contents

Class file image Download
<?php
/* vim: set ai tabstop=4: */
// $Date: 2002/04/09 01:29:38 $
// $Revision: 1.4 $
// +----------------------------------------------------------------------+
// | 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 web editor class
*
* Use this class to modify your config files through a web form
* This is an extension to the base config class.
*
* @author   Keyvan Minoukadeh <keyvan@k1m.com>
* @version  0.1.2
*/
class config_webedit extends config_base
{
	/**
	* show section names
	*/
	var $show_sections			= true;

	/**
	* show string quotes
	*/
	var $show_quotes			= true;

	/**
	* show static existing value
	*/
	var $show_existing			= true;

	/**
	* show comments
	*/
	var $show_comments			= true;
	
	/**
	* show types
	*/
	var $show_types				= true;

	/**
	* allow type change ($this->show_types must be true)
	*/
	var $allow_type_change		= false;

	// If you've made a stylesheet for your page,
	// enter name of each CSS class to use for each
	// element.

	/**
	* CSS class names
	*
	* main table class - <table>
	* type drop down class - <select>
	* type text - <div>
	* var name class - <div>
	* value input class - <input type='text'...>
	* error text class - <span>
	* existing static value - <span>
	* comment class - <div>
	* section name class - <td>
	* submit button class - <input type='submit'...>
	* reset button class - <input type='reset'...>
	*/
	var $css					= array('main'		=> 'configmanMain',
										'type'		=> 'configmanType',
										'type_text'	=> 'configmanTypeText',
										'var'		=> 'configmanVar',
										'value'		=> 'configmanValue',
										'error'		=> 'configmanError',
										'existing'	=> 'configmanExisting',
										'comment'	=> 'configmanComment',
										'section'	=> 'configmanSection',
										'submit'	=> 'configmanSubmit',
										'reset'		=> 'configmanReset');

	/**
	* Comment line separator
	*/
	var $comment_separator		= "<br />";

	/**
	* Confirmation text to appear when the 'Revert back' button is clicked
	*
	* Note: this will be entered in a javascript function surrounded by single quotes,
	*       so make sure you escape properly
	*/
	var $reset_confirm_text		= "This will revert all values back, any changes you\\'ve made will be lost.  Are you sure you want to continue?";

	/**
	* row color 1
	*/
	var $row_color_1			= "#DAEBFC";

	/**
	* row color 2
	*/
	var $row_color_2			= "#C1DDF9";

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


	/**
	* Constructor
	*
	* @param	string	$config				config file to use
	*/
	function config_webedit($config)
	{
		// run base constructor
		$this->config_base($config);
	}

	/**
	* Build form
	*
	* @param	string	$section		Section to display (empty string: all sections)
	* @param	string	$post_action	URL to post to (<form action=''...>) default: current page
	* @return	string					string containing the form
	*/
	function build_form($section='', $post_action=null)
	{
		$func_name = 'build_form';

		clearstatcache();

		if (is_null($post_action)) {			
			if (function_exists('version_compare') && version_compare(phpversion(), '4.1.0', '>=')) {
				$post_action = $_SERVER['PHP_SELF'];
			} else {
				$post_action = $GLOBALS['PHP_SELF'];
			}
		}

		if ($this->is_file_valid()) {
			$config_size = filesize($this->config);
			$config_mtime = filemtime($this->config);
			$config = file($this->config);
		} else {
			$this->_error("Config file does not exist, is unreadable or above max size limit");
			return false;
		}

		if (!empty($section)) {
			if ($this->debug) $this->_debug("$func_name: Building web form for config section '$section'");
			$this_section = false;
		} else {
			if ($this->debug) $this->_debug("$func_name: Building web form for all config sections");
			$this_section = true;
		}

		$diff_color = true;
		$form = array();
		$cur_comment = array();
		$form[] = "<form method=\"post\" name=\"CONFIGMAN_FORM\" action=\"{$post_action}\">";
		$form[] = "<input type=\"hidden\" name=\"CONFIGMAN_INFO[action]\" value=\"modify\" />";
		$form[] = "<input type=\"hidden\" name=\"CONFIGMAN_INFO[size]\" value=\"{$config_size}\" />";
		$form[] = "<input type=\"hidden\" name=\"CONFIGMAN_INFO[mtime]\" value=\"{$config_mtime}\" />";
		$form[] = "<table border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"{$this->css['main']}\">";

		foreach ($config as $num => $line) {
			$line = trim($line);

			// match comment
			if ($this_section && $this->show_comments && preg_match('!^'.preg_quote($this->comment).'(.*)$!', $line, $match)) {
				if (trim($match[1]) != '') {
					$cur_comment[] = trim($match[1]);
				}
				continue;
			}

			// match var
			if ($this_section && preg_match('!^'.$this->regex_type.'?('.$this->regex_var.')(\.'.$this->regex_assoc.')?\s*'.
							preg_quote($this->separator).'\s*(.*)$!i', $line, $match)) {

				// decide which bg color to use
				$diff_color = ($diff_color ? false : true);
				if ($diff_color) {
					$bg_color = $this->row_color_1;
				} else {
					$bg_color = $this->row_color_2;
				}

				// add comment row
				if ($this->show_comments && count($cur_comment)) {
					$form[] = "<tr bgcolor=\"{$bg_color}\">\n\t<td><div class=\"{$this->css['comment']}\">".implode($this->comment_separator, $cur_comment)."</div></td>\n</tr>";
					// reset comments captured
					$cur_comment = array();
				}

				// start row
				$form[] = "<tr bgcolor=\"{$bg_color}\">\n\t<td>";
				$form[] = "\t<table border=\"0\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">";
				$form[] = "\t<tr>";

				// add var name
				$form[] = "\t\t<td width=\"25%\" valign=\"top\"><div class=\"{$this->css['var']}\">{$match[2]}{$match[3]}</div></td>";

				// add drop down type
				if (!empty($match[1])) {
					if ($this->show_types && $this->allow_type_change) {
						$form[] = "\t\t<td width=\"10%\" align=\"center\" valign=\"top\"><select name=\"CONFIGMAN[{$num}][type]\" class=\"{$this->css['type']}\">";
						foreach ($this->type_prefix as $prefix => $type) {
							if ($prefix == $match[1]) {
								$form[] = "\t\t\t<option value=\"{$prefix}\" selected=\"selected\">{$type}</option>";
							} else {
								$form[] = "\t\t\t<option value=\"{$prefix}\">{$type}</option>";
							}
						}
						$form[] = "\t\t</select></td>";

					// add type name
					} elseif ($this->show_types) {
						$form[] = "\t\t<td width=\"10%\" align=\"center\" valign=\"top\"><div class=\"{$this->css['type_text']}\">".
							"<input type=\"hidden\" name=\"CONFIGMAN[{$num}][type]\" value=\"{$match[1]}\" />".
							$this->type_prefix[$match[1]]."</div></td>";
					
					// empty cell
					} else {
						$form[] = "\t\t<td width=\"10%\">".
									"<input type=\"hidden\" name=\"CONFIGMAN[{$num}][type]\" value=\"{$match[1]}\" />".
									"&nbsp;</td>";
					}
				} else {
					$form[] = "\t\t<td width=\"10%\">&nbsp;</td>";
				}

				// valid quote usage?
				if (preg_match('!^(?'.'>(["\'])?)(.*)(?(1)\1)$!', $match[4], $value_match)) {
					$valid_value = true;
					$display_value = $value_match[2];
				} else {
					$valid_value = false;
					$display_value = $match[4];
				}

				// show quotes?
				if ($this->show_quotes && $valid_value) {
					$cur_quote = htmlspecialchars($value_match[1]);
				} else {
					$cur_quote = '';
				}
				
				// show static existing values
				if ($this->show_existing) {
					$cur_existing = htmlspecialchars($match[4]);
				} else {
					$cur_existing = '';
				}

				// add value input field
				$form[] = "\t\t<td width=\"65%\" valign=\"top\"><input type=\"text\" name=\"CONFIGMAN[{$num}][value]\" value=\"{$cur_quote}".
							htmlspecialchars($display_value)."{$cur_quote}\" class=\"{$this->css['value']}\" />&nbsp;".
							"<span class=\"{$this->css['existing']}\"> {$cur_existing}</span>";
				if (!$valid_value) {
					$form[] = "\t\t<br /><span class=\"{$this->css['error']}\">Invalid value (opening AND closing quotes required)</span>";
				}
				$form[] = "\t\t</td>";
				$form[] = "\t</tr></table>\n\t</td>\n</tr>";
				continue;
			}

			// match section
			if (preg_match('!^\[('.$this->regex_section.')\]!', $line, $match)) {
				$match[1] = trim($match[1]);
				if (empty($section) || ($match[1] === $section)) {
					$this_section = true;
					if ($this->show_sections) {
						$form[] = "<tr>\n\t<td>&nbsp;</td>\n</tr>";
						$form[] = "<tr>\n\t<td class=\"{$this->css['section']}\">{$match[1]}</td>\n</tr>";
					}
				} else {
					$this_section = false;
				}
				// reset any comments captured
				$cur_comment = array();
				continue;
			}
		}
		// submit and reset buttons
		$form[] = "<tr>\n\t<td>&nbsp;<br />".
					"<input type=\"submit\" name=\"submit\" value=\"Update!\" class=\"{$this->css['submit']}\" />".
					" &nbsp; &nbsp; &nbsp; ".
					"<input type=\"reset\" name=\"reset\" value=\"Revert back\" class=\"{$this->css['reset']}\" ".
					"onclick=\"return confirm('{$this->reset_confirm_text}')\" />".
					"</td>\n</tr>";
		$form[] = "</table>\n</form>";
		return implode("\n", $form);
	}

	/**
	* Update config
	*
	* @param	array	$configman			Result of form post ($CONFIGMAN array)
	* @param	array	$configman_info		Result of form post ($CONFIGMAN_INFO array)
	* @return	bool						true on success, false otherwise
	*/
	function update($configman, $configman_info)
	{
		$func_name = 'update';

		if (empty($configman_info['action']) || empty($configman_info['size']) || empty($configman_info['mtime'])) {
			if ($this->debug) $this->_debug("$func_name: Required info not included in array");
			return false;
		}

		// get rid of magic crap
		$this->strip_magic_slashes($configman);
		$this->strip_magic_slashes($configman_info);

		if ($this->is_file_valid() && is_writable($this->config)) {
			// check action
			if ($configman_info['action'] !== 'modify') {
				if ($this->debug) $this->_debug("$func_name: Incorrect action");
				return false;
			}
			// check file size
			if ((int)$configman_info['size'] !== filesize($this->config)) {
				if ($this->debug) $this->_debug("$func_name: Config file sizes do not match");
				return false;
			}
			// check modification time
			if ((int)$configman_info['mtime'] !== filemtime($this->config)) {
				if ($this->debug) $this->_debug("$func_name: Config file has already been modified (modification time mismatch)");
				return false;
			}
			$config = file($this->config);
		} else {
			$this->_error("Config file does not exist or is unreadable or unwritable");
			return false;
		}

		$new = array();

		foreach ($config as $num => $line) {
			$line = rtrim($line);

			if (!isset($configman[$num])) {
				$new[] = $line;
				continue;
			}
			if (preg_match('!^(\s*)'.$this->regex_type.'?('.$this->regex_var.')(\.'.$this->regex_assoc.')?(\s*'.
					preg_quote($this->separator).'\s*)(.*)$!i', $line, $match)) {
				// set new type
				if (isset($configman[$num]['type'])) {
					$new_type = $configman[$num]['type'];
				} else {
					$new_type = $match[2];
				}
				// set new value
				$new_val = $configman[$num]['value'];
				$new[] = $match[1].$new_type.$match[3].$match[4].$match[5].$new_val;
				continue;
			}
			$new[] = $line;		
		}

		$fp = @fopen($this->config, "w");
		if (!$fp) {
			if ($this->debug) $this->_debug("$func_name: Could not create/access file");
			return false;
		} else {
			// exclusive lock
			flock($fp, 2);
			$result = @fwrite($fp, implode("\n", $new));
			// release lock
			flock($fp, 3);
			fclose($fp);
			if (!$result) {
				if ($this->debug) $this->_debug("$func_name: Could not write to file");
				return false;
			} else {
				if ($this->debug) $this->_debug("$func_name: Config file written");
				// touch file with modification time of main config file (used for comparison)
				touch($this->config);
				return true;
			}
		}
		// should not reach here
		return false;
	}


}

?>