[Customisation Database Commits] r909 [2/2] - in /trunk/titania: includes/library/automod/ includes/tools/ includes/tools/automod/ store/phpbb_packages/ store/phpbb_packages/extracted/

Nathan Guse exreaction at phpbb.com
Sat Mar 27 17:24:58 GMT 2010


Added: trunk/titania/includes/library/automod/editor.php
==============================================================================
*** trunk/titania/includes/library/automod/editor.php (added)
--- trunk/titania/includes/library/automod/editor.php Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,1278 ----
+ <?php
+ /**
+ *
+ * @package automod
+ * @version $Id$
+ * @copyright (c) 2008 phpBB Group
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
+ *
+ */
+ 
+ /**
+ */
+ if (!defined('IN_PHPBB'))
+ {
+ 	exit;
+ }
+ 
+ // Constant Defines for actions
+ //define('AFTER',		1);
+ //define('BEFORE',	2);
+ 
+ /**
+ * Editor Class
+ * Runs through file sequential, ie new finds must come after previous finds
+ * Handles placing the files after being edited
+ * @package automod
+ * @todo: implement some string checkin, way too much can go wild here
+ */
+ class editor
+ {
+ 	/**
+ 	* Holds contents of file
+ 	*/
+ 	var $file_contents = '';
+ 
+ 	/**
+ 	* Holds the filename of the currently open file
+ 	*/
+ 	var $open_filename = '';
+ 
+ 	/**
+ 	* Full action array with complete finds
+ 	*/
+ 	var $mod_actions = array();
+ 
+ 	/**
+ 	* One of the three constants defined in functions_mods.php
+ 	*/
+ 	var $write_method = 0;
+ 
+ 	/**
+ 	* Keeps finds sequential, plus loop optimization
+ 	*/
+ 	var $start_index = 0;
+ 
+ 	/*
+ 	* Keeps inline find sequential
+ 	*/
+ 	var $last_string_offset = 0;
+ 
+ 	/*
+ 	* Only apply string offset to the line to which it belongs
+ 	*/
+ 	var $last_inline_ary_offset = 0;
+ 
+ 	/**
+ 	* Time when MOD was installed
+ 	*/
+ 	var $install_time = 0;
+ 
+ 	/**
+ 	* Only used when board has templates stored in the database
+ 	*/ 
+ 	var $template_id = 0;
+ 
+ 	/**
+ 	* Store the  current action & most recent action to aid the uninstall building process
+ 	*/
+ 	var $last_action = array();
+ 	var $curr_action = array();
+ 
+ 	/**
+ 	* Constructor method
+ 	* This is not called directly in AutoMOD
+ 	*/
+ 	function editor()
+ 	{
+ 
+ 	}
+ 
+ 	/**
+ 	* Make all line endings the same - UNIX
+ 	*/
+ 	function normalize($string)
+ 	{
+ 		$string = str_replace(array("\r\n", "\r"), "\n", $string);
+ 		return $string;
+ 	}
+ 
+ 	/**
+ 	* Open a file with IO, for processing
+ 	*
+ 	* @param string $filename - relative path from phpBB Root to the file to open
+ 	* 		e.g. viewtopic.php, styles/prosilver/templates/index_body.html
+ 	*/
+ 	function open_file($filename, $backup_path)
+ 	{
+ 		global $phpbb_root_path, $db, $user;
+ 
+ 		$this->file_contents = @file($phpbb_root_path . $filename);
+ 
+ 		if ($this->file_contents === false)
+ 		{
+ 			return $user->lang['FILE_EMPTY'];
+ 		}
+ 
+ 		$this->file_contents = $this->normalize($this->file_contents);
+ 
+ 		// Check for file contents in the database if this is a template file
+ 		// this will overwrite the @file call if it exists in the DB. 
+ 		if (strpos($filename, 'template/') !== false)
+ 		{
+ 			// grab template name and filename
+ 			preg_match('#styles/([a-z0-9_]+)/template/([a-z0-9_]+.[a-z]+)#i', $filename, $match);
+ 
+ 			$sql = 'SELECT d.template_data, d.template_id 
+ 				FROM ' . STYLES_TEMPLATE_DATA_TABLE . ' d, ' . STYLES_TEMPLATE_TABLE . " t
+ 				WHERE d.template_filename = '" . $db->sql_escape($match[2]) . "'
+ 					AND t.template_id = d.template_id
+ 					AND t.template_storedb = 1
+ 					AND t.template_name = '" . $db->sql_escape($match[1]) . "'";
+ 			$result = $db->sql_query($sql);
+ 
+ 			if ($row = $db->sql_fetchrow($result))
+ 			{
+ 				$this->file_contents = explode("\n", $this->normalize($row['template_data']));
+ 
+ 				// emulate the behavior of file()
+ 				$lines = sizeof($this->file_contents);
+ 				for ($i = 0; $i < $lines; $i++)
+ 				{
+ 					$this->file_contents[$i] .= "\n";
+ 				}
+ 
+ 				$this->template_id = $row['template_id'];
+ 			}
+ 			else
+ 			{
+ 				$this->template_id = 0;
+ 			}
+ 		}
+ 
+ 		/* 
+ 		* If the file does not exist, or is empty, die.
+ 		* Non existant files cannot be edited, and empty files will have no
+ 		* finds
+ 		*/
+ 		if (!sizeof($this->file_contents))
+ 		{
+ 			global $user;
+ 			trigger_error(sprintf($user->lang['MOD_OPEN_FILE_FAIL'], "$phpbb_root_path$filename"), E_USER_WARNING);
+ 		}
+ 
+ 		$this->start_index = 0;
+ 		$this->open_filename = $filename;
+ 
+ 		// Make a backup of this file
+ 		$this->backup_file($backup_path);
+ 	}
+ 
+ 	/**
+ 	* Checks if a find is present
+ 	* Keep in mind partial finds and multi-line finds
+ 	*
+ 	* @param string $find - string to find
+ 	* @return mixed : array with position information if $find is found; false otherwise
+ 	*/
+ 	function find($find)
+ 	{
+ 		$find_success = 0;
+ 
+ 		$find = $this->normalize($find);
+ 		$find_ary = explode("\n", $find);
+ 
+ 		$total_lines = sizeof($this->file_contents);
+ 		$find_lines = sizeof($find_ary);
+ 
+ 		$mode = array('', 'trim');
+ 
+ 		foreach ($mode as $function)
+ 		{
+ 			// we process the file sequentially ... so we keep track of indices
+ 			for ($i = $this->start_index; $i < $total_lines; $i++)
+ 			{
+ 				for ($j = 0; $j < $find_lines; $j++)
+ 				{
+ 					if ($function)
+ 					{
+ 						$find_ary[$j] = $function($find_ary[$j]);
+ 					}
+ 	
+ 					// if we've reached the EOF, the find failed.
+ 					if (!isset($this->file_contents[$i + $j]))
+ 					{
+ 						return false;
+ 					}
+ 	
+ 					if (!trim($find_ary[$j]))
+ 					{
+ 						// line is blank.  Assume we can find a blank line, and continue on
+ 						$find_success += 1;
+ 					}
+ 					// using $this->file_contents[$i + $j] to keep the array pointer where I want it
+ 					// if the first line of the find (index 0) is being looked at, $i + $j = $i.
+ 					// if $j is > 0, we look at the next line of the file being inspected
+ 					// hopefully, this is a decent performer.
+ 					else if (strpos($this->file_contents[$i + $j], $find_ary[$j]) !== false)
+ 					{
+ 						// we found this part of the find
+ 						$find_success += 1;
+ 					}
+ 					// we might have an increment operator, which requires a regular expression match
+ 					else if (strpos($find_ary[$j], '{%:') !== false)
+ 					{
+ 						$regex = preg_replace('#{%:(\d+)}#', '(\d+)', $find_ary[$j]);
+ 	
+ 						if (preg_match('#' . $regex . '#is', $this->file_contents[$i + $j]))
+ 						{
+ 							$find_success += 1;
+ 						}
+ 						else
+ 						{
+ 							$find_success = 0;
+ 						}
+ 					}
+ 					else
+ 					{
+ 						// the find failed.  Reset $find_success
+ 						$find_success = 0;
+ 	
+ 						// skip to next iteration of outer loop, that is, skip to the next line
+ 						break;
+ 					}
+ 	
+ 					if ($find_success == $find_lines)
+ 					{
+ 						// we found the proper number of lines
+ 						$this->start_index = $i;
+ 	
+ 						// return our array offsets
+ 						return array(
+ 							'start' => $i,
+ 							'end' => $i + $j,
+ 						);
+ 					}
+ 	
+ 				}
+ 			}
+ 		}
+ 
+ 		// if return has not been previously invoked, the find failed.
+ 		return false;
+ 	}
+ 
+ 	/**
+ 	* This function is used to determine when an edit has ended, so we know that 
+ 	* the current line will not be looked at again.  This fixes some former bugs.
+ 	*/
+ 	function close_edit()
+ 	{
+ 		$this->start_index++;
+ 		$this->last_action = array();
+ 		$this->last_string_offset = 0;
+ 	}
+ 
+ 	/*
+ 	* In-line analog to close_edit(), above.
+ 	* Advance the pointer one character
+ 	*/
+ 	function close_inline_edit()
+ 	{
+ 		$this->last_string_offset++;
+ 	}
+ 
+ 	/**
+ 	* Find a string within a given line
+ 	*
+ 	* @param string $find Complete find - narrows the scope of the inline search
+ 	* @param string $inline_find - the substring to find
+ 	* @param int $start_offset - the line number where $find starts
+ 	* @param int $end_offset - the line number where $find ends
+ 	*
+ 	* @return mixed array on success or false on failure of find
+ 	*/
+ 	function inline_find($find, $inline_find, $start_offset = false, $end_offset = false)
+ 	{
+ 		$find = $this->normalize($find);
+ 
+ 		if ($start_offset === false || $end_offset === false)
+ 		{
+ 			$offsets = $this->find($find);
+ 
+ 			if (!$offsets)
+ 			{
+ 				// the find failed, so no further action can occur.
+ 				return false;
+ 			}
+ 
+ 			$start_offset = $offsets['start'];
+ 			$end_offset = $offsets['end'];
+ 
+ 			unset($offsets);
+ 		}
+ 
+ 		// cast is required in case someone tries to find a number
+ 		// Often done in colspan="7" type inline operations
+ 		$inline_find = (string) $inline_find;
+ 
+ 		// similar method to find().  Just much more limited scope
+ 		for ($i = $start_offset; $i <= $end_offset; $i++)
+ 		{
+ 			if ($this->last_string_offset > 0 && ($this->last_inline_ary_offset == 0 || $this->last_inline_ary_offset == $i))
+ 			{
+ 				$string_offset = strpos(substr($this->file_contents[$i], $this->last_string_offset), $inline_find);
+ 
+ 				if ($string_offset !== false)
+ 				{
+ 					$string_offset += $this->last_string_offset;
+ 				}
+ 			}
+ 			else
+ 			{
+ 				$string_offset = strpos($this->file_contents[$i], $inline_find);
+ 			}
+ 
+ 			if ($string_offset !== false)
+ 			{
+ 				$this->last_string_offset = $string_offset;
+ 				$this->last_inline_ary_offset = $i;
+ 
+ 				// if we find something, return the line number, string offset, and find length
+ 				return array(
+ 					'array_offset'	=> $i,
+ 					'string_offset'	=> $string_offset,
+ 					'find_length'	=> strlen($inline_find),
+ 				);
+ 			}
+ 		}
+ 
+ 		// if the previous failed, trim() the find and try again
+ 		for ($i = $start_offset; $i <= $end_offset; $i++)
+ 		{
+ 			$inline_find = trim($inline_find);
+ 			if ($this->last_string_offset > 0 && ($this->last_inline_ary_offset == 0 || $this->last_inline_ary_offset == $i))
+ 			{
+ 				$string_offset = strpos(substr($this->file_contents[$i], $this->last_string_offset), $inline_find);
+ 
+ 				if ($string_offset !== false)
+ 				{
+ 					$string_offset += $this->last_string_offset;
+ 				}
+ 			}
+ 			else
+ 			{
+ 				$string_offset = strpos($this->file_contents[$i], $inline_find);
+ 			}
+ 
+ 			if ($string_offset !== false)
+ 			{
+ 				$this->last_string_offset = $string_offset;
+ 
+ 				// if we find something, return the line number, string offset, and find length
+ 				return array(
+ 					'array_offset'	=> $i,
+ 					'string_offset'	=> $string_offset,
+ 					'find_length'	=> strlen($inline_find),
+ 				);
+ 			}
+ 		}
+ 
+ 		return false;
+ 	}
+ 
+ 
+ 	/**
+ 	* Add a string to the file, BEFORE/AFTER the given find string
+ 	* @param string $find - Complete find - narrows the scope of the inline search
+ 	* @param string $add - The string to be added before or after $find
+ 	* @param string $pos - BEFORE or AFTER
+ 	* @param int $start_offset - First line in the FIND
+ 	* @param int $end_offset - Last line in the FIND
+ 	*
+ 	* @return bool success or failure of add
+ 	*/
+ 	function add_string($find, $add, $pos, $start_offset = false, $end_offset = false)
+ 	{
+ 		// this seems pretty simple...throughly test
+ 		$add = $this->normalize($add);
+ 
+ 		if ($start_offset === false || $end_offset === false)
+ 		{
+ 			$offsets = $this->find($find);
+ 
+ 			if (!$offsets)
+ 			{
+ 				// the find failed, so the add cannot occur.
+ 				return false;
+ 			}
+ 
+ 			$start_offset = $offsets['start'];
+ 			$end_offset = $offsets['end'];
+ 
+ 			unset($offsets);
+ 		}
+ 
+ 		$full_find = array();
+ 		for ($i = $start_offset; $i <= $end_offset; $i++)
+ 		{
+ 			$full_find[] = $this->file_contents[$i];
+ 		}
+ 
+ 		$full_find[0] = ltrim($full_find[0], "\n");
+ 		$full_find[sizeof($full_find) - 1] = rtrim($full_find[sizeof($full_find) - 1], "\n");
+ 
+ 		// make sure our new lines are correct
+ 		$add = "\n" . trim($add, "\n") . "\n";
+ 
+ 		if ($pos == 'AFTER')
+ 		{
+ 			$this->file_contents[$end_offset] = rtrim($this->file_contents[$end_offset], "\n") . $add;
+ 		}
+ 
+ 		if ($pos == 'BEFORE')
+ 		{
+ 			$this->file_contents[$start_offset] = $add . ltrim($this->file_contents[$start_offset], "\n");
+ 		}
+ 
+ 		$this->curr_action = func_get_args();
+ 		$this->build_uninstall(implode("", $full_find), NULL, strtolower($pos) . ' add', $add);
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Increment (or perform other mathematical operation) on the given wildcard
+ 	* Support multiple wildcards {%:1}, {%:2} etc...
+ 	* This method is a variation on the inline find and replace methods
+ 	*
+ 	* @param string $find - Complete find - contains $inline_find
+ 	* @param string $inline_find - contains tokens to be replaced
+ 	* @param string $operation - tokens to do some math
+ 	* @param int $start_offset - First line in the FIND
+ 	* @param int $end_offset - Last line in the FIND
+ 	*
+ 	* @return bool
+ 	*/
+ 	function inc_string($find, $inline_find, $operation, $start_offset = false, $end_offset = false)
+ 	{
+ 		if ($start_offset === false || $end_offset === false)
+ 		{
+ 			$offsets = $this->find($find);
+ 
+ 			if (!$offsets)
+ 			{
+ 				// the find failed, so the add cannot occur.
+ 				return false;
+ 			}
+ 
+ 			$start_offset = $offsets['start'];
+ 			$end_offset = $offsets['end'];
+ 
+ 			unset($offsets);
+ 		}
+ 
+ 		// $inline_find is optional
+ 		if (!$inline_find)
+ 		{
+ 			$inline_find = $find;
+ 		}
+ 
+ 		// parse the MODX operator
+ 		// let's explain this regex a bit:
+ 		// - literal %: followed by a number.  optional space
+ 		// - plus or minus operator. optional space
+ 		// - number to increment by.  optional
+ 		preg_match('#{%:(\d+)} ?([+-]) ?(\d*)#', $operation, $action);
+ 		// make sure there is actually a number here
+ 		$action[2] = (isset($action[2])) ? $action[2] : '+';
+ 		$action[3] = (isset($action[3])) ? $action[3] : 1;
+ 
+ 		$matches = 0;
+ 		// $start_offset _should_ equal $end_offset, but we allow other cases
+ 		for ($i = $start_offset; $i <= $end_offset; $i++)
+ 		{
+ 			// This is intended.  We turn the MODX token into something PCRE can
+ 			// understand.
+ 			$inline_find = preg_replace('#{%:(\d+)}#', '(\d+)', $inline_find);
+ 
+ 			if (preg_match('#' . $inline_find . '#is', $this->file_contents[$i], $find_contents))
+ 			{
+ 				// now we can do some math
+ 				// $find_contents[1] is the original number, $action[2] is the operator
+ 				$new_number = eval('return ' . ((int) $find_contents[1]) . $action[2] . ((int) $action[3]) . ';');
+ 
+ 				// now we replace
+ 				$new_contents = str_replace($find_contents[1], $new_number, $find_contents[0]);
+ 
+ 				$this->file_contents[$i] = str_replace($find_contents[0], $new_contents, $this->file_contents[$i]);
+ 
+ 				$matches += 1;
+ 			}
+ 		}
+ 
+ 		if (!$matches)
+ 		{
+ 			return false;
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 
+ 	/**
+ 	* Replace a string - replaces the entirety of $find with $replace
+ 	*
+ 	* @param string $find - Complete find - contains $inline_find
+ 	* @param string $replace - Will replace $find
+ 	* @param int $start_offset - First line in the FIND
+ 	* @param int $end_offset - Last line in the FIND
+ 	*
+ 	* @return bool
+ 	*/
+ 	function replace_string($find, $replace, $start_offset = false, $end_offset = false)
+ 	{
+ 		$replace = $this->normalize($replace);
+ 
+ 		if ($start_offset === false || $end_offset === false)
+ 		{
+ 			$offsets = $this->find($find);
+ 
+ 			if (!$offsets)
+ 			{
+ 				return false;
+ 			}
+ 
+ 			$start_offset = $offsets['start'];
+ 			$end_offset = $offsets['end'];
+ 			unset($offsets);
+ 		}
+ 
+ 		// remove each line from the file, but add it to $full_find
+ 		$full_find = array();
+ 		for ($i = $start_offset; $i <= $end_offset; $i++)
+ 		{
+ 			$full_find[] = $this->file_contents[$i];
+ 			$this->file_contents[$i] = '';
+ 		}
+ 
+ 		$this->file_contents[$start_offset] = rtrim($replace) . "\n";
+ 
+ 		$this->curr_action = func_get_args();
+ 		$this->build_uninstall(implode("", $full_find), NULL, 'replace-with', $replace);
+ 
+ 		return true;
+ 	}
+ 
+ 	/*
+ 	* Replace $inline_find with $inline_replace
+ 	* Arguments are very similar to inline_add, below
+ 	*/
+ 	function inline_replace($find, $inline_find, $inline_replace, $array_offset = false, $string_offset = false, $length = false)
+ 	{
+ 		if ($string_offset === false || $length === false)
+ 		{
+ 			// look for the inline find
+ 			$inline_offsets = $this->inline_find($find, $inline_find);
+ 
+ 			if (!$inline_offsets)
+ 			{
+ 				return false;
+ 			}
+ 
+ 			$array_offset = $inline_offsets['array_offset'];
+ 			$string_offset = $inline_offsets['string_offset'];
+ 			$length = $inline_offsets['find_length'];
+ 			unset($inline_offsets);
+ 		}
+ 
+ 		$this->file_contents[$array_offset] = substr_replace($this->file_contents[$array_offset], $inline_replace, $string_offset, $length);
+ 
+ 		$this->last_string_offset += strlen($inline_replace) - 1;
+ 
+ 		$this->curr_action = func_get_args();
+ 
+ 		// This isn't a full find, but it is the closest we can get
+ 		$this->build_uninstall($this->file_contents[$array_offset], $inline_find, 'in-line-replace', $inline_replace);
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Adds a string inline before or after a given find
+ 	*
+ 	* @param string $find Complete find - narrows the scope of the inline search
+ 	* @param string $inline_find - the string to add before or after
+ 	* @param string $inline_add - added before or after $inline_find
+ 	* @param string $pos - 'BEFORE' or 'AFTER'
+ 	* @param int $array_offset - line number where $inline_find may be found (optional)
+ 	* @param int $string_offset - location within the line where $inline_find begins (optional)
+ 	* @param int $length - essentially strlen($inline_find) (optional)
+ 	*
+ 	* @return bool success or failure of action
+ 	*/
+ 	function inline_add($find, $inline_find, $inline_add, $pos, $array_offset = false, $string_offset = false, $length = false)
+ 	{
+ 		if ($string_offset === false || $length === false)
+ 		{
+ 			// look for the inline find
+ 			$inline_offsets = $this->inline_find($find, $inline_find);
+ 
+ 			if (!$inline_offsets)
+ 			{
+ 				return false;
+ 			}
+ 
+ 			$array_offset = $inline_offsets['array_offset'];
+ 			$string_offset = $inline_offsets['string_offset'];
+ 			$length = $inline_offsets['find_length'];
+ 			unset($inline_offsets);
+ 		}
+ 
+ 		if ($string_offset + $length > strlen($this->file_contents[$array_offset]))
+ 		{
+ 			// we have an invalid string offset.  rats.
+ 			return false;
+ 		}
+ 
+ 		if ($pos == 'AFTER')
+ 		{
+ 			$this->file_contents[$array_offset] = substr_replace($this->file_contents[$array_offset], $inline_add, $string_offset + $length, 0);
+ 			$this->last_string_offset += strlen($inline_add) + $length - 1;
+ 		}
+ 		else if ($pos == 'BEFORE')
+ 		{
+ 			$this->file_contents[$array_offset] = substr_replace($this->file_contents[$array_offset], $inline_add, $string_offset, 0);
+ 			$this->last_string_offset += $length;
+ 		}
+ 
+ 		$this->curr_action = func_get_args();
+ 
+ 		$this->build_uninstall($this->file_contents[$array_offset], $inline_find, 'in-line-' . strtolower($pos) . '-add', $inline_add);
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Function to build full edits such that uninstall will work more often
+ 	* 
+ 	* @param $find - The largest find we can put together -- sometimes this
+ 	* 		comes from the file itself, other times from the MODX file
+ 	* @param $inline_find - Subset of $find or NULL
+ 	* @param $action_type - Name of the MODX action being taken
+ 	* @param $action - The code which is being inserted into the file
+ 	* @return void
+ 	*/
+ 	function build_uninstall($find, $inline_find, $action_type, $action)
+ 	{
+ 		$find = trim($find);
+ 		$inline_find = trim($inline_find);
+ 		$action = trim($action);
+ 
+ 		/*
+ 		* This if statement finds out if we are in the special case where 
+ 		* a MOD specifies a before action and an after action on the same
+ 		* find.  If this is the case, the uninstaller must see a replace
+ 		* rather than an add
+ 		*/
+ 		if (!empty($this->last_action) && $this->last_action[0] == $this->curr_action[0] &&
+ 			(($this->last_action[2] == 'AFTER' && $this->curr_action[2] == 'BEFORE') 
+ 			|| ($this->last_action[2] == 'BEFORE' && $this->curr_action[2] == 'AFTER')))
+ 		{
+ 			$last_action_index = sizeof($this->mod_actions[$this->open_filename]) - 1;
+ 			unset($this->mod_actions[$this->open_filename][$last_action_index]);
+ 
+ 			// Re-index the array to start at zero and go sequentially
+ 			$this->mod_actions[$this->open_filename] = array_merge($this->mod_actions[$this->open_filename]);
+ 
+ 			$action_type = 'REPLACE';
+ 
+ 			// Remove the add from the find -- this is an effect of the way the
+ 			// add method works, putting the new lines in the same array element
+ 			// as the find
+ 			if (!empty($this->last_action))
+ 			{
+ 				$find = str_replace(trim($this->last_action[1]), '', $find);
+ 			}
+ 
+ 			if ($this->last_action[2] == 'AFTER')
+ 			{
+ 				$action = $this->curr_action[1] . "\n" . $this->curr_action[0] . "\n" . $this->last_action[1];
+ 			}
+ 			else // implicit if ($this->last_action[2] == 'BEFORE')
+ 			{
+ 				$action = $this->last_action[1] . "\n" . $this->curr_action[0] . "\n" . $this->curr_action[1];
+ 			}
+ 		}
+ 
+ 		// Build another complex array of MOD Actions
+ 		// This approach is rather memory-intensive ... it might behoove us
+ 		// to think of something else
+ 		if (!$inline_find)
+ 		{
+ 			$this->mod_actions[$this->open_filename][] = array(
+ 				$find => array(
+ 					$action_type => $action,
+ 				)
+ 			);
+ 		}
+ 		else
+ 		{
+ 			$this->mod_actions[$this->open_filename][] = array(
+ 				$find => array(
+ 					'in-line-edit'	=> array(
+ 						$inline_find	=> array(
+ 							$action_type	=> array($action),
+ 						),
+ 					),
+ 				),
+ 			);
+ 		}
+ 
+ 		$this->last_action = $this->curr_action;
+ 	}
+ 
+ 	function clear_actions()
+ 	{
+ 		// free some memory
+ 		$this->mod_actions = array();
+ 	}
+ }
+ 
+ /**
+ * @package automod
+ * class editor_direct will alter files by using the local file access functions 
+ * such as fopen and fwrite.  This is typically only useful in Windows environments
+ * due to permissions settings.
+ */
+ class editor_direct extends editor
+ {
+ 	function editor_direct()
+ 	{
+ 		$this->write_method = WRITE_DIRECT;
+ 		$this->install_time = time();
+ 	}
+ 
+ 	/**
+ 	* Moves files or complete directories
+ 	*
+ 	* @param $from string Can be a file or a directory. Will move either the file or all files within the directory
+ 	* @param $to string Where to move the file(s) to. If not specified then will get moved to the root folder
+ 	* @param $strip Used for FTP only
+ 	* @return mixed: Bool true on success, error string on failure, NULL if no action was taken
+ 	* 
+ 	* NOTE: function should preferably not return in case of failure on only one file.  
+ 	* 	The current method makes error handling difficult 
+ 	*/
+ 	function copy_content($from, $to = '', $strip = '')
+ 	{
+ 		global $phpbb_root_path, $user, $config;
+ 
+ 		if (strpos($from, $phpbb_root_path) !== 0)
+ 		{
+ 			$from = $phpbb_root_path . $from;
+ 		}
+ 
+ 		// When installing a MODX 1.2.0 MOD, this happens once in a long while.
+ 		// Not sure why yet.
+ 		if (is_array($to))
+ 		{
+ 			return NULL;
+ 		}
+ 
+ 		if (strpos($to, $phpbb_root_path) !== 0)
+ 		{
+ 			$to = $phpbb_root_path . $to;
+ 		}
+ 
+ 		$files = array();
+ 		if (is_dir($from))
+ 		{
+ 			// get all of the files within the directory
+ 			$files = find_files($from, '.*');
+ 		}
+ 		else if (is_file($from))
+ 		{
+ 			$files = array($from);
+ 		}
+ 
+ 		if (empty($files))
+ 		{
+ 			return false;
+ 		}
+ 
+ 		// Look at the last character of $to and compare it to '/'
+ 		if ($to[strlen($to) - 1] == '/')
+ 		{
+ 			$dirname_check = $to;
+ 		}
+ 		else
+ 		{
+ 			$dirname_check = dirname($to);
+ 		}
+ 
+ 		if (!is_dir($dirname_check))
+ 		{
+ 			if ($this->recursive_mkdir($dirname_check) === false)
+ 			{
+ 				return sprintf($user->lang['MODS_MKDIR_FAILURE'], $dirname_check);
+ 			}
+ 		}
+ 
+ 		foreach ($files as $file)
+ 		{
+ 			if (is_dir($to))
+ 			{
+ 				$dest = str_replace($from, $to, $file);
+ 
+ 				if (!file_exists($dest))
+ 				{
+ 					$this->recursive_mkdir(dirname($dest));
+ 				}
+ 			}
+ 			else
+ 			{
+ 				$dest = $to;
+ 			}
+ 
+ 			if (!@copy($file, $dest))
+ 			{
+ 				return sprintf($user->lang['MODS_COPY_FAILURE'], $dest);
+ 			}
+ 			@chmod($dest, octdec($config['am_file_perms']));
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 	function close_file($new_filename)
+ 	{
+ 		global $phpbb_root_path, $config, $mod_installed, $mod_uninstalled, $force_install;
+ 		global $db, $user;
+ 
+ 		if (!is_dir($new_filename) && !file_exists(dirname($new_filename)))
+ 		{
+ 			if ($this->recursive_mkdir(dirname($new_filename)) === false)
+ 			{
+ 				return sprintf($user->lang['MODS_MKDIR_FAILED'], dirname($new_filename));
+ 			}
+ 		}
+ 
+ 		$file_contents = implode('', $this->file_contents);
+ 
+ 		if (file_exists($new_filename) && !is_writable($new_filename))
+ 		{
+ 			return sprintf($user->lang['WRITE_DIRECT_FAIL'], $new_filename);
+ 		}
+ 
+ 		if ($this->template_id && ($mod_installed || $mod_uninstalled || $force_install))
+ 		{
+ 			update_database_template($new_filename, $this->template_id, $file_contents, $this->install_time);
+ 		}
+ 
+ 		// If we are not looking at a file stored in the database, use local file functions
+ 		$fr = @fopen($new_filename, 'wb');
+ 		$length_written = @fwrite($fr, $file_contents);
+ 		@chmod($new_filename, octdec($config['am_file_perms']));
+ 
+ 		// This appears to be correct even with multibyte encodings.  strlen and 
+ 		// fwrite both return the number of bytes written, not the number of chars
+ 		if ($length_written < strlen($file_contents))
+ 		{
+ 			return sprintf($user->lang['WRITE_DIRECT_TOO_SHORT'], $new_filename);
+ 		}
+ 
+ 		if (!@fclose($fr))
+ 		{
+ 			return sprintf($user->lang['WRITE_DIRECT_FAIL'], $new_filename);			
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Creates a backup of the currently open file before AutoMOD makes any changes
+ 	*/
+ 	function backup_file($backup_dir)
+ 	{
+ 		if (!$backup_dir)
+ 		{
+ 			return;
+ 		}
+ 
+ 		return $this->close_file($backup_dir . $this->open_filename);
+ 	}
+ 
+ 	/**
+ 	* @author Michal Nazarewicz (from the php manual)
+ 	* Creates all non-existant directories in a path
+ 	* @param $path - path to create
+ 	* @param $mode - CHMOD the new dir to these permissions
+ 	* @return bool
+ 	*/
+ 	function recursive_mkdir($path, $mode = false)
+ 	{
+ 		if (!$mode)
+ 		{
+ 			global $config;
+ 			$mode = octdec($config['am_dir_perms']);
+ 		}
+ 
+ 		$dirs = explode('/', $path);
+ 		$count = sizeof($dirs);
+ 		$path = '.';
+ 		for ($i = 0; $i < $count; $i++)
+ 		{
+ 			$path .= '/' . $dirs[$i];
+ 
+ 			if (!is_dir($path))
+ 			{
+ 				@mkdir($path, $mode);
+ 				@chmod($path, $mode);
+ 
+ 				if (!is_dir($path))
+ 				{
+ 					return false;
+ 				}
+ 			}
+ 		}
+ 		return true;
+ 	}
+ 
+ 	function commit_changes($source, $destination)
+ 	{
+ 		return $this->copy_content($source, $destination, $source);
+ 	}
+ 
+ 	function commit_changes_final($source, $destination)
+ 	{
+ 		return NULL;
+ 	}
+ 
+ 	function create_edited_root($dir)
+ 	{
+ 		return $this->recursive_mkdir($dir);
+ 	}
+ }
+ 
+ class editor_ftp extends editor
+ {
+ 	var $transfer;
+ 
+ 	function editor_ftp()
+ 	{
+ 		global $config, $user;
+ 
+ 		$this->write_method = WRITE_FTP;
+ 		$this->install_time = time();
+ 
+ 		if (!class_exists('transfer'))
+ 		{
+ 			global $phpbb_root_path, $phpEx;
+ 			include($phpbb_root_path . 'includes/functions_transfer.' . $phpEx);
+ 		}
+ 
+ 		$this->transfer = new $config['ftp_method']($config['ftp_host'], $config['ftp_username'], request_var('password', ''), $config['ftp_root_path'], $config['ftp_port'], $config['ftp_timeout']);
+ 		$error = $this->transfer->open_session();
+ 
+ 		// Use the permissions settings specified in the AutoMOD configuration
+ 		$this->transfer->dir_perms = octdec($config['am_dir_perms']);
+ 		$this->transfer->file_perms = octdec($config['am_file_perms']);
+ 
+ 		if (is_string($error))
+ 		{
+ 			// FTP login failed
+ 			trigger_error(sprintf($user->lang['MODS_FTP_CONNECT_FAILURE'], $user->lang[$error]), E_USER_ERROR);
+ 		}
+ 	}
+ 
+ 	/**
+ 	* Moves files or complete directories
+ 	*
+ 	* @param $from string Can be a file or a directory. Will move either the file or all files within the directory
+ 	* @param $to string Where to move the file(s) to. If not specified then will get moved to the root folder
+ 	* @param $strip Used for FTP only
+ 	* @return mixed: Bool true on success, error string on failure, NULL if no action was taken
+ 	* 
+ 	* NOTE: function should preferably not return in case of failure on only one file.  
+ 	* 	The current method makes error handling difficult 
+ 	*/
+ 	function copy_content($from, $to = '', $strip = '')
+ 	{
+ 		global $phpbb_root_path, $user;
+ 
+ 		if (strpos($from, $phpbb_root_path) !== 0)
+ 		{
+ 			$from = $phpbb_root_path . $from;
+ 		}
+ 
+ 		// When installing a MODX 1.2.0 MOD, this happens once in a long while.
+ 		// Not sure why yet.
+ 		if (is_array($to))
+ 		{
+ 			return NULL;
+ 		}
+ 
+ 		if (strpos($to, $phpbb_root_path) !== 0)
+ 		{
+ 			$to = $phpbb_root_path . $to;
+ 		}
+ 
+ 		$files = array();
+ 		if (is_dir($from))
+ 		{
+ 			// get all of the files within the directory
+ 			$files = find_files($from, '.*');
+ 		}
+ 		else if (is_file($from))
+ 		{
+ 			$files = array($from);
+ 		}
+ 
+ 		if (empty($files))
+ 		{
+ 			return false;
+ 		}
+ 
+ 		// ftp
+ 		foreach ($files as $file)
+ 		{
+ 			if (is_dir($to))
+ 			{
+ 				$to_file = str_replace(array($phpbb_root_path, $strip), '', $file);
+ 			}
+ 			else
+ 			{
+ 				$to_file = str_replace($phpbb_root_path, '', $to);
+ 			}
+ 
+ 			$this->recursive_mkdir(dirname($to_file));
+ 
+ 			if (!$this->transfer->overwrite_file($file, $to_file))
+ 			{
+ 				// may as well return ... the MOD is likely dependent upon
+ 				// the file that is being copied
+ 				return sprintf($user->lang['MODS_FTP_FAILURE'], $to_file);
+ 			}
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Write & close file
+ 	*/
+ 	function close_file($new_filename)
+ 	{
+ 		global $phpbb_root_path, $edited_root, $mod_installed, $mod_uninstalled, $force_install;
+ 		global $db, $user;
+ 
+ 		if (!is_dir($new_filename) && !file_exists(dirname($new_filename)))
+ 		{
+ 			if ($this->recursive_mkdir(dirname($new_filename)) === false)
+ 			{
+ 				return sprintf($user->lang['MODS_MKDIR_FAILED'], dirname($new_filename));
+ 			}
+ 		}
+ 
+ 		$file_contents = implode('', $this->file_contents);
+ 
+ 		if ($this->template_id && ($mod_installed || $mod_uninstalled || $force_install))
+ 		{
+ 			update_database_template($new_filename, $this->template_id, $file_contents, $this->install_time);
+ 		}
+ 
+ 		if (!$this->transfer->write_file($new_filename, $file_contents))
+ 		{
+ 			return sprintf($user->lang['MODS_FTP_FAILURE'], $new_filename);
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Creates a backup of the currently open file before AutoMOD makes any changes
+ 	*/
+ 	function backup_file($backup_dir)
+ 	{
+ 		return $this->close_file($backup_dir . $this->open_filename);
+ 	}
+ 
+ 	/**
+ 	* @ignore
+ 	*/
+ 	function recursive_mkdir($path, $mode = 0777)
+ 	{
+ 		return $this->transfer->make_dir($path);
+ 	}
+ 
+ 	function commit_changes($source, $destination)
+ 	{
+ 		// Move edited files back
+ 		return $this->copy_content($source, $destination, $source);
+ 	}
+ 
+ 	function commit_changes_final($source, $destionation)
+ 	{
+ 		return NULL;
+ 	}
+ 
+ 	function create_edited_root($dir)
+ 	{
+ 		return $this->recursive_mkdir($dir);
+ 	}
+ }
+ 
+ class editor_manual extends editor
+ {
+ 	function editor_manual()
+ 	{
+ 		global $config, $phpbb_root_path;
+ 
+ 		$this->write_method = WRITE_MANUAL;
+ 		$this->install_time = time();
+ 
+ 		if (!class_exists('compress'))
+ 		{
+ 			global $phpEx;
+ 			include($phpbb_root_path . 'includes/functions_compress.' . $phpEx);
+ 		}
+ 
+ 		// Ugly regular expression to extract "tar" from "tar.gz" or "tar.bz2"
+ 		// Made ugly because it does nothing with "zip"
+ 		preg_match('#\.(\w{3})\.?.*#', $config['compress_method'], $match);
+ 		$class = 'compress_' . $match[1];
+ 
+ 		$this->compress = new $class('w', $phpbb_root_path . 'store/mod_' . $this->install_time . $config['compress_method'], $config['compress_method']);
+ 	}
+ 
+ 	function copy_content($from, $to = '', $strip = '')
+ 	{
+ 		global $phpbb_root_path, $user;
+ 
+ 		if (strpos($from, $phpbb_root_path) !== 0)
+ 		{
+ 			$from = $phpbb_root_path . $from;
+ 		}
+ 
+ 		if (strpos($to, $phpbb_root_path) !== 0)
+ 		{
+ 			$to = $phpbb_root_path . $to;
+ 		}
+ 
+ 		// Note: phpBB's compression class does support adding a whole directory at a time.
+ 		// However, I chose not to use that function because it would not allow AutoMOD's
+ 		// error handling to work the same as for FTP & Direct methods.
+ 		$files = array();
+ 		if (is_dir($from))
+ 		{
+ 			// get all of the files within the directory
+ 			$files = find_files($from, '.*');
+ 		}
+ 		else if (is_file($from))
+ 		{
+ 			$files = array($from);
+ 		}
+ 
+ 		if (empty($files))
+ 		{
+ 			return false;
+ 		}
+ 
+ 		foreach ($files as $file)
+ 		{
+ 			if (is_dir($to))
+ 			{
+ 				$to_file = str_replace(array($phpbb_root_path, $strip), '', $file);
+ 			}
+ 			else
+ 			{
+ 				$to_file = str_replace($phpbb_root_path, '', $to);
+ 			}
+ 
+ 			// filename calculation is involved here: be sure to remove "store/mods/foo"
+ 			// and prepend the "files" directory
+ 			if (!$this->compress->add_file($to_file, substr($to_file, 0, strpos($to_file, 'root/') + 5), 'files'))
+ 			{
+ 				return sprintf($user->lang['WRITE_MANUAL_FAIL'], $new_filename);
+ 			}
+ 		}
+ 
+ 		// return true since we are now taking an action - NULL implies no action
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Write & close file
+ 	*/
+ 	function close_file($new_filename)
+ 	{
+ 		global $phpbb_root_path, $edited_root, $mod_installed, $mod_uninstalled, $force_install;
+ 		global $db, $user;
+ 
+ 		$file_contents = implode('', $this->file_contents);
+ 
+ 		if ($this->template_id && ($mod_installed || $mod_uninstalled || $force_install))
+ 		{
+ 			update_database_template($new_filename, $this->template_id, $file_contents, $this->install_time);
+ 		}
+ 
+ 		// don't include extra dirs in zip file
+ 		$strip_position = strpos($new_filename, '_edited') + 8; // want the end of the string
+ 		if (!$strip_position)
+ 		{
+ 			$strip_position = strpos($new_filename, '_uninst') + 7;
+ 		}
+ 
+ 		$new_filename = 'files/' . substr($new_filename, $strip_position);
+ 
+ 		if (!$this->compress->add_data($file_contents, $new_filename))
+ 		{
+ 			return sprintf($user->lang['WRITE_MANUAL_FAIL'], $new_filename);
+ 		}
+ 
+ 		return true;
+ 	}
+ 
+ 	/**
+ 	* Backup is undefined when creating a compressed file.
+ 	*/
+ 	function backup_file($backup_dir)
+ 	{
+ 		return NULL;
+ 	}
+ 
+ 	function recursive_mkdir($path, $mode = 0777)
+ 	{
+ 		return NULL;
+ 	}
+ 
+ 	function commit_changes($source, $destination)
+ 	{
+ 		global $template, $user, $phpbb_admin_path;
+ 
+ 		$download_url = append_sid("{$phpbb_admin_path}index.php", 'i=mods&amp;mode=frontend&amp;action=download&amp;time=' . $this->install_time);
+ 
+ 		$template->assign_vars(array(
+ 			'S_MANUAL_INSTRUCTIONS'		=> true,
+ 			'L_AM_MANUAL_INSTRUCTIONS'	=> sprintf($user->lang['AM_MANUAL_INSTRUCTIONS'], '<a href="' . $download_url . '">', '</a>'),
+ 		));
+ 
+ 		meta_refresh(3, $download_url);
+ 
+ 		$this->compress->close();
+ 		return true;
+ 	}
+ 
+ 	function commit_changes_final($source, $destination)
+ 	{
+ 		return NULL;
+ 	}
+ 
+ 	function create_edited_root($dir)
+ 	{
+ 		return NULL;
+ 	}
+ } 
+ 
+ ?>
\ No newline at end of file

Propchange: trunk/titania/includes/library/automod/editor.php
------------------------------------------------------------------------------
    svn:keywords = Revision Author Date Id

Added: trunk/titania/includes/library/automod/functions_mods.php
==============================================================================
*** trunk/titania/includes/library/automod/functions_mods.php (added)
--- trunk/titania/includes/library/automod/functions_mods.php Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,321 ----
+ <?php
+ /**
+ *
+ * @package automod
+ * @version $Id$
+ * @copyright (c) 2008 phpBB Group
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
+ *
+ */
+ 
+ /**
+ * @ignore
+ */
+ if (!defined('IN_PHPBB'))
+ {
+ 	exit;
+ }
+ 
+ global $table_prefix;
+ define('MODS_TABLE', $table_prefix . 'mods');
+ 
+ define('WRITE_DIRECT', 1);
+ define('WRITE_FTP', 2);
+ define('WRITE_MANUAL', 3);
+ 
+ function test_ftp_connection($method, &$test_ftp_connection, &$test_connection)
+ {
+ 	global $phpbb_root_path, $phpEx;
+ 
+ 	$transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
+ 
+ 	$test_connection = $transfer->open_session();
+ 
+ 	// Make sure that the directory is correct by checking for the existence of common.php
+ 	if ($test_connection === true)
+ 	{
+ 		// Check for common.php file
+ 		if (!$transfer->file_exists($phpbb_root_path, 'common.' . $phpEx))
+ 		{
+ 			$test_connection = 'ERR_WRONG_PATH_TO_PHPBB';
+ 		}
+ 	}
+ 
+ 	$transfer->close_session();
+ 
+ 	// Make sure the login details are correct before continuing
+ 	if ($test_connection !== true)
+ 	{
+ 		$test_ftp_connection = true;
+ 	}
+ 
+ 	return;
+ }
+ 
+ /**
+ * Helper function
+ * Runs basename() on $path, then trims the extension from it
+ * @param string $path - path to be basenamed
+ */
+ function core_basename($path)
+ {
+ 	$path = basename($path);
+ 	$path = substr($path, 0, strrpos($path, '.'));
+ 
+ 	$parts = explode('-', $path);
+ 	return end($parts);
+ }
+ 
+ /**
+ * Helper function for matching languages
+ * This is a fairly dumb function because it ignores dialects.  But I have
+ * not seen any MODs that specify more than one dialect of the same language
+ * @param string $user_language - ISO language code of the current user
+ * @param string $xml_language - ISO language code of the MODX tag
+ * @return bool Whether or not this is a match
+ */
+ function match_language($user_language, $xml_language)
+ {
+ 	return strtolower(substr($user_language, 0, 2)) == strtolower(substr($xml_language, 0, 2));
+ }
+ 
+ /**
+ * Easy method to grab localisable tags from the XML array
+ * @param $header - variable holding all relevant tag information
+ * @param $tagname - tag name to fetch
+ * @param $index - Index number to pull.  Not required.
+ * @return $output - Localised contents of the tag in question
+ */
+ function localise_tags($header, $tagname, $index = false)
+ {
+ 	global $user;
+ 
+ 	$output = '';
+ 
+ 	if (isset($header[$tagname]) && is_array($header[$tagname]))
+ 	{
+ 		foreach ($header[$tagname] as $i => $void)
+ 		{
+ 			// Ugly.
+ 			if ($index !== false && $index != $i)
+ 			{
+ 				continue;
+ 			}
+ 
+ 			if (!isset($header[$tagname][$i]['attrs']['LANG']))
+ 			{
+ 				// avoid notice...although, if we get here, MODX is invalid.
+ 				continue;
+ 			}
+ 
+ 			if (match_language($user->data['user_lang'], $header[$tagname][$i]['attrs']['LANG']))
+ 			{
+ 				$output = isset($header[$tagname][$i]['data']) ? htmlspecialchars(trim($header[$tagname][$i]['data'])) : '';
+ 			}
+ 		}
+ 
+ 		// If there was no language match, put something out there
+ 		// This is probably fairly common for non-English users of the MODs Manager
+ 		if (!$output)
+ 		{
+ 			$output = isset($header[$tagname][0]['data']) ? htmlspecialchars(trim($header[$tagname][0]['data'])) : '';
+ 		}
+ 	}
+ 
+ 	if (!$output)
+ 	{
+ 		// Should never happen.  If it does, either the MOD is not valid MODX
+ 		// or the tag being localised is optional
+ 		$output = isset($user->lang['UNKNOWN_MOD_' . $tagname]) ? $user->lang['UNKNOWN_MOD_' . $tagname] : 'UNKNOWN_MOD_' .$tagname;
+ 	}
+ 
+ 	return $output;
+ }
+ 
+ /**
+ * List files matching specified PCRE pattern.
+ *
+ * @access public
+ * @param string Relative or absolute path to the directory to be scanned.
+ * @param string Search pattern (perl compatible regular expression).
+ * @param integer Number of subdirectory levels to scan (set to 1 to scan only current).
+ * @param integer This one is used internally to control recursion level.
+ * @return array List of all files found matching the specified pattern.
+ */
+ function find_files($directory, $pattern, $max_levels = 20, $_current_level = 1)
+ {
+ 	if ($_current_level <= 1)
+ 	{
+ 		if (strpos($directory, '\\') !== false)
+ 		{
+ 			$directory = str_replace('\\', '/', $directory);
+ 		}
+ 		if (empty($directory))
+ 		{
+ 			$directory = './';
+ 		}
+ 		else if (substr($directory, -1) != '/')
+ 		{
+ 			$directory .= '/';
+ 		}
+ 	}
+ 
+ 	$files = array();
+ 	$subdir = array();
+ 	if (is_dir($directory))
+ 	{
+ 		$handle = @opendir($directory);
+ 		while (($file = @readdir($handle)) !== false)
+ 		{
+ 			if ($file == '.' || $file == '..')
+ 			{
+ 				continue;
+ 			}
+ 
+ 			$fullname = $directory . $file;
+ 
+ 			if (is_dir($fullname))
+ 			{
+ 				if ($_current_level < $max_levels)
+ 				{
+ 					$subdir = array_merge($subdir, find_files($fullname . '/', $pattern, $max_levels, $_current_level + 1));
+ 				}
+ 			}
+ 			else
+ 			{
+ 				if (preg_match('/^' . $pattern . '$/i', $file))
+ 				{
+ 					$files[] = $fullname;
+ 				}
+ 			}
+ 		}
+ 		@closedir($handle);
+ 		sort($files);
+ 	}
+ 
+ 	return array_merge($files, $subdir);
+ }
+ 
+ /**
+ * This function is common to all editor classes, so it is pulled out from them
+ * @param $filename - The filename to update
+ * @param $template_id - The template set to update
+ * @param $file_contents - The data to write
+ * @param $install_time - Essentially the current time
+ * @return bool true
+ */
+ function update_database_template($filename, $template_id, $file_contents, $install_time)
+ {
+ 	global $db;
+ 
+ 	// grab filename
+ 	preg_match('#styles/[a-z0-9_]+/template/([a-z0-9_]+.html)#i', $filename, $match);
+ 
+ 	if (empty($match[1]))
+ 	{
+ 		return false;
+ 	}
+ 
+ 	$sql = 'UPDATE ' . STYLES_TEMPLATE_DATA_TABLE . "
+ 		SET template_data = '" . $db->sql_escape($file_contents) . "', template_mtime = " . (int) $install_time . '
+ 		WHERE template_id = ' . (int) $template_id . "
+ 		AND template_filename = '" . $db->sql_escape($match[1]) . "'";
+ 	$db->sql_query($sql);
+ 
+ 	// if something failed, sql_query will error out
+ 	return true;
+ }
+ 
+ function determine_write_method($pre_install = false)
+ {
+ 	global $phpbb_root_path, $config;
+ 
+ 	// to be truly correct, we should scan all files ...
+ 	if ((is_writable($phpbb_root_path) && $config['write_method'] == WRITE_DIRECT) || $pre_install)
+ 	{
+ 		$write_method = 'direct';
+ 	}
+ 	// FTP Method is now auto-detected
+ 	else if ($config['write_method'] == WRITE_FTP)
+ 	{
+ 		$write_method = 'ftp';
+ 	}
+ 	// or zip or tarballs
+ 	else if ($config['compress_method'])
+ 	{
+ 		$write_method = 'manual';
+ 	}
+ 	else
+ 	{
+ 		// We cannot go on without a write method set up.
+ 		trigger_error('MODS_SETUP_INCOMPLETE', E_USER_ERROR);
+ 	}
+ 
+ 	return $write_method;
+ }
+ 
+ function handle_ftp_details($method, $test_ftp_connection, $test_connection)
+ {
+ 	global $config, $template, $user;
+ 
+ 	$s_hidden_fields = build_hidden_fields(array('method' => $method));
+ 
+ 	if (!class_exists($method))
+ 	{
+ 		trigger_error('Method does not exist.', E_USER_ERROR);
+ 	}
+ 
+ 	$requested_data = call_user_func(array($method, 'data'));
+ 	foreach ($requested_data as $data => $default)
+ 	{
+ 		$default = (!empty($config['ftp_' . $data])) ? $config['ftp_' . $data] : $default;
+ 
+ 		$template->assign_block_vars('data', array(
+ 			'DATA'		=> $data,
+ 			'NAME'		=> $user->lang[strtoupper($method . '_' . $data)],
+ 			'EXPLAIN'	=> $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'],
+ 			'DEFAULT'	=> (!empty($_REQUEST[$data])) ? request_var($data, '') : $default
+ 		));
+ 	}
+ 
+ 	$template->assign_vars(array(
+ 		'S_CONNECTION_SUCCESS'		=> ($test_ftp_connection && $test_connection === true) ? true : false,
+ 		'S_CONNECTION_FAILED'		=> ($test_ftp_connection && $test_connection !== true) ? true : false,
+ 		'ERROR_MSG'					=> ($test_ftp_connection && $test_connection !== true) ? $user->lang[$test_connection] : '',
+ 
+ 		'S_FTP_UPLOAD'			=> true,
+ 		'UPLOAD_METHOD'			=> $method,
+ 		'S_HIDDEN_FIELDS_FTP'	=> $s_hidden_fields,
+ 	));
+ }
+ 
+ /**
+ * PHP 5 Wrapper - simulate scandir, but only those features that we actually need
+ * NB: The third parameter of PHP5 native scandir is _not_ present in this wrapper
+ */
+ if (!function_exists('scandir'))
+ {
+ 	function scandir($directory, $sorting_order = false)
+ 	{
+ 		$files = array();
+ 
+ 		$dp = opendir($directory);
+ 		while (($filename = readdir($dp)) !== false)
+ 		{
+ 			$files[] = $filename;
+ 		}
+ 
+ 		if ($sorting_order)
+ 		{
+ 			rsort($files);
+ 		}
+ 		else
+ 		{
+ 			sort($files);
+ 		}
+ 
+ 		return $files;
+ 	}
+ }
+ 
+ ?>
\ No newline at end of file

Propchange: trunk/titania/includes/library/automod/functions_mods.php
------------------------------------------------------------------------------
    svn:keywords = Revision Author Date Id

Added: trunk/titania/includes/library/automod/mod_parser.php
==============================================================================
*** trunk/titania/includes/library/automod/mod_parser.php (added)
--- trunk/titania/includes/library/automod/mod_parser.php Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,730 ----
+ <?php
+ /** 
+ *
+ * @package automod
+ * @version $Id$
+ * @copyright (c) 2008 phpBB Group
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License 
+ *
+ */
+ /**
+ */
+ if (!defined('IN_PHPBB'))
+ {
+ 	exit;
+ }
+ 
+ /**
+ * MOD Parser class
+ * Basic wrapper to run individual parser functions
+ * Also contains some parsing functions that are global (i.e. needed for all parsers)
+ * @package automod
+ *
+ * Each parser requires the following functions:
+ *	~ set_file($path_to_mod_file)
+ *		~ a means of setting the data to be acted upon
+ *	~ get_details()
+ *		~ returns an array of information about the MOD
+ *	~ get_actions()
+ *		~ returns an array of the MODs actions
+ *	~ get_modx_version
+ *		~ returns the MODX version of the MOD being looked at
+ *
+ */
+ class parser
+ {
+ 	var $parser;
+ 
+ 	/**
+ 	* constructor, sets type of parser
+ 	*/
+ 	function parser($ext)
+ 	{
+ 		switch ($ext)
+ 		{
+ 			case 'xml':
+ 			default:
+ 				$this->parser = new parser_xml();
+ 			break;
+ 		}
+ 	}
+ 
+ 	function set_file($file)
+ 	{
+ 		$this->parser->set_file($file);
+ 	}
+ 
+ 	function get_details()
+ 	{
+ 		return $this->parser->get_details();
+ 	}
+ 
+ 	function get_actions()
+ 	{
+ 		return $this->parser->get_actions();
+ 	}
+ 
+ 	function get_modx_version()
+ 	{
+ 		if (!$this->parser->modx_version)
+ 		{
+ 			$this->get_details();
+ 		}
+ 
+ 		return $this->parser->modx_version;
+ 	}
+ 
+ 	/**
+ 	* Returns the needed sql query to reverse the actions taken by the given query
+ 	* @todo: Add more
+ 	*/
+ 	function reverse_query($orig_query)
+ 	{
+ 		if (preg_match('#ALTER TABLE\s([a-z_]+)\sADD(COLUMN|)\s([a-z_]+)#i', $orig_query, $matches))
+ 		{
+ 			return "ALTER TABLE {$matches[1]} DROP COLUMN {$matches[3]};";
+ 		}
+ 		else if (preg_match('#CREATE TABLE\s([a-z_])+#i', $orig_query, $matches))
+ 		{
+ 			return "DROP TABLE {$matches[1]};";
+ 		}
+ 
+ 		return false;
+ 	}
+ 
+ 	/**
+ 	* Parse sql
+ 	*
+ 	* @param array $sql_query
+ 	*/
+ 	function parse_sql(&$sql_query)
+ 	{
+ 		global $dbms, $table_prefix;
+ 
+ 		if (!function_exists('get_available_dbms'))
+ 		{
+ 			global $phpbb_root_path, $phpEx;
+ 
+ 			include($phpbb_root_path . 'includes/functions_install.' . $phpEx);
+ 		}
+ 
+ 		static $available_dbms;
+ 
+ 		if (!isset($available_dbms))
+ 		{
+ 			$available_dbms = get_available_dbms($dbms);
+ 		}
+ 
+ 		$remove_remarks = $available_dbms[$dbms]['COMMENTS'];
+ 		$delimiter = $available_dbms[$dbms]['DELIM'];
+ 
+ 		if (sizeof($sql_query) == 1)
+ 		{
+ 			// do some splitting here
+ 			$sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query);
+ 			$remove_remarks($sql_query[0]);
+ 			$sql_query = split_sql_file($sql_query[0], $delimiter);
+ 		}
+ 		else
+ 		{
+ 			$query_count = sizeof($sql_query);
+ 			for ($i = 0; $i < $query_count; $i++)
+ 			{
+ 				$sql_query[$i] = preg_replace('#phpbb_#i', $table_prefix, $sql_query[$i]);
+ 				$remove_remarks($sql_query[$i]);
+ 			}
+ 		}
+ 
+ 		//return $sql_query;
+ 	}
+ 
+ 	/**
+ 	* Returns the edits array, but now filled with edits to reverse the given array
+ 	* @todo: Add more
+ 	*/
+ 	function reverse_edits($actions)
+ 	{
+ 		$reverse_edits = array();
+ 
+ 		foreach ($actions['EDITS'] as $file => $edit_ary)
+ 		{
+ 			foreach ($edit_ary as $edit_id => $edit)
+ 			{
+ 				foreach ($edit as $find => $action_ary)
+ 				{
+ 					foreach ($action_ary as $type => $command)
+ 					{
+ 						// it is possible for a single edit in the install process
+ 						// to become more than one in the uninstall process
+ 						while (isset($reverse_edits['EDITS'][$file][$edit_id]))
+ 						{
+ 							$edit_id++;
+ 						}
+ 
+ 						switch (strtoupper($type))
+ 						{
+ 							// for before and after adds, we use the find as a tool for more precise finds
+ 							// this isn't perfect, but it seems better than having
+ 							// finds of only a couple characters, like "/*"
+ 							case 'AFTER ADD':
+ 								$total_find = rtrim($find, "\n") . "\n" . trim($command, "\n");
+ 
+ 								$reverse_edits['EDITS'][$file][$edit_id][$total_find]['replace with'] = $find;
+ 							break;
+ 
+ 							case 'BEFORE ADD':
+ 								$total_find = rtrim($command, "\n") . "\n" . trim($find, "\n");
+ 
+ 								// replace with the find
+ 								$reverse_edits['EDITS'][$file][$edit_id][$total_find]['replace with'] = $find;
+ 							break;
+ 
+ 							case 'REPLACE WITH':
+ 							case 'REPLACE, WITH':
+ 							case 'REPLACE-WITH':
+ 							case 'REPLACE':
+ 								// replace $command (new code) with $find (original code)
+ 								$reverse_edits['EDITS'][$file][$edit_id][$command]['replace with'] = $find;
+ 							break;
+ 
+ 							case 'IN-LINE-EDIT':
+ 								// build the reverse just like the normal action
+ 								foreach ($command as $inline_find => $inline_action_ary)
+ 								{
+ 									foreach ($inline_action_ary as $inline_action => $inline_command)
+ 									{
+ 										$inline_command = $inline_command[0];
+ 
+ 										switch (strtoupper($inline_action))
+ 										{
+ 											case 'IN-LINE-AFTER-ADD':
+ 											case 'IN-LINE-BEFORE-ADD':
+ 												// Replace with a blank string
+ 												$reverse_edits['EDITS'][$file][$edit_id][$find]['in-line-edit'][$inline_command]['in-line-replace'][] = '';
+ 											break;
+ 	
+ 											case 'IN-LINE-REPLACE':
+ 												// replace with the inline find
+ 												$reverse_edits['EDITS'][$file][$edit_id][$find]['in-line-edit'][$inline_command][$inline_action][] = $inline_find;
+ 											break;
+ 	
+ 											default:
+ 												// For the moment, we do nothing.  What about increment?
+ 											break;
+ 										}
+ 									}
+ 								}
+ 							break;
+ 
+ 							case 'SQL':
+ 								$reverse_edits['SQL'][] = $this->reverse_query($command);
+ 							break;
+ 
+ 							default:
+ 								// again, increment
+ 							break;
+ 						}
+ 					}
+ 				}
+ 			}
+ 		}
+ 
+ 		return $reverse_edits;
+ 	}
+ }
+ 
+ /**
+ * XML parser
+ * @package automod
+ */
+ class parser_xml
+ {
+ 	var $data;
+ 	var $file;
+ 	var $modx_version;
+ 
+ 	/**
+ 	* set data to read from
+ 	*/
+ 	function set_file($file)
+ 	{
+ 		// Shouldn't ever happen since the master class reads file names from
+ 		// the file system and lists them
+ 		if (!file_exists($file))
+ 		{
+ 			trigger_error('Cannot locate File: ' . $file);
+ 		}
+ 
+ 		$this->file = $file;
+ 		$this->data = trim(@file_get_contents($file));
+ 		$this->data = str_replace(array("\r\n", "\r"), "\n", $this->data);
+ 
+ 		$XML = new xml_array();
+ 		$this->data = $XML->parse($this->file, $this->data);
+ 
+ 		return;
+ 	}
+ 
+ 	/**
+ 	* return array of the basic MOD details
+ 	*/
+ 	function get_details()
+ 	{
+ 		global $user;
+ 
+ 		if (empty($this->data))
+ 		{
+ 			$this->set_file($this->file);
+ 		}
+ 
+ 		$header = array(
+ 			'MOD-VERSION'	=> array(0 => array('children' => array())),
+ 			'INSTALLATION'	=> array(0 => array('children' => array('TARGET-VERSION' => array(0 => array('data' => ''))))),
+ 			'AUTHOR-GROUP'	=> array(0 => array('children' => array('AUTHOR' => array()))),
+ 			'HISTORY'		=> array(0 => array('children' => array('ENTRY' => array()))),
+ 		);
+ 
+ 		$version = $phpbb_version = '';
+ 
+ 		$header = $this->data[0]['children']['HEADER'][0]['children'];
+ 
+ 		// get MOD version information
+ 		// This is also our first opportunity to differentiate MODX 1.0.x from
+ 		// MODX 1.2.0.
+ 		if (isset($header['MOD-VERSION'][0]['children']))
+ 		{
+ 			$this->modx_version = 1.0;
+ 
+ 			$version_info = $header['MOD-VERSION'][0]['children'];
+ 			$version = (isset($version_info['MAJOR'][0]['data'])) ? trim($version_info['MAJOR'][0]['data']) : 0;
+ 			$version .= '.' . ((isset($version_info['MINOR'][0]['data'])) ? trim($version_info['MINOR'][0]['data']) : 0);
+ 			$version .= '.' . ((isset($version_info['REVISION'][0]['data'])) ? trim($version_info['REVISION'][0]['data']) : 0);
+ 			$version .= (isset($version_info['RELEASE'][0]['data'])) ? trim($version_info['RELEASE'][0]['data']) : '';
+ 		}
+ 		else
+ 		{
+ 			$this->modx_version = 1.2;
+ 
+ 			$version = trim($header['MOD-VERSION'][0]['data']); 
+ 		}
+ 
+ 		// get phpBB version recommendation
+ 		switch ($this->modx_version)
+ 		{
+ 			case 1.0:
+ 				if (isset($header['INSTALLATION'][0]['children']['TARGET-VERSION'][0]['children']))
+ 				{
+ 					$version_info = $header['INSTALLATION'][0]['children']['TARGET-VERSION'][0]['children'];
+ 
+ 					$phpbb_version = (isset($version_info['MAJOR'][0]['data'])) ? trim($version_info['MAJOR'][0]['data']) : 0;
+ 					$phpbb_version .= '.' . ((isset($version_info['MINOR'][0]['data'])) ? trim($version_info['MINOR'][0]['data']) : 0);
+ 					$phpbb_version .= '.' . ((isset($version_info['REVISION'][0]['data'])) ? trim($version_info['REVISION'][0]['data']) : 0);
+ 					$phpbb_version .= (isset($version_info['RELEASE'][0]['data'])) ? trim($version_info['RELEASE'][0]['data']) : '';
+ 				}
+ 			break;
+ 
+ 			case 1.2:
+ 			default:
+ 				$phpbb_version = (isset($header['INSTALLATION'][0]['children']['TARGET-VERSION'][0]['data'])) ? $header['INSTALLATION'][0]['children']['TARGET-VERSION'][0]['data'] : 0;
+ 			break;
+ 		}
+ 
+ 		$author_info = $header['AUTHOR-GROUP'][0]['children']['AUTHOR'];
+ 
+ 		$author_details = array();
+ 		for ($i = 0; $i < sizeof($author_info); $i++)
+ 		{
+ 			$author_details[] = array(
+ 				'AUTHOR_NAME'		=> isset($author_info[$i]['children']['USERNAME'][0]['data']) ? trim($author_info[$i]['children']['USERNAME'][0]['data']) : '',
+ 				'AUTHOR_EMAIL'		=> isset($author_info[$i]['children']['EMAIL'][0]['data']) ? trim($author_info[$i]['children']['EMAIL'][0]['data']) : '',
+ 				'AUTHOR_REALNAME'	=> isset($author_info[$i]['children']['REALNAME'][0]['data']) ? trim($author_info[$i]['children']['REALNAME'][0]['data']) : '',
+ 				'AUTHOR_WEBSITE'	=> isset($author_info[$i]['children']['HOMEPAGE'][0]['data']) ? trim($author_info[$i]['children']['HOMEPAGE'][0]['data']) : '',
+ 			);
+ 		}
+ 
+ 		// history
+ 		$history_info = (!empty($header['HISTORY'][0]['children']['ENTRY'])) ? $header['HISTORY'][0]['children']['ENTRY'] : array();
+ 		$history_size = sizeof($history_info);
+ 
+ 		$mod_history = array();
+ 		for ($i = 0; $i < $history_size; $i++)
+ 		{
+ 			$changes	= array();
+ 			$entry		= $history_info[$i]['children'];
+ 			$changelog	= isset($entry['CHANGELOG']) ? $entry['CHANGELOG'] : array();
+ 			$changelog_size = sizeof($changelog);
+ 			$changelog_id = 0;
+ 
+ 			for ($j = 0; $j < $changelog_size; $j++)
+ 			{
+ 				// Ignore changelogs in foreign languages except in the case that there is no 
+ 				// match for the current user's language
+ 				// TODO: Look at modifying localise_tags() for use here.
+ 				if (match_language($user->data['user_lang'], $changelog[$j]['attrs']['LANG']))
+ 				{
+ 					$changelog_id = $j;
+ 				}
+ 			}
+ 
+ 			$change_count = isset($changelog[$changelog_id]['children']['CHANGE']) ? sizeof($changelog[$changelog_id]['children']['CHANGE']) : 0;
+ 			for ($j = 0; $j < $change_count; $j++)
+ 			{
+ 				$changes[] = $changelog[$changelog_id]['children']['CHANGE'][$j]['data'];
+ 			}
+ 
+ 			switch ($this->modx_version)
+ 			{
+ 				case 1.0:
+ 					$changelog_version_ary	= (isset($entry['REV-VERSION'][0]['children'])) ? $entry['REV-VERSION'][0]['children'] : array();
+ 
+ 					$changelog_version = (isset($changelog_version_ary['MAJOR'][0]['data'])) ? trim($changelog_version_ary['MAJOR'][0]['data']) : 0;
+ 					$changelog_version .= '.' . ((isset($changelog_version_ary['MINOR'][0]['data'])) ? trim($changelog_version_ary['MINOR'][0]['data']) : 0);
+ 					$changelog_version .= '.' . ((isset($changelog_version_ary['REVISION'][0]['data'])) ? trim($changelog_version_ary['REVISION'][0]['data']) : 0);
+ 					$changelog_version .= (isset($changelog_version_ary['RELEASE'][0]['data'])) ? trim($changelog_version_ary['RELEASE'][0]['data']) : '';
+ 				break;
+ 
+ 				case 1.2:
+ 				default:
+ 					$changelog_version = (isset($entry['REV-VERSION'][0]['data'])) ? $entry['REV-VERSION'][0]['data'] : '0.0.0';
+ 				break;
+ 			}
+ 
+ 			$mod_history[] = array(
+ 				'DATE'		=> $entry['DATE'][0]['data'],
+ 				'VERSION'	=> $changelog_version,
+ 				'CHANGES'	=> $changes,
+ 			);
+ 		}
+ 
+ 		$children = array();
+ 
+ 		// Parse links
+ 		if ($this->modx_version == 1.2)
+ 		{
+ 			$link_group = (isset($header['LINK-GROUP'][0]['children'])) ? $header['LINK-GROUP'][0]['children'] : array();
+ 
+ 			if (isset($link_group['LINK']))
+ 			{
+ 				for ($i = 0, $size = sizeof($link_group['LINK']); $i <= $size; $i++)
+ 				{
+ 					// do some stuff with attrs
+ 					// commented out due to a possible PHP bug.  When using this, 
+ 					// sizeof($link_group) changed each time ...
+ 					// $attrs = &$link_group[$i]['attrs'];
+ 	
+ 					if (!isset($link_group['LINK'][$i]))
+ 					{
+ 						continue;
+ 					}
+ 
+ 					$children[$link_group['LINK'][$i]['attrs']['TYPE']][] = array(
+ 						'href'		=> $link_group['LINK'][$i]['attrs']['HREF'],
+ 						'realname'	=> isset($link_group['LINK'][$i]['attrs']['REALNAME']) ? $link_group['LINK'][$i]['attrs']['REALNAME'] : core_basename($link_group['LINK'][$i]['attrs']['HREF']),
+ 						'title'		=> localise_tags($link_group, 'LINK', $i),
+ 					);
+ 				}
+ 			}
+ 		}
+ 
+ 		// try not to hardcode schema?
+ 		$details = array(
+ 			'MOD_PATH' 		=> $this->file,
+ 			'MOD_NAME'		=> localise_tags($header, 'TITLE'),
+ 			'MOD_DESCRIPTION'	=> nl2br(localise_tags($header, 'DESCRIPTION')),
+ 			'MOD_VERSION'		=> htmlspecialchars(trim($version)),
+ //			'MOD_DEPENDENCIES'	=> (isset($header['TITLE'][0]['data'])) ? htmlspecialchars(trim($header['TITLE'][0]['data'])) : '',
+ 
+ 			'AUTHOR_DETAILS'	=> $author_details,
+ 			'AUTHOR_NOTES'		=> nl2br(localise_tags($header, 'AUTHOR-NOTES')),
+ 			'MOD_HISTORY'		=> $mod_history,
+ 			'PHPBB_VERSION'		=> $phpbb_version,
+ 			'CHILDREN'			=> $children,
+ 		);
+ 
+ 		return $details;
+ 	}
+ 
+ 	/**
+ 	* returns complex array containing all mod actions
+ 	*/
+ 	function get_actions()
+ 	{
+ 		global $db, $user;
+ 
+ 		$actions = array();
+ 
+ 		$xml_actions = $this->data[0]['children']['ACTION-GROUP'][0]['children'];
+ 
+ 		// sql
+ 		$actions['SQL'] = array();
+ 		$sql_info = (!empty($xml_actions['SQL'])) ? $xml_actions['SQL'] : array();
+ 
+ 		$match_dbms = array();
+ 		switch ($db->sql_layer)
+ 		{
+ 			case 'firebird':
+ 			case 'oracle':
+ 			case 'postgres':
+ 			case 'sqlite':
+ 			case 'mssql':
+ 			case 'db2':
+ 				$match_dbms = array($db->sql_layer);
+ 			break;
+ 
+ 			case 'mssql_odbc':
+ 				$match_dbms = array('mssql');
+ 			break;
+ 
+ 			// and now for the MySQL fun
+ 			// This will generate an array of things we can probably use, but	
+ 			// will not have any priority
+ 			case 'mysqli':
+ 				$match_dbms = array('mysql_41', 'mysqli', 'mysql');
+ 			break;
+ 
+ 			case 'mysql4':
+ 			case 'mysql':
+ 				if (version_compare($db->sql_server_info(true), '4.1.3', '>='))
+ 				{
+ 					$match_dbms = array('mysql_41', 'mysql4', 'mysql', 'mysqli');
+ 				}
+ 				else if (version_compare($db->sql_server_info(true), '4.0.0', '>='))
+ 				{
+ 					$match_dbms = array('mysql_40', 'mysql4', 'mysql', 'mysqli');
+ 				}
+ 				else
+ 				{
+ 					$match_dbms = array('mysql');
+ 				}
+ 			break;
+ 
+ 			// Should never happen
+ 			default:
+ 			break;
+ 		}
+ 
+ 		for ($i = 0; $i < sizeof($sql_info); $i++)
+ 		{
+ 			if ($this->modx_version == 1.0)
+ 			{
+ 				$actions['SQL'][] = (!empty($sql_info[$i]['data'])) ? trim($sql_info[$i]['data']) : '';
+ 			}
+ 			else if ($this->modx_version == 1.2)
+ 			{
+ 				// Make a slightly shorter name.
+ 				$xml_dbms = &$sql_info[$i]['attrs']['DBMS'];
+ 
+ 				if (!isset($sql_info[$i]['attrs']['DBMS']) || in_array($xml_dbms, $match_dbms))
+ 				{
+ 					$actions['SQL'][] = (!empty($sql_info[$i]['data'])) ? trim($sql_info[$i]['data']) : '';
+ 				}
+ 				else
+ 				{
+ 					// NOTE: skipped SQL is not currently useful
+ 					$sql_skipped = true;
+ 				}
+ 			}
+ 		}
+ 
+ 		// new files
+ 		$new_files_info = (!empty($xml_actions['COPY'])) ? $xml_actions['COPY'] : array();
+ 		for ($i = 0; $i < sizeof($new_files_info); $i++)
+ 		{
+ 			$new_files = $new_files_info[$i]['children']['FILE'];
+ 			for ($j = 0; $j < sizeof($new_files); $j++)
+ 			{
+ 				$from = str_replace('\\', '/', $new_files[$j]['attrs']['FROM']);
+ 				$to = str_replace('\\', '/', $new_files[$j]['attrs']['TO']);
+ 				$actions['NEW_FILES'][$from] = $to;
+ 			}
+ 		}
+ 
+ 		// open
+ 		$open_info = (!empty($xml_actions['OPEN'])) ? $xml_actions['OPEN'] : array();
+ 		for ($i = 0; $i < sizeof($open_info); $i++)
+ 		{
+ 			$current_file = str_replace('\\', '/', trim($open_info[$i]['attrs']['SRC']));
+ 			$actions['EDITS'][$current_file] = array();
+ 
+ 			$edit_info = (!empty($open_info[$i]['children']['EDIT'])) ? $open_info[$i]['children']['EDIT'] : array();
+ 			// find, after add, before add, replace with
+ 			for ($j = 0; $j < sizeof($edit_info); $j++)
+ 			{
+ 				$action_info = (!empty($edit_info[$j]['children'])) ? $edit_info[$j]['children'] : array();
+ 
+ 				// store some array information to help decide what kind of operation we're doing
+ 				$action_count = $total_action_count = 0;
+ 				if (isset($action_info['ACTION']))
+ 				{
+ 					$action_count += sizeof($action_info['ACTION']);
+ 				}
+ 
+ 				if (isset($action_info['INLINE-EDIT']))
+ 				{
+ 					$total_action_count += sizeof($action_info['INLINE-EDIT']);
+ 				}
+ 
+ 				$find_count = sizeof($action_info['FIND']);
+ 				// first we try all the possibilities for a FIND/ACTION combo, then look at inline possibilities.
+ 
+ 				if (isset($action_info['ACTION']))
+ 				{
+ 					for ($k = 0; $k < $find_count; $k++)
+ 					{
+ 						// is this anything but the last iteration of the loop?
+ 						if ($k < ($find_count - 1))
+ 						{
+ 							// NULL has special meaning for an action ... no action to be taken; advance pointer 
+ 							$actions['EDITS'][$current_file][$j][$action_info['FIND'][$k]['data']] = NULL;
+ 						}
+ 						else
+ 						{
+ 							// this is the last iteration, assign the action tags 
+ 			
+ 							for ($l = 0; $l < $action_count; $l++)
+ 							{
+ 								$type = str_replace('-', ' ', $action_info['ACTION'][$l]['attrs']['TYPE']);
+ 								$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$k]['data'], "\n\r")][$type] = (isset($action_info['ACTION'][$l]['data'])) ? preg_replace("#^(\s)+\n#", '', rtrim(trim($action_info['ACTION'][$l]['data'], "\n"))) : '';
+ 							}
+ 						}
+ 					}
+ 				}
+ 
+ 				// add comment to the actions array
+ 				$actions['EDITS'][$current_file][$j]['comment'] = localise_tags($action_info, 'COMMENT');
+ 
+ 				// inline
+ 				if (isset($action_info['INLINE-EDIT']))
+ 				{
+ 					$inline_info = (!empty($action_info['INLINE-EDIT'])) ? $action_info['INLINE-EDIT'] : array();
+ 
+ 					if ($find_count > $total_action_count)
+ 					{
+ 						// Yeah, $k is used more than once for different information
+ 						for ($k = 0; $k < $find_count; $k++)
+ 						{
+ 							// is this anything but the last iteration of the loop?
+ 							if ($k < ($find_count - 1))
+ 							{
+ 								// NULL has special meaning for an action ... no action to be taken; advance pointer 
+ 								$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$k]['data'], "\r\n")] = NULL;
+ 							}
+ 						}
+ 					}
+ 
+ 					/*
+ 					* This loop attaches the in-line information to the _last
+ 					* find_ in the <edit> tag.  This is the intended behavior
+ 					* Any additional finds ought to be in a different edit tag
+ 					*/
+ 					for ($k = 0; $k < sizeof($inline_info); $k++)
+ 					{
+ 						$inline_data = (!empty($inline_info[$k]['children'])) ? $inline_info[$k]['children'] : array();
+ 
+ 						$inline_find_count = sizeof($inline_data['INLINE-FIND']);
+ 
+ 						$inline_comment = localise_tags($inline_data, 'INLINE-COMMENT');
+ 						$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$find_count - 1]['data'], "\r\n")]['in-line-edit']['inline-comment'] = $inline_comment;
+ 
+ 						$inline_actions = (!empty($inline_data['INLINE-ACTION'])) ? $inline_data['INLINE-ACTION'] : array();
+ 						for ($l = 0; $l < $inline_find_count; $l++)
+ 						{
+ 							$inline_find = $inline_data['INLINE-FIND'][$l]['data'];
+ 
+ 							// trying to reduce the levels of arrays without impairing features.
+ 							// need to keep the "full" edit intact.
+ 							//
+ 							// inline actions must be trimmed in case the MOD author
+ 							// inserts a new line by mistake
+ 							if ($l < ($inline_find_count - 1))
+ 							{
+ 								$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$find_count - 1]['data'], "\r\n")]['in-line-edit'][$k][$inline_find]['in-line-'][] = null;
+ 							}
+ 							else
+ 							{
+ 								for ($m = 0; $m < sizeof($inline_actions); $m++)
+ 								{
+ 									$type = str_replace(',', '-', str_replace(' ', '', $inline_actions[$m]['attrs']['TYPE']));
+ 									if (!empty($inline_actions[$m]['data']))
+ 									{
+ 										$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$find_count - 1]['data'], "\r\n")]['in-line-edit'][$k][$inline_find]['in-line-' . $type][] = trim($inline_actions[$m]['data'], "\n");
+ 									}
+ 									else
+ 									{
+ 										$actions['EDITS'][$current_file][$j][trim($action_info['FIND'][$find_count - 1]['data'], "\r\n")]['in-line-edit'][$k][$inline_find]['in-line-' . $type][] = '';
+ 									}
+ 								}
+ 							}
+ 						}
+ 					}
+ 				}
+ 			}
+ 		}
+ 
+ 		if (!empty($xml_actions['DIY-INSTRUCTIONS']))
+ 		{
+ 			$actions['DIY_INSTRUCTIONS'] = localise_tags($xml_actions, 'DIY-INSTRUCTIONS');
+ 		}
+ 
+ 		return $actions;
+ 	}
+ }
+ 
+ /**
+ * XML processing
+ * @package automod
+ */
+ class xml_array
+ {
+ 	var $output = array();
+ 	var $parser;
+ 	var $XML;
+ 
+ 	function parse($file, $XML)
+ 	{
+ 		$this->parser = xml_parser_create();
+ 		xml_set_object($this->parser, $this);
+ 		xml_set_element_handler($this->parser, "tag_open", "tag_closed");
+ 		xml_set_character_data_handler($this->parser, "tag_data");
+ 
+ 		$this->XML = xml_parse($this->parser, $XML);
+ 		if (!$this->XML)
+ 		{
+ 			die(sprintf("<strong>XML error</strong>: %s at line %d.  View the file %s in a web browser for a more detailed error message.", 
+ 				xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser), $file));
+ 		}
+ 
+ 		xml_parser_free($this->parser);
+ 
+ 		return $this->output;
+ 	}
+ 
+ 	function tag_open($parser, $name, $attrs)
+ 	{
+ 		$tag = array("name" => $name, "attrs" => $attrs);
+ 		array_push($this->output, $tag);
+ 	}
+ 
+ 	function tag_data($parser, $tag_data)
+ 	{
+ 		if ($tag_data)
+ 		{
+ 			if (isset($this->output[sizeof($this->output) - 1]['data']))
+ 			{
+ 				$this->output[sizeof($this->output) - 1]['data'] .= $tag_data;
+ 			}
+ 			else
+ 			{
+ 				$this->output[sizeof($this->output) - 1]['data'] = $tag_data;
+ 			}
+ 		}
+ 	}
+ 
+ 	function tag_closed($parser, $name)
+ 	{
+ 		$this->output[sizeof($this->output) - 2]['children'][$name][] = $this->output[sizeof($this->output) - 1];
+ 		array_pop($this->output);
+ 	}
+ }
+ 
+ ?>
\ No newline at end of file

Propchange: trunk/titania/includes/library/automod/mod_parser.php
------------------------------------------------------------------------------
    svn:keywords = Revision Author Date Id

Modified: trunk/titania/includes/tools/contrib_tools.php
==============================================================================
*** trunk/titania/includes/tools/contrib_tools.php (original)
--- trunk/titania/includes/tools/contrib_tools.php Sat Mar 27 17:24:58 2010
***************
*** 394,418 ****
  	/**
  	* Prepare the files to test automod with
  	*
! 	* @param string $version Version string of the revision (30 for 3.0.x, 32 for 3.2.x, etc)
  	*/
  	public function automod_phpbb_files($version)
  	{
! 		$version = titania::$config->phpbb_versions[$version];
! 		$phpbb_root = titania::$config->contrib_temp_path . 'phpbb/' . $version . '/';
  
! 		if (!file_exists($phpbb_root))
  		{
  			// Need to unzip
  			phpbb::_include('functions_compress', false, 'compress_zip');
  
  			// Unzip to our temp directory
! 			$zip = new compress_zip('r', TITANIA_ROOT . 'includes/tools/automod/phpbb/phpBB-' . $version . '.zip');
  			$zip->extract($phpbb_root);
  			$zip->close();
  
  			// Find the phpBB root
! 			$package_root = $this->find_root($phpbb_root, array(array('common.php')));
  
  			// Move it to the correct location
  			if ($package_root != '')
--- 394,419 ----
  	/**
  	* Prepare the files to test automod with
  	*
! 	* @param string $version the full phpBB version number.  Ex: 2.0.23, 3.0.1, 3.0.7-pl1
  	*/
  	public function automod_phpbb_files($version)
  	{
! 		$version = preg_replace('#[^a-zA-Z0-9\.\-]+#', '', $version);
  
! 		$phpbb_root = TITANIA_ROOT . 'store/phpbb_packages/extracted/' . $version . '/';
! 
! 		if (!file_exists($phpbb_root . 'common.php'))
  		{
  			// Need to unzip
  			phpbb::_include('functions_compress', false, 'compress_zip');
  
  			// Unzip to our temp directory
! 			$zip = new compress_zip('r', TITANIA_ROOT . 'store/phpbb_packages/phpBB-' . $version . '.zip');
  			$zip->extract($phpbb_root);
  			$zip->close();
  
  			// Find the phpBB root
! 			$package_root = $this->find_root($phpbb_root, 'common.php');
  
  			// Move it to the correct location
  			if ($package_root != '')
***************
*** 466,475 ****
  	{
  		phpbb::_include('functions_transfer', false, 'transfer');
  		phpbb::_include('functions_admin', 'recalc_nested_sets');
! 		titania::_include('tools/automod/acp_mods', false, 'acp_mods');
! 		titania::_include('tools/automod/editor', false, 'editor');
! 		titania::_include('tools/automod/mod_parser', false, 'parser');
! 		titania::_include('tools/automod/functions_mods', 'test_ftp_connection');
  
  		titania::add_lang('automod');
  
--- 467,476 ----
  	{
  		phpbb::_include('functions_transfer', false, 'transfer');
  		phpbb::_include('functions_admin', 'recalc_nested_sets');
! 		titania::_include('library/automod/acp_mods', false, 'acp_mods');
! 		titania::_include('library/automod/editor', false, 'editor');
! 		titania::_include('library/automod/mod_parser', false, 'parser');
! 		titania::_include('library/automod/functions_mods', 'test_ftp_connection');
  
  		titania::add_lang('automod');
  
***************
*** 484,490 ****
  			// Find the first item with install in the name
  			foreach (scandir($modx_file) as $item)
  			{
! 		       if (strpos($item, 'install') !== false && strpos($item, '.xml') !== false)
  		       {
  				   $modx_file .= $item;
  				   break;
--- 485,491 ----
  			// Find the first item with install in the name
  			foreach (scandir($modx_file) as $item)
  			{
! 		       if (strpos($item, 'install') !== false && strpos($item, '.xml'))
  		       {
  				   $modx_file .= $item;
  				   break;

Added: trunk/titania/store/phpbb_packages/extracted/index.htm
==============================================================================
*** trunk/titania/store/phpbb_packages/extracted/index.htm (added)
--- trunk/titania/store/phpbb_packages/extracted/index.htm Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,10 ----
+ <html>
+ <head>
+ <title></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ </head>
+ 
+ <body bgcolor="#FFFFFF" text="#000000">
+ 
+ </body>
+ </html>

Added: trunk/titania/store/phpbb_packages/index.htm
==============================================================================
*** trunk/titania/store/phpbb_packages/index.htm (added)
--- trunk/titania/store/phpbb_packages/index.htm Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,10 ----
+ <html>
+ <head>
+ <title></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ </head>
+ 
+ <body bgcolor="#FFFFFF" text="#000000">
+ 
+ </body>
+ </html>

Added: trunk/titania/store/phpbb_packages/read me.txt
==============================================================================
*** trunk/titania/store/phpbb_packages/read me.txt (added)
--- trunk/titania/store/phpbb_packages/read me.txt Sat Mar 27 17:24:58 2010
***************
*** 0 ****
--- 1,9 ----
+ All files must be named like the following:
+ 
+ phpBB-(full version).zip
+ 
+ Example:
+ 
+ phpBB-2.0.23.zip
+ phpBB-3.0.0.zip
+ phpBB-3.0.7-pl1.zip
\ No newline at end of file




More information about the customisationdb-commits mailing list