<?php /*

 ocPortal
 Copyright (c) ocProducts, 2004-2012

 See text/EN/licence.txt for full licencing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/


/**
 * @license		http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright	ocProducts Ltd
 * @package		core_upgrader
 */

/**
 * The upgrader.php script handler.
 */
function upgrade_script()
{
	@ini_set('ocproducts.xss_detect','0');

	require_lang('upgrade');
	require_code('database_action');
	require_code('config2');
	if (function_exists('set_time_limit')) @set_time_limit(180);

	if ((array_key_exists('given_password',$_POST)))
	{
		$given_password=post_param('given_password');
		if (check_master_password($given_password))
		{
			$type=get_param('type','misc');

			require_code('abstract_file_manager');

			up_do_header();

			if (post_param('ftp_username','')!='')
			{
				$_POST['uses_ftp']='1';
				_ftp_info(true); // To give early error if there's a problem
			}

			// Handle shared site upgrading with no per-site UI
			global $SITE_INFO;
			if (isset($SITE_INFO['custom_file_base_stub'])) // This upgrader script must be called on a particular site with a real DB (e.g. shareddemo.myocp.com), but will run for all sites on same install
			{
				require_code('shared_installs');
				$u=current_share_user();
				if (!is_null($u))
				{
					upgrade_sharedinstall_sites();
					echo '<p>Now regenerate <kbd>template.sql</kbd>, using something like <kbd>mysqldump -uroot -p myocp_site_shareddemo > ~/public_html/template.sql</kbd></p>';
					up_do_footer();
					return;
				}
			}

			$show_more_link=true;

			switch ($type)
			{
				case 'misc':
					clear_caches_1();

					$l_choices=do_lang('FU_CHOICES');
					$oc=(get_option('site_closed')=='0')?do_lang('SITE_OPEN'):do_lang('SITE_CLOSED');
					$a=float_to_raw_string(ocp_version_number());
					$b=get_value('version');
					if (is_null($b)) $b='2.5';
					$l_up_info=do_lang('FU_UP_INFO'.(($a==$b)?'_1':'_2'),$a,$b);
					$l_fu_closedness=do_lang('FU_CLOSENESS',$oc);
					$l_maintenance=do_lang('FU_MAINTENANCE');
					$l_upgrading=do_lang('FU_UPGRADING');
					$l_take_backup=do_lang('FU_TAKE_BACKUP');
					$l_clear_caches=fu_link('upgrader.php?type=decache',do_lang('FU_CLEAR_CACHES'));
					$l_check_permissions=fu_link('upgrader.php?type=check_perms',do_lang('FU_CHECK_PERMISSIONS'));
					$l_fix_permissions=fu_link('upgrader.php?type=fix_perms',do_lang('FU_FIX_PERMISSIONS'));
					$l_close_site=fu_link('upgrader.php?type=close_site',do_lang('FU_CLOSE_SITE'),get_option('site_closed')=='1');
					$l_integrity_scan=fu_link('upgrader.php?type=integrity_scan&allow_merging=1',do_lang('FU_INTEGRITY_SCAN'),false,do_lang('FU_WILL_MERGE'));
					$l_integrity_scan_no_merging=fu_link('upgrader.php?type=integrity_scan',do_lang('FU_INTEGRITY_SCAN_NO_CSS_MERGE'));
					$l_database_upgrade=fu_link('upgrader.php?type=db_upgrade',do_lang('FU_DATABASE_UPGRADE'));
					$l_theme_upgrade=fu_link('upgrader.php?type=theme_upgrade',do_lang('FU_THEME_UPGRADE'));
					$l_open_site=fu_link('upgrader.php?type=open_site',do_lang('FU_OPEN_SITE'),get_option('site_closed')=='0');
					$l_error_correction=do_lang('FU_ERROR_CORRECTION');
					$l_not_for_patch=do_lang('FU_NOT_FOR_PATCH');
					$l_tutorial=fu_link('http://ocportal.com/docs/tut_upgrade.htm',do_lang('FU_TUTORIAL'));
					$l_release_notes=do_lang('FU_RELEASE_NOTES');
					$l_refer_release_notes=do_lang('FU_REFER_RELEASE_NOTES');
					$news_id=post_param_integer('news_id',NULL);
					$tar_url='';
					if (!is_null($news_id))
					{
						require_code('files');
						$fetch_url='http://ocportal.com/uploads/website_specific/ocportal.com/scripts/fetch_release_details.php?news_id='.strval($news_id).'&from_version='.urlencode(strval(ocp_version()).'.'.ocp_version_minor());
						$news=http_download_file($fetch_url,NULL,true,false,'ocPortal',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,30.0);

						$details=unserialize($news);
						if ($details[0]!='')
							$l_refer_release_notes=$details[0].'<div style="overflow: auto; height: 150px">'.$details[2].'</div>';
						$tar_url=$details[1];
					}
					$l_download=fu_link('upgrader.php?type=file_upgrade&tar_url='.urlencode(base64_encode($tar_url)),do_lang('FU_DOWNLOAD'));
					$l_important=do_lang('IMPORTANT');
					$l_bugs=do_lang('FU_BUGS');
					$l_upgrade_steps=do_lang('FU_UPGRADE_STEPS');
					$l_action=do_lang('ACTION');
					$l_step=do_lang('FU_STEP');
					$l_estimated_time=do_lang('FU_ESTIMATED_TIME');
					$l_safe_mode=fu_link('index.php?keep_safe_mode=1',do_lang('FU_SAFE_MODE'));
					$num_addons=$GLOBALS['SITE_DB']->query_value('addons','COUNT(*)');
					$l_addon_management=fu_link('adminzone/index.php?page=admin_addons&keep_safe_mode=1',do_lang('FU_ADDON_MANAGEMENT',integer_format($num_addons)),$num_addons==0);
					$l_customisations=do_lang('FU_CUSTOMISATIONS');
					$closed=comcode_to_tempcode(get_option('closed'),NULL,true);
					$closed_url=build_url(array('page'=>'admin_config','type'=>'category','id'=>'SITE'),get_module_zone('admin_config'),NULL,false,false,false,'group_CLOSED_SITE');

					echo "
<p>{$l_choices}</p>

<div style=\"margin: 0 50px\">
	<h2>{$l_maintenance}&hellip;</h2><ul>
		<li>{$l_clear_caches}</li>
		<li>{$l_check_permissions}</li>
		<li>{$l_fix_permissions}</li>
	</ul>

	<h2 style=\"margin-top: 40px\">{$l_upgrading}&hellip;</h2>

	<h3>{$l_important}</h3>

	<p>{$l_bugs}</p>

	<h3>{$l_release_notes}</h3>

	<p>{$l_refer_release_notes}</p>

	<h3>{$l_upgrade_steps}</h3>

	<div class=\"wide_table_wrap\"><table style=\"margin-top: 5px\" class=\"solidborder wide_table spaced_table\">
		<tr>
			<th>{$l_step}</th>
			<th>{$l_action}</th>
			<th>{$l_estimated_time}</th>
		</tr>
		<tr><th>X</th><td>{$l_not_for_patch} {$l_tutorial}</td><td>".escape_html(display_time_period(60*120))."</td></tr>
		<tr><th>1</th><td>{$l_take_backup}</td><td>".escape_html(display_time_period(60*120))."</td></tr>
		<tr><th>2</th><td>{$l_close_site}  {$l_fu_closedness}<br /><q style=\"font-style: italic\">".$closed->evaluate()."</q> <span class=\"associated_link_to_small\">[<a href=\"".escape_html($closed_url->evaluate())."\" title=\"(this link will open in a new window)\" target=\"_blank\">".do_lang('CHANGE')."</a>]</span></td><td>".escape_html(display_time_period(60))."</td></tr>
		<tr><th>3</th><td>{$l_download}</td><td>".escape_html(display_time_period(60*5))."</td></tr>
		<tr><th>4</th><td>{$l_not_for_patch} {$l_integrity_scan_no_merging}<!-- ".do_lang('OR')." {$l_integrity_scan}--></td><td>".str_replace(' ','&nbsp;',escape_html(display_time_period(60*10)))."&nbsp;&dagger;</td></tr>
		<tr><th>5</th><td>{$l_not_for_patch} {$l_database_upgrade}<br />{$l_up_info}</td><td>".escape_html(display_time_period(60*5))."</td></tr>
		<tr><th>6</th><td>{$l_not_for_patch} {$l_theme_upgrade}</td><td>".escape_html(display_time_period(60*5))."</td></tr>
		<tr><th>7</th><td>{$l_clear_caches}</td><td>1 minute</td></tr>
		<tr><th>8</th><td>{$l_open_site}  {$l_fu_closedness}</td><td>1 minute</td></tr>
	</table></div>

	<p>&dagger; {$l_customisations}</p>

	<h2 style=\"margin-top: 40px\">{$l_error_correction}&hellip;</h2><ul style=\"margin-top: 5px\">
		<li>{$l_safe_mode}</li>
		<li>{$l_addon_management}</li>
	</ul>
</div>
";
					$show_more_link=false;
					break;

				case 'decache':
					clear_caches_2();
					echo '<p>'.do_lang('SUCCESS').'</p>';
					break;

				case 'check_perms':
					echo check_perms();
					break;

				case 'fix_perms':
					echo fix_perms();
					break;

				case 'open_site':
					set_option('site_closed','0');
					echo '<p>'.do_lang('SUCCESS').'</p>';
					break;

				case 'close_site':
					set_option('closed',do_lang('FU_CLOSED_FOR_UPGRADES',get_site_name()));
					set_option('site_closed','1');
					echo '<p>'.do_lang('SUCCESS').'</p>';
					break;

				case 'file_upgrade':
					if (get_param('tar_url','')=='') echo do_lang('FU_FILE_UPGRADE_INFO');
					echo do_lang('FU_FILE_UPGRADE_INFO_MANUAL');
					echo '<form title="'.do_lang('PROCEED').'" enctype="multipart/form-data" action="upgrader.php?type=_file_upgrade" method="post">'.post_fields_relay();
					echo '<label for="url">'.do_lang('URL').'</label> <input type="text" id="url" name="url" value="'.escape_html(base64_decode(get_param('tar_url',''))).'" /> ';
					if ((ocp_srv('HTTP_HOST')=='ocportal.com') || ($GLOBALS['DEBUG_MODE'])) // for ocProducts to use on own site, for testing
					{
						echo '<br /><label for="upload">'.do_lang('UPLOAD').'</label> <input type="file" id="upload" name="upload" />';
					}
					echo '<input type="submit" value="'.do_lang('PROCEED').'" />';
					echo '</form>';
					$show_more_link=false;
					break;

				case '_file_upgrade':
					require_code('tar');
					if (function_exists('set_time_limit')) @set_time_limit(0);
					if ((post_param('url','')=='') && ((ocp_srv('HTTP_HOST')=='ocportal.com') || ($GLOBALS['DEBUG_MODE'])))
					{
						$temp_path=$_FILES['upload']['tmp_name'];
					} else
					{
						if (post_param('url','')=='') warn_exit(do_lang_tempcode('IMPROPERLY_FILLED_IN'));

						$temp_path=ocp_tempnam('ocpfu');
						$myfile=fopen($temp_path,'wb');
						http_download_file(post_param('url'),NULL,true,false,'ocPortal',NULL,NULL,NULL,NULL,NULL,$myfile);
						fclose($myfile);
					}
					$upgrade_resource=tar_open($temp_path,'rb');
					//tar_extract_to_folder($upgrade_resource,'',true);
					disable_php_memory_limit();
					$directory=tar_get_directory($upgrade_resource); // Uses up to around 5MB
					$data=array('todo'=>array());
					$popup_simple_extract=(_ftp_info()===false);
					if (!$popup_simple_extract)
						echo '<p>'.do_lang('EXTRACTING_MESSAGE').'</p>';
					$addon_contents=array();
					// Find addons
					foreach ($directory as $upgrade_file2)
					{
						// See if we can find an addon registry file in our upgrade TAR
						if ((strpos($upgrade_file2['path'],'/addon_registry/')!==false) && (substr($upgrade_file2['path'],-4)=='.php'))
						{
							$file_data=tar_get_file($upgrade_resource,$upgrade_file2['path']);
							$addon_contents[basename($upgrade_file2['path'],'.php')]=$file_data['data'];
						}
					}
					// Process files
					foreach ($directory as $offset=>$upgrade_file)
					{
						// skip over these, from manually installer package (which may be used for an upgrade)
						if ($upgrade_file['path']=='info.php') continue;
						if ($upgrade_file['path']=='install.php') continue;
						if ($upgrade_file['path']=='install.sql') continue;
						if ($upgrade_file['path']=='info.php.template') continue;

						if (!$popup_simple_extract)
						{
							// See if we can skip the file, if the on-disk version is identical?
							if ((file_exists(get_file_base().'/'.$upgrade_file['path'])) && (filesize(get_file_base().'/'.$upgrade_file['path'])==$upgrade_file['size']))
							{
								$tar_data=tar_get_file($upgrade_resource,$upgrade_file['path']);
								if (file_get_contents(get_file_base().'/'.$upgrade_file['path'])==$tar_data['data'])
								{
									echo do_lang('U_SKIPPING_MESSAGE',escape_html($upgrade_file['path'])).'<br />';
									continue;
								}
							}
						}

						// Addon registry file, for installed addon
						if ((strpos($upgrade_file['path'],'/addon_registry/')!==false) && (file_exists(get_file_base().'/'.$upgrade_file['path'])))
						{
							if (substr($upgrade_file['path'],-1)!='/')
							{
								if ($popup_simple_extract)
								{
									$data['todo'][]=array($upgrade_file['path'],$upgrade_file['mtime'],$offset+512,$upgrade_file['size'],($upgrade_file['mode'] & 0002)!=0);
								} else
								{
									$file_data=tar_get_file($upgrade_resource,$upgrade_file['path']);
									afm_make_file($upgrade_file['path'],$file_data['data'],($file_data['mode'] & 0002)!=0);
									echo do_lang('U_EXTRACTING_MESSAGE',escape_html($upgrade_file['path'])).'<br />';
								}
							}
						} else
						{
							// Some other file
							$found=NULL;
							if (substr($upgrade_file['path'],-1)!='/')
							{
								foreach ($addon_contents as $addon_name=>$addon_data)
								{
									// See if this is the addon for the file
									$shortened_path=$upgrade_file['path'];
									$shortened_path=preg_replace('#^themes/default/(templates|css)/#','',$shortened_path);
									if (strpos($addon_data,'\''.addslashes($shortened_path).'\'')!==false)
									{
										$found=$addon_name;
										break;
									}
								}
							}

							// Install if either of the following is true:
							//  - it's some file not in an addon (shouldn't actually happen)
							//  - it's a new addon (addon that is not installed or uninstalled i.e. does not have an exported mod file)
							//  - it's a file in an addon we have installed
							//  - we're upgrading from an ocPortal version that doesn't support addons yet
							if ((is_null($found)) || (!file_exists(get_file_base().'/imports/mods/'.$found.'.tar')) || (file_exists(get_file_base().'/sources/hooks/systems/addon_registry/'.$found.'.php')) || (!file_exists(get_file_base().'/sources/hooks/systems/addon_registry')))
							{
								if (substr($upgrade_file['path'],-1)=='/')
								{
									afm_make_directory($upgrade_file['path'],false,true);
								} else
								{
									if ($popup_simple_extract)
									{
										$data['todo'][]=array($upgrade_file['path'],$upgrade_file['mtime'],$offset+512,$upgrade_file['size'],($upgrade_file['mode'] & 0002)!=0);
									} else
									{
										$file_data=tar_get_file($upgrade_resource,$upgrade_file['path']);
										if (!file_exists(get_file_base().'/'.dirname($upgrade_file['path']))) afm_make_directory(dirname($upgrade_file['path']),false,true);
										afm_make_file($upgrade_file['path'],$file_data['data'],($file_data['mode'] & 0002)!=0);

										echo do_lang('U_EXTRACTING_MESSAGE',escape_html($upgrade_file['path'])).'<br />';
									}
								}
							}

							if (substr($upgrade_file['path'],-1)!='/')
							{
								// If true: We need to copy it into our archived addon so that addon is kept up-to-date
								if ((!is_null($found)) && (file_exists(get_file_base().'/imports/mods/'.$found.'.tar')))
								{
									$old_mod_file=tar_open(get_file_base().'/imports/mods/'.$found.'.tar','rb');
									$new_mod_file=tar_open(get_file_base().'/imports/mods/'.$found.'.new.tar','wb');
									$directory2=tar_get_directory($old_mod_file,true);
									if (!is_null($directory2))
									{
										foreach ($directory2 as $d)
										{
											if ($d['path']==$upgrade_file['path']) continue;
											$file_data=tar_get_file($old_mod_file,$d['path']);
											if ($d['path']=='mod.inf')
											{
												$file_data['data']=preg_replace('#^version=.*#m','version=(version-synched)',$file_data['data']);
											}
											tar_add_file($new_mod_file,$d['path'],$file_data['data'],$d['mode'],$d['mtime']);
										}
										$file_data=tar_get_file($upgrade_resource,$upgrade_file['path']);
										tar_add_file($new_mod_file,$upgrade_file['path'],$file_data['data'],$upgrade_file['mode'],$upgrade_file['mtime']);
										tar_close($new_mod_file);
										tar_close($old_mod_file);
										unlink(get_file_base().'/imports/mods/'.$found.'.tar');
										rename(get_file_base().'/imports/mods/'.$found.'.new.tar',get_file_base().'/imports/mods/'.$found.'.tar');

										echo do_lang('U_PACKING_MESSAGE',escape_html($upgrade_file['path'])).'<br />';
									}
								}
							}
						}
					}
					tar_close($upgrade_resource);
					if ($popup_simple_extract)
					{
						copy($temp_path,get_custom_file_base().'/data_custom/upgrader.tar.tmp');
						@unlink($temp_path);
						$temp_path=get_custom_file_base().'/data_custom/upgrader.tar.tmp';
						$tmp_data_path=get_custom_file_base().'/data_custom/upgrader.tmp';
						$tmp_data_file=fopen($tmp_data_path,'wb');
						fwrite($tmp_data_file,serialize($data));
						fclose($tmp_data_file);
						global $SITE_INFO;
						$extract_url=get_base_url().'/data/upgrader2.php?hashed_password='.urlencode($SITE_INFO['admin_password']).'&tmp_path='.urlencode($temp_path).'&file_offset=0&tmp_data_path='.urlencode($tmp_data_path).'&done='.urlencode(do_lang('DONE'));
						echo '<p>'.do_lang('FU_EXTRACTING_WINDOW',integer_format(count($data['todo']))).'</p>';
						echo '<iframe frameBorder="0" title="" style="width: 100%; height: 400px" src="'.escape_html($extract_url).'"></iframe>';
					} else
					{
						echo '<p>'.do_lang('SUCCESS').'</p>';
						@unlink($temp_path);
					}

					unset($_POST['news_id']);

					break;

				case 'integrity_scan':
					$allow_merging=either_param_integer('allow_merging',0);
					echo run_integrity_check(false,$allow_merging==1);
					break;

				case '_integrity_scan':
					_integrity_scan();
					echo '<p>'.do_lang('SUCCESS').'</p>';
					break;

				case 'db_upgrade':
					$something_done=false;
					clear_caches_2();
					if (version_specific())
					{
						echo do_lang('FU_UPGRADED_CORE_TABLES');
						$something_done=true;
					}	
					$done=upgrade_modules();
					if ($done!='')
					{
						echo do_lang('FU_UPGRADE_MODULES',$done);
						$something_done=true;
					}
					if (!$something_done) echo do_lang('NO_UPGRADE_DONE');

					$version_files=ocp_version_number();
					$_version_database=get_value('ocf_version');
					$version_database=floatval($_version_database);
					if (is_null($_version_database)) $version_database=2.1; // Either 2.0 or 2.1, and they are equivalent in terms of what we need to do
					if ($version_database<$version_files) echo do_lang('FU_MUST_UPGRADE_OCF',fu_link('upgrader.php?type=ocf',do_lang('FU_UPGRADE_OCF')));
					break;

				case 'theme_upgrade':
					echo upgrade_themes();
					break;

				case 'ocf': // Only to be launched as a consequent of db_upgrade
					if (ocf_upgrade()) echo '<p>'.do_lang('SUCCESS').'</p>'; else echo do_lang('FU_NO_OCF_UPGRADE');
					break;
			}

			if ($show_more_link)
			{
				echo '<hr /><div>'.fu_link('upgrader.php?type=misc',do_lang('MORE_OPTIONS')).'</div>';
			}
		} else
		{
			up_do_header();
			up_do_login(do_lang('USER_BAD_PASSWORD'));
		}
	} else
	{
		up_do_header();
		up_do_login();
	}

	up_do_footer();
}

/**
 * Do an integrity check. This does not include an alien check in basic mode; otherwise check_alien() is called within this function.
 *
 * @param  boolean	Whether to just do the minimum basic scan.
 * @param  boolean 	Whether merging of CSS changes is allowed.
 * @param  boolean 	Whether to give some help to unix people.
 * @return string		Results.
 */
function run_integrity_check($basic=false,$allow_merging=true,$unix_help=false)
{
	$ret_str='';

	// We'll need to know about stuff in our addon registry, and file manifest
	if (function_exists('find_all_hooks'))
	{
		$hooks=find_all_hooks('systems','addon_registry');
	} else
	{
		$hooks=array();
		$dir=get_file_base().'/sources/hooks/systems/addon_registry';
		$dh=@opendir($dir);
		if ($dh!==false)
		{
			while (($file=readdir($dh))!==false)
			{
				if ((substr($file,-4)=='.php') && (preg_match('#^[\w\-]*$#',substr($file,0,strlen($file)-4))!=0))
				{
					$hooks[substr($file,0,strlen($file)-4)]='sources';
				}
			}
			closedir($dh);
		}
	}
	$hook_keys=array_keys($hooks);
	$hook_files=array();
	foreach ($hook_keys as $hook)
	{
		$path=get_custom_file_base().'/sources/hooks/systems/addon_registry/'.filter_naughty_harsh($hook).'.php';
		if (!file_exists($path))
		{
			$path=get_file_base().'/sources/hooks/systems/addon_registry/'.filter_naughty_harsh($hook).'.php';
		}
		$hook_files[$hook]=file_get_contents($path);
	}
	unset($hook_keys);
	$master_data=@unserialize(file_get_contents(get_file_base().'/data/files.dat',FILE_TEXT));
	if ($master_data===false) $master_data=array();

	// Moved module handling
	if ($basic)
	{
		$not_missing=array();
	} else
	{
		$hidden=post_fields_relay();
		$ret_str.='<form title="'.do_lang('PROCEED').'" action="upgrader.php?type=_integrity_scan" method="post">'.$hidden;
		list($moved,$not_missing)=move_modules();
		if ($moved!='')
		{
			$ret_str.=do_lang('WARNING_MOVED_MODULES',$moved);
		}
	}

	// Override handling
	list($outdated__outdated_original_and_override,$outdated__possibly_outdated_override,$outdated__missing_original_but_has_override,$outdated__uninstalled_addon_but_has_override)=check_outdated__handle_overrides(get_file_base().'/','',$master_data,$hook_files,$allow_merging);

	// Look for missing files, wrt bundled addons
	$outdated__outdated_original='';
	$outdated__missing_file_entirely='';
	$outdated__future_files='';
	$files_determined_to_upload=array();
	$files_to_check=array();
	foreach ($hook_files as $addon_name=>$hook_file)
	{
		$matches=array();
		if (preg_match('#function get_file_list\(\)\s*\{([^\}]*)\}#',$hook_file,$matches)!=0)
		{
			if (!defined('HIPHOP_PHP'))
			{
				$files_to_check=array_merge($files_to_check,eval($matches[1]));
			} else
			{
				require_code('hooks/systems/addon_registry/'.$addon_name);
				$hook=object_factory('Hook_addon_registry_'.$addon_name);
				$files_to_check=array_merge($files_to_check,$hook->get_file_list());
			}
		}
	}
	unset($hook_files);
	sort($files_to_check);
	foreach ($files_to_check as $file)
	{
		if (should_ignore_file($file,IGNORE_BUNDLED_VOLATILE)) continue;

		if (preg_match('#^[^/]+\.tpl$#',$file)!=0)
			$real_file='themes/default/templates/'.$file;
		elseif (preg_match('#^[^/]+\.css$#',$file)!=0)
			$real_file='themes/default/css/'.$file;
		else
			$real_file=$file;
		$file_info=@$master_data[$real_file];

		if ($file=='data/files.dat') continue;
		if ($file=='data/files_previous.dat') continue;
		if (($file=='recommended.htaccess') || ($file=='plain.htaccess')) continue; // May be renamed
		if (!file_exists(get_file_base().'/'.$real_file))
		{
			if (!in_array(get_file_base().'/'.$real_file,$not_missing))
			{
				$outdated__missing_file_entirely.='<li><kbd>'.escape_html($real_file).'</kbd></li>';
				$files_determined_to_upload[]=$real_file;
			}
		} elseif (!is_null($file_info))
		{
			if (@filesize(get_file_base().'/'.$real_file)>1024*1024) continue; // Too big, so special exception

			$file_contents=@file_get_contents(get_file_base().'/'.$real_file,FILE_BINARY);
			if ($file_contents===false) continue;
			if (strpos($real_file,'/version.php')!==false) $file_contents=preg_replace('/\d{10}/','',$file_contents);
			$true_hash=sprintf('%u',crc32(preg_replace('#[\r\n\t ]#','',$file_contents)));
			if ($true_hash!=$file_info[0])
			{
				if (filemtime(get_file_base().'/'.$real_file)<ocp_version_time())
				{
					$outdated__outdated_original.='<li><kbd>'.escape_html($real_file).'</kbd></li>'; //  [disk-hash: '.$true_hash.', required-hash: '.$file_info[0].']
					$files_determined_to_upload[]=$real_file;
				} else
				{
					$outdated__future_files.='<li><kbd>'.escape_html($real_file).'</kbd></li>';
				}
			}
		}
	}

	// Output integrity check results
	if ($outdated__possibly_outdated_override!='')
	{
		if ($basic)
		{
			$ret_str.='<p>The following files have been superseded by new versions, but you have overrides/customisations blocking the new versions. Look into this and consider reincorporating your changes into our new version. If this is not done, bugs (potentially security holes) may occur, or be left unfixed. If you edited using an inbuilt editor, the file on which you based it will be saved as <kbd>file.editfrom</kbd>: you may use a tool such as <a href="http://winmerge.sourceforge.net/" target="_blank">WinMerge</a> to compare the <kbd>editfrom</kbd> file to your own, and then apply those same changes to the latest version of the file.</p><ul>'.$outdated__possibly_outdated_override.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_OUTDATED',$outdated__possibly_outdated_override);
		}
	}
	if ($outdated__outdated_original_and_override!='')
	{
		if ($basic)
		{
			$ret_str.='<p>The following non-overridden files are outdated, as are the corresponding overridden files (you can find the correct versions for the original in the manual installer ZIP for the version you\'re running, but the overrides may still cause problems and might need removing/replacing):</p><ul>'.$outdated__outdated_original_and_override.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_OUTDATED_ORIGINAL_AND_OVERRIDE',$outdated__outdated_original_and_override);
		}
	}
	if ($outdated__missing_original_but_has_override!='')
	{
		if ($basic)
		{
			$ret_str.='<p>The following original files to these overridden files are actually missing (you can find them in the manual installer ZIP for the version you\'re running):</p><ul>'.$outdated__missing_original_but_has_override.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_MISSING_ORIGINAL_BUT_HAS_OVERRIDE',$outdated__missing_original_but_has_override);
		}
	}
	if (($outdated__uninstalled_addon_but_has_override!='') && (!$basic))
	{
		$ret_str.=do_lang('WARNING_FILE_FROM_UNINSTALLED_ADDON',$outdated__uninstalled_addon_but_has_override);
	}
	if ($outdated__missing_file_entirely!='')
	{
		if ($basic)
		{
			$ret_str.='<p>These files are actually missing and need uploading (you can find them in the manual installer ZIP for the version you\'re running):</p><ul>'.$outdated__missing_file_entirely.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_MISSING_FILE_ENTIRELY',$outdated__missing_file_entirely);
		}
	}
	if ($outdated__outdated_original!='')
	{
		if ($basic)
		{
			$ret_str.='<p>These files are outdated (you can find the correct versions in the manual installer ZIP for the version you\'re running):</p><ul>'.$outdated__outdated_original.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_OUTDATED_ORIGINAL',$outdated__outdated_original);
		}
	}
	if ($outdated__future_files!='')
	{
		if ($basic)
		{
			$ret_str.='<p>These files do not match the ones bundled with your version, but claim to be newer (so these might be bug fixes someone has put here):</p><ul>'.$outdated__future_files.'</ul>';
		} else
		{
			$ret_str.=do_lang('WARNING_FILE_FUTURE_FILES',$outdated__future_files);
		}
	}

	// And some special help for unix geeks
	if ($unix_help)
	{
		$unix_out='OCP_EXTRACTED_AT="<manual-extracted-at-dir>";'."\n".'cd "<temp-dir-to-upload-from>";'."\n";
		$directories_to_make=array();
		foreach ($files_determined_to_upload as $file)
		{
			$dirname=dirname($file);
			$directories_to_make[$dirname]=1;
		}
		foreach (array_keys($directories_to_make) as $directory)
		{
			$unix_out.='mkdir -p '.escapeshellcmd($directory).';'."\n";
		}
		foreach ($files_determined_to_upload as $file)
		{
			$unix_out.='cp "$OCP_EXTRACTED_AT/'.escapeshellcmd($file).'" "'.escapeshellcmd(dirname($file)).'"/;'."\n";
		}
		require_lang('upgrade');
		$ret_str.=do_lang('SH_COMMAND',nl2br(escape_html($unix_out)));
	}

	// Alien files
	if (!$basic)
	{
		$master_data=array();
		foreach ($files_to_check as $file)
		{
			if ((substr($file,-4)=='.tpl') && (strpos($file,'/')===false))
			{
				$master_data['themes/default/templates/'.$file]=1;
			}
			elseif ((substr($file,-4)=='.css') && (strpos($file,'/')===false))
			{
				$master_data['themes/default/css/'.$file]=1;
			} else
			{
				$master_data[$file]=1;
			}
		}

		$alien=check_alien(file_exists(get_file_base().'/data/files_previous.dat')?unserialize(file_get_contents(get_file_base().'/data/files_previous.dat',FILE_TEXT)):array(),$master_data,get_file_base().'/');
		if ($alien!='')
		{
			$ret_str.=do_lang('WARNING_FILE_ALIEN',$alien);
		}
		if (($moved!='') || ($alien!=''))
		{
			$ret_str.='<input accesskey="c" style="margin: 1px; padding: 0" type="submit" value="'.do_lang('FU_AUTO_HANDLE').'" />';
		}
		$ret_str.='</form>';
	}

	return $ret_str;
}

/**
 * Get hidden form fields for relaying POST information.
 *
 * @return string		The hidden form fields for relaying POST information.
 */
function post_fields_relay()
{
	$hidden='';
	foreach (array_keys($_POST) as $key)
	{
		$hidden.='<input type="hidden" name="'.escape_html($key).'" value="'.escape_html(post_param($key)).'" />';
	}
	return $hidden;
}

/**
 * Generate a form-based link to relay POST information to a URL.
 *
 * @param  string		The URL (something like 'upgrader.php?type=ocf')
 * @param  string		The URL caption text
 * @param  boolean	Whether it is disabled
 * @param  string		Extra Javascript
 * @return string		The form-based link
 */
function fu_link($url,$text,$disabled=false,$js='')
{
	$hidden=(strpos($url,'http://ocportal.com')!==false)?'':post_fields_relay();
	if (get_param_integer('keep_safe_mode',0)==1) $url.='&keep_safe_mode=1';
	if (get_param_integer('keep_show_loading',0)==1) $url.='&keep_show_loading=1';
	return '<form title="'.escape_html($text).'" style="display: inline" action="'.escape_html($url).'" method="post">'.$hidden.'<input '.(empty($js)?'':'onclick="return window.confirm(\''.addslashes($js).'\');" ').'accesskey="c" style="margin: 1px; padding: 0" '.($disabled?'disabled="disabled"':'').' type="submit" value="'.escape_html($text).'" /></form>';
}

/**
 * Output a login page.
 *
 * @param  ?string	Error message (NULL: none)
 */
function up_do_login($message=NULL)
{
	$type=get_param('type','misc');
	global $SITE_INFO;
	$ftp_username=get_value('ftp_username');
	$ftp_folder=get_value('ftp_directory');
	$ftp_domain=get_value('ftp_domain');
	if (is_null($ftp_domain)) $ftp_domain=array_key_exists('ftp_domain',$SITE_INFO)?$SITE_INFO['ftp_domain']:'localhost';
	if (is_null($ftp_username))
	{
		if (!array_key_exists('ftp_username',$SITE_INFO))
		{
			if ((function_exists('posix_getpwuid')) && (strpos(@ini_get('disable_functions'),'posix_getpwuid')===false))
			{
				$u_info=posix_getpwuid(fileowner(get_file_base().'/index.php'));
				$ftp_username=$u_info['name'];
			} else $ftp_username='';
			if (is_null($ftp_username)) $ftp_username='';
		} else $ftp_username=$SITE_INFO['ftp_username'];
	}
	if (is_null($ftp_folder))
	{
		if (!array_key_exists('ftp_folder',$SITE_INFO))
		{
			$dr=array_key_exists('DOCUMENT_ROOT',$_SERVER)?$_SERVER['DOCUMENT_ROOT']:(array_key_exists('DOCUMENT_ROOT',$_ENV)?$_ENV['DOCUMENT_ROOT']:'');
			if (strpos($dr,'/')!==false) $dr_parts=explode('/',$dr); else $dr_parts=explode('\\',$dr);
			$webdir_stub=$dr_parts[count($dr_parts)-1];
			$pos=strpos($_SERVER['PHP_SELF'],'upgrader.php');
			if ($pos===false) $pos=strlen($_SERVER['PHP_SELF']); else $pos--;
			$ftp_folder='/'.$webdir_stub.substr($_SERVER['PHP_SELF'],0,$pos);
		} else $ftp_folder=$SITE_INFO['ftp_folder'];
	}
	require_lang('installer');
	$l_password=do_lang('MASTER_PASSWORD');
	$l_ftp_info=do_lang('FU_FTP_INFO');
	$l_ftp_domain=do_lang('FTP_DOMAIN');
	$l_ftp_directory=do_lang('FTP_DIRECTORY');
	$l_ftp_username=do_lang('FTP_USERNAME');
	$l_ftp_password=do_lang('FTP_PASSWORD');
	$l_login=do_lang('_LOGIN');
	$l_login_info=do_lang('FU_LOGIN_INFO');
	$l_login_info_pass_forget=do_lang('FU_LOGIN_INFO_PASS_FORGET');
	$l_login_forgot_password_q=do_lang('FU_LOGIN_FORGOT_PASSWORD_Q');
	if (!is_null($message)) echo '<p><strong>'.$message.'</strong></p>';
	$news_id=get_param_integer('news_id',NULL);
	$url="upgrader.php?type=".escape_html($type);
	if (get_param_integer('keep_safe_mode',0)==1) $url.='&keep_safe_mode=1';
	if (get_param_integer('keep_show_loading',0)==1) $url.='&keep_show_loading=1';
	echo "
	<p>{$l_login_info}</p>
	<form title=\"{$l_login}\" action=\"".escape_html($url)."\" method=\"post\">
	".(is_null($news_id)?'':('<input type="hidden" name="news_id" value="'.strval($news_id).'" />'))."
	<p>
		{$l_password}: <input type=\"password\" name=\"given_password\" value=\"".escape_html(post_param('password',''))."\" />
	</p>
	";

	require_code('files');
	if ((is_suexec_like()) || ((!function_exists('ftp_ssl_connect')) && (!function_exists('ftp_connect'))))
	{
	} else
	{
		echo "
		<hr />
		{$l_ftp_info}
		<table>
			<tr><th>{$l_ftp_domain}:</th><td><input size=\"50\" type=\"text\" name=\"ftp_domain\" value=\"".escape_html($ftp_domain)."\" /></td></tr>
			<tr><th>{$l_ftp_directory}:</th><td><input size=\"50\" type=\"text\" name=\"ftp_folder\" value=\"".escape_html($ftp_folder)."\" /></td></tr>
			<tr><th>{$l_ftp_username}:</th><td><input size=\"50\" type=\"text\" name=\"ftp_username\" value=\"".escape_html($ftp_username)."\" /></td></tr>
			<tr><th>{$l_ftp_password}:</th><td><input size=\"50\" type=\"password\" name=\"ftp_password\" /></td></tr>
		</table>
		<hr />
		";
	}

	echo "
	<p>
		<input type=\"submit\" value=\"{$l_login}\" />
	</p>
	</form>
	";

	echo "
	<hr />
	<div style=\"font-size: 0.8em\">
	<h2>{$l_login_forgot_password_q}</h2>
	<p>{$l_login_info_pass_forget}</p>
	</div>
	";
}

/**
 * Output the upgrader page header.
 */
function up_do_header()
{
	$upgrader_title=do_lang('FU_UPGRADER_TITLE');
	$upgrader_intro=do_lang('FU_UPGRADER_INTRO');
	$charset=get_charset();
	$lang=user_lang();

	@ob_end_clean();
	echo <<<END
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{$lang}" lang="{$lang}">
	<head>
		<meta http-equiv="Content-Type" content="application/xhtml+xml; charset={$charset}" />

		<title>{$upgrader_title}</title>
		<link rel="icon" href="http://ocportal.com/favicon.ico" type="image/x-icon" />

		<style type="text/css">
END;
@print(preg_replace('#/\*\s*\*/\s*#','',str_replace('url(\'\')','none',str_replace('url("")','none',preg_replace('#\{[\$+].*\}#','',file_get_contents(get_file_base().'/themes/default/css/global.css'))))));
echo <<<END
			.main_page_title { text-decoration: underline; display: block; background: url('themes/default/images/bigicons/ocp-logo.png') top left no-repeat; min-height: 42px; padding: 3px 0 0 60px; }
			a[target="_blank"], a[onclick$="window.open"] { padding-right: 0; }
		</style>

		<meta name="robots" content="noindex, nofollow" />
	</head>
	<body class="re_body"><div class="global_middle">
		<h1 class="main_page_title">{$upgrader_title}</h1>
		<p>{$upgrader_intro}</p><hr />
END;
}

/**
 * Output the upgrader page footer.
 */
function up_do_footer()
{
	echo <<<END
	</div></body>
</html>
END;
}

/**
 * Clear many caches.
 */
function clear_caches_1() // These have to happen early - to prevent things that could kill the update process
{
	require_code('view_modes');
	erase_cached_templates();
	erase_cached_language();
}

/**
 * Clear more caches. This is intentionally done after db upgrading.
 */
function clear_caches_2()
{
	require_code('view_modes');
	require_code('zones2');
	if (file_exists(get_file_base().'/sources/zones3.php')) // If is for back-compatibility, was introduced in newer version and function moved into here
		require_code('zones3');
	erase_comcode_cache();
	erase_tempcode_cache();
	erase_comcode_page_cache();
	persistant_cache_empty();
}

/**
 * Find extra directories to chmod
 *
 * @return array		Extra directories to chmod
 */
function get_chmod_array_2()
{
	$hooks=find_all_hooks('systems','chmod');
	$directories=array();
	foreach (array_keys($hooks) as $hook)
	{
		require_code('hooks/systems/chmod/'.filter_naughty_harsh($hook));
		$ob=object_factory('Hook_chmod_'.filter_naughty_harsh($hook),true);
		if (is_null($ob)) continue;
		$directories=array_merge($directories,$ob->run());
	}
	return $directories;
}

/**
 * Do permission checking
 *
 * @return string		Output messages
 */
function check_perms()
{
	require_code('inst_special');

	$super_out='';

	global $LANG;
	$LANG='EN'; // Make it simple
	if (array_key_exists('lang',$_GET)) $LANG=$_GET['lang'];
	if (preg_match('#\w+#A',$LANG)==0) return '';

	$array=array_merge(get_chmod_array(),get_chmod_array_2());
	require_code('themes2');
	$themes=find_all_themes();

	$out='';
	for ($i=0;$i<count($array);$i++)
	{
		$chmod=$array[$i];
		if (is_dir(get_file_base().'/'.$chmod))
		{
			if (strpos($chmod,'themes/default')!==false) // chmod ALL theme dirs
			{
				foreach (array_keys($themes) as $theme)
				{
					$_chmod=str_replace('themes/default','themes/'.$theme,$chmod);
					$dh=@opendir(get_file_base().'/'.$_chmod);
					if ($dh!==false)
					{
						while (($file=readdir($dh))!==false) if (!should_ignore_file($_chmod.'/'.$file,IGNORE_ACCESS_CONTROLLERS)) $array[]=$_chmod.'/'.$file;
						closedir($dh);
					}
				}
			} else
			{
				$dh=@opendir(get_file_base().'/'.$chmod);
				if ($dh!==false)
				{
					while (($file=readdir($dh))!==false) if (!should_ignore_file($chmod.'/'.$file,IGNORE_ACCESS_CONTROLLERS)) $array[]=$chmod.'/'.$file;
					closedir($dh);
				}
			}
		}
		/*if (strpos($chmod,'themes/default')!==false) // chmod ALL theme files
		{
			foreach (array_keys($themes) as $theme)
			{
				$_chmod=str_replace('themes/default','themes/'.$theme,$chmod);
				if (!file_exists(get_file_base().'/'.$_chmod)) continue;
				if (!is_writable_wrap(get_file_base().'/'.$_chmod)) $out.='<li>'.do_lang('FU_NEEDS_CHMOD','<kbd>'.escape_html($_chmod).'</kbd>').'</li>';
			}
		} else
		{*/
			if (!file_exists(get_file_base().'/'.$chmod)) continue;
			if (!is_writable_wrap(get_file_base().'/'.$chmod)) $out.='<li>'.do_lang('FU_NEEDS_CHMOD','<kbd>'.escape_html($chmod).'</kbd>').'</li>';
		//}
	}
	$out.=check_excess_perms($array);
	if ($out=='')
	{
		$super_out=do_lang('FU_ALL_CHMODDED_GOOD');
	} else
	{
		$super_out=do_lang('WARNING_FILE_CHMOD',$out);
	}

	return $super_out;
}

/**
 * Do permission setting
 *
 * @return string		Output messages
 */
function fix_perms()
{
	require_code('inst_special');

	$super_out='';

	global $LANG;
	$LANG=get_param('lang','EN');

	$array=array_merge(get_chmod_array(),get_chmod_array_2());
	require_code('themes2');
	$themes=find_all_themes();

	$GLOBALS['SUPRESS_ERROR_DEATH']=true;

	for ($i=0;$i<count($array);$i++)
	{
		$chmod=$array[$i];
		if (is_dir(get_file_base().'/'.$chmod))
		{
			if (strpos($chmod,'themes/default')!==false)
			{
				foreach (array_keys($themes) as $theme)
				{
					$_chmod=str_replace('themes/default','themes/'.$theme,$chmod);
					$dh=@opendir(get_file_base().'/'.$_chmod);
					if ($dh!==false)
					{
						while (($file=readdir($dh))!==false)
						{
							if (!should_ignore_file($_chmod.'/'.$file,IGNORE_ACCESS_CONTROLLERS)) $array[]=$_chmod.'/'.$file;
						}
						closedir($dh);
					}
				}
			} else
			{
				$dh=@opendir(get_file_base().'/'.$chmod);
				if ($dh!==false)
				{
					while (($file=readdir($dh))!==false)
					{
						if (!should_ignore_file($chmod.'/'.$file,IGNORE_ACCESS_CONTROLLERS)) $array[]=$chmod.'/'.$file;
					}
					closedir($dh);
				}
			}
		}
		/*if (strpos($chmod,'themes/default')!==false)
		{
			foreach (array_keys($themes) as $theme)
			{
				$_chmod=str_replace('themes/default','themes/'.$theme,$chmod);
				if (!file_exists(get_file_base().'/'.$_chmod)) continue;
				if (!is_writable_wrap(get_file_base().'/'.$_chmod))
					afm_set_perms($_chmod,true);
			}
		} else
		{*/
			if (!file_exists(get_file_base().'/'.$chmod)) continue;
			if (!is_writable_wrap(get_file_base().'/'.$chmod))
				afm_set_perms($chmod,true);
		//}
	}

	$super_out='';

	foreach ($GLOBALS['ATTACHED_MESSAGES_RAW'] as $_error)
	{
		$error=$_error[0];
		if (is_object($error)) $error=$error->evaluate();
		$super_out.='<p>'.$error.'</p>';
	}

	$super_out.='<p>'.do_lang('SUCCESS').'</p>';

	$GLOBALS['SUPRESS_ERROR_DEATH']=false;

	return $super_out;
}

/**
 * Tell the user about any modules that need moving again (because the ocp ones haven't moved).
 *
 * @return array		Pair: HTML list of moved files, raw list
 */
function move_modules()
{
	$out='';
	$outr=array();

	$zones=find_all_zones();
	foreach ($zones as $zone)
	{
		$pages=find_all_pages($zone,'modules');
		foreach (array_keys($pages) as $page)
		{
			// See if this isn't the true home of the module
			foreach ($zones as $zone2)
			{
				$_path_a=$zone2.'/pages/modules/'.$page.'.php'; // potential true home
				$_path_b=$zone.'/pages/modules/'.$page.'.php'; // where it is now
				$path_a=zone_black_magic_filterer(get_file_base().'/'.$_path_a);
				$path_b=zone_black_magic_filterer(get_file_base().'/'.$_path_b);
				if (($zone2!=$zone) && (file_exists($path_a)) && (filemtime($path_a)>=filemtime($path_b)))
				{
					if (($page=='filedump') && ($zone2=='cms')) continue; // This has moved between versions

					$out.='<li><input type="checkbox" name="'.uniqid('').'" value="move:'.escape_html($_path_a.':'.$_path_b).'" /> '.do_lang('FILE_MOVED','<kbd>'.escape_html($page).'</kbd>','<kbd>'.escape_html($zone2).'</kbd>','<kbd>'.escape_html($zone).'</kbd>').'</li>';
					$outr[]=$path_b;
				}
			}
		}
	}

	return array($out,$outr);
}

/**
 * Find any excess permissions
 *
 * @param  array		Permissions that DO need to be set
 * @param  string		Where we are searching under
 * @return string		Messages
 */
function check_excess_perms($array,$rel='')
{
	$out='';

	$dir=get_file_base().'/'.$rel.'/';

	$dh=@opendir($dir);
	if ($dh!==false)
	{
		while (($file=readdir($dh))!==false)
		{
			if (($file=='.') || ($file=='..')) continue;

			$is_dir=@is_dir($dir.$file);

			if ((should_ignore_file($dir.$file,IGNORE_ACCESS_CONTROLLERS)) && ($is_dir)) continue;

			$relpath=$rel.(($rel=='')?'':'/').$file;
			$ok=(in_array($relpath,$array)) || (in_array(preg_replace('#^[^/]+/#','site/',$relpath),$array)) || (in_array(preg_replace('#^themes/[^/]+/#','themes/default/',$relpath),$array));
			if ((is_writable_wrap($dir.$file)) && ((!function_exists('posix_getuid')) || (fileowner($dir.$file)!=posix_getuid())))
			{
				if (!$ok)
				{
					$out.='<li>'.do_lang('FU_NEEDS_UNCHMOD','<kbd>'.escape_html($rel.(($rel=='')?'':'/').$file)).'</kbd></li>';
				}
			}

			if (($is_dir) && (!$ok)) $out.=check_excess_perms($array,escape_html($rel.(($rel=='')?'':'/').$file));
		}
	}

	return $out;
}

/**
 * Check for out-dated files.
 *
 * @param  SHORT_TEXT	The directory we are scanning relative to
 * @param  SHORT_TEXT	The directory (relative) we are scanning
 * @param  array 			Unserialised data/files.dat
 * @param  array 			A list of the contents of our addon registry hook files
 * @param  boolean 		Whether merging of CSS changes is allowed
 * @return array			Tuple of various kinds of outdated/missing files
 */
function check_outdated__handle_overrides($dir,$rela,&$master_data,&$hook_files,$allow_merging)
{
	$outdated__outdated_original_and_override='';
	$outdated__possibly_outdated_override='';
	$outdated__missing_original_but_has_override='';
	$outdated__uninstalled_addon_but_has_override='';

	require_code('diff');
	require_code('files');

	$dh=@opendir($dir);
	if ($dh!==false)
	{
		while (($file=readdir($dh))!==false)
		{
			if (should_ignore_file($rela.$file,IGNORE_ACCESS_CONTROLLERS | IGNORE_THEMES | IGNORE_USER_CUSTOMISE)) continue;
			if ($file=='files.dat') continue;
			if ($file=='files_previous.dat') continue;

			$is_dir=@is_dir($dir.$file);

			if (($is_dir) && (is_readable($dir.$file)))
			{
				list($_outdated__outdated_original_and_override,$_outdated__possibly_outdated_override,$_outdated__missing_original_but_has_override,$_outdated__uninstalled_addon_but_has_override)=check_outdated__handle_overrides($dir.$file.'/',$rela.$file.'/',$master_data,$hook_files,$allow_merging);
				$outdated__outdated_original_and_override.=$_outdated__outdated_original_and_override;
				$outdated__possibly_outdated_override.=$_outdated__possibly_outdated_override;
				$outdated__missing_original_but_has_override.=$_outdated__missing_original_but_has_override;
				$outdated__uninstalled_addon_but_has_override.=$_outdated__uninstalled_addon_but_has_override;
			} else
			{
				if (strpos($rela,'_custom')!==false)
				{
					$equiv_file=get_file_base().'/'.str_replace('_custom','',$rela).$file;
					if ((!file_exists($equiv_file)) && (substr($rela,0,7)=='themes/') && (substr_count($rela,'/')==3))
					{
						$equiv_file=get_file_base().'/'.str_replace('_custom','',preg_replace('#themes/[^/]*/#','themes/default/',$rela)).$file;
					}
					if (file_exists($equiv_file))
					{
						if ($allow_merging)
						{
							if (file_exists($dir.$file.'.editfrom')) // If we edited-from, then we use that to do the compare
							{
								$hash_on_disk=sprintf('%u',crc32(preg_replace('#[\r\n\t ]#','',file_get_contents($dir.$file.'.editfrom',FILE_BINARY))));
								$only_if_noncustom=false;
							} else
							{
								$hash_on_disk=sprintf('%u',crc32(preg_replace('#[\r\n\t ]#','',file_get_contents($dir.$file,FILE_BINARY))));
								$only_if_noncustom=true;
							}
							$_true_hash=sprintf('%u',crc32(preg_replace('#[\r\n\t ]#','',file_get_contents($equiv_file,FILE_BINARY))));
							if (array_key_exists($file,$master_data)) // Get hash from perfection table
							{
								$true_hash=$master_data[$rela.$file][0];
								if ($true_hash!=$_true_hash)
								{
									$outdated__outdated_original_and_override.='<li><kbd>'.escape_html($rela.$file).'</kbd></li>';
									unset($master_data[$rela.$file]);
									continue;
								}
							} else // Get hash from non-overridden file (equiv file)
							{
								if ($only_if_noncustom) $true_hash=NULL; // Except we can't as we're not looking at the .editfrom and thus can't expect equality
								else $true_hash=$_true_hash;
							}

							if ((!is_null($true_hash)) && ($hash_on_disk!=$true_hash))
							{
								if ((function_exists('diff_compute_new')) && (substr($file,-4)=='.css') && ($true_hash!==2) && (file_exists($dir.$file.'.editfrom')) && (is_writable_wrap($dir.$file)))
								{
									$new=diff_compute_new($equiv_file,$dir.$file.'.editfrom',$dir.$file);
									$myfile=fopen($dir.$file.'.'.strval(time()),'wb');
									fwrite($myfile,file_get_contents($dir.$file));
									fclose($myfile);
									$myfile=fopen($dir.$file,'wb');
									fwrite($myfile,$new);
									fclose($myfile);
									$outdated__possibly_outdated_override.='<li><kbd>'.escape_html($rela.$file).'</kbd> '.do_lang('AUTO_MERGED').'</li>';
									$myfile=fopen($dir.$file.'.editfrom','wb');
									fwrite($myfile,file_get_contents($equiv_file));
									fclose($myfile);
								} else
								{
									$outdated__possibly_outdated_override.='<li><kbd>'.escape_html($rela.$file).'</kbd></li>';
								}
							}
						} else
						{
							$outdated__possibly_outdated_override.='<li><kbd>'.escape_html($rela.$file).'</kbd></li>';
						}

						unset($master_data[$rela.$file]);
					} elseif (array_key_exists(str_replace('_custom','',preg_replace('#themes/[^/]*/#','themes/default/',$rela)).$file,$master_data))
					{
						$known_in_addon=false;
						foreach ($hook_files as $hook_file)
						{
							if (strpos($hook_file,str_replace('themes/default/css/','',str_replace('themes/default/templates/','',str_replace('_custom','',preg_replace('#themes/[^/]*/#','themes/default/',$rela)))).$file)!==false)
							{
								$known_in_addon=true;
								break;
							}
						}
						if ($known_in_addon)
						{
							$outdated__missing_original_but_has_override.='<li><kbd>'.escape_html($rela.$file).'</kbd></li>';
						} else
						{
							$outdated__uninstalled_addon_but_has_override.='<li><kbd>'.escape_html($rela.$file).'</kbd></li>';
						}
						unset($master_data[$rela.$file]);
					}
				}
			}
		}
	}

	return array($outdated__outdated_original_and_override,$outdated__possibly_outdated_override,$outdated__missing_original_but_has_override,$outdated__uninstalled_addon_but_has_override);
}

/**
 * Check for alien files.
 *
 * @param  array			List of files from old version
 * @param  array			List of verbatim files
 * @param  SHORT_TEXT	The directory we are scanning relative to
 * @param  SHORT_TEXT	The directory (relative) we are scanning
 * @param  boolean		Whether to give raw output (no UI)
 * @return string			HTML list of alien files
 */
function check_alien($old_files,$files,$dir,$rela='',$raw=false)
{
	$alien='';

	$dh=@opendir($dir);
	if ($dh!==false)
	{
		if ($rela=='')
		{
			$old_addons_now_gone=array(
				'sources/hooks/systems/addon_registry/core_installation_uninstallation.php',
			);
			$modules_moved_intentionally=array(
				'collaboration/pages/modules/filedump.php',
			);
			foreach (array_merge($old_addons_now_gone,$modules_moved_intentionally) as $x)
			{
				if (file_exists(get_file_base().'/'.$x))
				{
					$alien.='<li>';
					if (!$raw) $alien.='<input checked="checked" type="checkbox" name="'.uniqid('').'" value="delete:'.escape_html($x).'" /> ';
					$alien.='<kbd>'.escape_html($x).'</kbd></li>';
				}
			}
		}
		while (($file=readdir($dh))!==false)
		{
			if (should_ignore_file($rela.$file,IGNORE_ACCESS_CONTROLLERS | IGNORE_THEMES | IGNORE_USER_CUSTOMISE)) continue;
			if ($rela.$file=='data/images') continue;
			if ($rela.$file=='data/areaedit/plugins/SpellChecker/aspell') continue;

			$is_dir=@is_dir($dir.$file);
			if (!is_readable($dir.$file)) continue;

			if ($file=='index.php') continue; // New zone

			if ($is_dir)
			{
				if (!file_exists($dir.$file.'/info.php'))
				{
					if (($rela=='') && (!file_exists($dir.$file.'/pages'))) // Scan to make sure it's not some other system placed under the webroot
					{
						$ok=false;
						foreach (array_keys($files) as $f)
						{
							if (substr($f,0,strlen($rela.$file.'/'))==$rela.$file.'/')
							{
								$ok=true;
								break;
							}
						}
						if (!$ok) continue;
					}

					$alien.=check_alien($old_files,$files,$dir.$file.'/',$rela.$file.'/',$raw);
				}
			} else
			{
				if (!array_key_exists($rela.$file,$files))
				{
					if (strpos($rela,'pages/modules')!==false) // Check it isn't a moved module
					{
						$zones=find_all_zones();
						$matches=array();
						preg_match('#(.*)pages/modules#',$rela,$matches);
						$current_zone=str_replace('/','',$matches[1]);
						foreach ($zones as $zone)
						{
							if (array_key_exists(str_replace($current_zone.'/',$zone.'/',$rela.$file),$files))
								continue 2;
						}
					}
					$disabled='';
					//if ((is_dir($dir.'/'.$file=='')) && ()) Not needed as this is only for files
					$checked='';

					if (array_key_exists($rela.$file,$old_files)) $checked='checked="checked" ';
					$alien.='<li>';
					if (!$raw) $alien.='<input '.$disabled.$checked.'type="checkbox" name="'.uniqid('').'" value="delete:'.escape_html($rela.$file).'" /> ';
					$alien.='<kbd>'.escape_html($rela.$file).'</kbd></li>';
				}
			}
		}
	}

	return $alien;
}

/**
 * Move/delete certain selected things, in follow up to an integrity scan.
 */
function _integrity_scan()
{
	foreach (array_keys($_POST) as $key)
	{
		$val=post_param($key);
		if (strpos($val,':')!==false)
		{
			$bits=explode(':',$val);
			if ($bits[0]=='delete')
			{
				afm_delete_file($bits[1]);
			}
			elseif ($bits[0]=='move')
			{
				afm_delete_file($bits[2]);
				afm_move($bits[1],$bits[2]);
			}
		}
	}
}

/**
 * Version specific upgrading. These are things that are relatively major structural changes and therefore will get done outside the module upgrade system.
 *
 * @return boolean		Whether anything was done
 */
function version_specific()
{
	// Version specific (rather than component specific) upgrading
	$version_files=ocp_version_number();
	$_version_database=get_value('version');
	$version_database=floatval($_version_database);
	if (is_null($_version_database)) $version_database=2.1; // Either 2.0 or 2.1, and they are equivalent in terms of what we need to do
	if ($version_database<$version_files)
	{
		if ($version_database<2.5)
		{
			$GLOBALS['SITE_DB']->query('DELETE FROM '.get_table_prefix().'chat_messages');
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'galleries'),array('module_the_name'=>'images'));
			$GLOBALS['SITE_DB']->query_update('group_page_access',array('page_name'=>'galleries'),array('page_name'=>'images'));
			$GLOBALS['SITE_DB']->alter_table_field('zones','zone_wide','?BINARY');
			$GLOBALS['SITE_DB']->alter_table_field('theme_images','id','SHORT_TEXT');
			$GLOBALS['SITE_DB']->refresh_field_definition('URLPATH');
			$GLOBALS['SITE_DB']->query('ALTER TABLE '.get_table_prefix().'translate TYPE=MYISAM'); // Just in case it's not
			$GLOBALS['SITE_DB']->create_index('translate','#search',array('text_original'));

			$trans4=insert_lang(do_lang('A_SITE_ABOUT','???'),1);
			$trans8=insert_lang(do_lang('GUIDES'),1);
			$GLOBALS['SITE_DB']->query_insert('zones',array(/*'zone_title'=>insert_lang(do_lang('SITE'),1),*/'zone_name'=>'membersonly','zone_default_page'=>'start','zone_header_text'=>$trans4,'zone_theme'=>'-1','zone_wide'=>0,'zone_require_session'=>0));
			$GLOBALS['SITE_DB']->query_insert('zones',array(/*'zone_title'=>insert_lang(do_lang('GUIDES'),1),*/'zone_default_page'=>'userguide','zone_header_text'=>$trans8,'zone_theme'=>'-1','zone_wide'=>0,'zone_require_session'=>0));
		}
		if ($version_database<3.0)
		{
			fu_rename_zone('membersonly','site');
			fu_rename_zone('admincentre','adminzone');
			if (file_exists(get_file_base().'/collaboration')) fu_rename_zone('supermembercentre','collaboration');
			fu_rename_zone('membercentre','site',true); // Merged into 'site' (formerly membersonly)
			actual_delete_zone_lite('seedy');
			$GLOBALS['SITE_DB']->query_insert('zones',array('zone_name'=>'cms','zone_title'=>insert_lang(do_lang('CMS'),1),'zone_default_page'=>'cms','zone_header_text'=>insert_lang(do_lang('CMS'),1),'zone_theme'=>'-1','zone_wide'=>0,'zone_require_session'=>1));

			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'admin_cleanup'),array('module_the_name'=>'admin_caches'));
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'seedy_page'),array('module_the_name'=>'cedi'));
			$GLOBALS['SITE_DB']->query_update('attachment_refs',array('r_referer_type'=>'cedi_page'),array('r_referer_type'=>'seedy_page'));
			$GLOBALS['SITE_DB']->query_update('attachment_refs',array('r_referer_type'=>'cedi_post'),array('r_referer_type'=>'seedy_post'));
			$modules_gone=array('seedy_move','seedy_changes','seedy_edit_page','seedy_manage_tree','seedy_move','seedy_post','seedy_show_tree','seedy_merge','admin_seedy','admin_pages','admin_ftp_downloads','admin_timezone','admin_modules','admin_ocf_moderator_logs','admin_submitban');
			foreach ($modules_gone as $module)
			{
				$GLOBALS['SITE_DB']->query_delete('modules',array('module_the_name'=>$module),'',1);
			}
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'galleries'),array('module_the_name'=>'images'),'',1);
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'admin_sitetree'),array('module_the_name'=>'admin_comcode_pages'),'',1);
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'admin_addons'),array('module_the_name'=>'admin_mods'),'',1);
			$GLOBALS['SITE_DB']->query_update('modules',array('module_the_name'=>'admin_awards'),array('module_the_name'=>'admin_dotws'),'',1);
		}
		if ($version_database<4.0)
		{
			$GLOBALS['SITE_DB']->query('ALTER TABLE '.get_table_prefix().'translate CHANGE id id INT(10) UNSIGNED AUTO_INCREMENT');
		}
		if ($version_database<5.1)
		{
			// Installaton code got moved over
			$sitetree_version=$GLOBALS['SITE_DB']->query_value('modules','module_version',array('module_the_name'=>'admin_sitetree'));
			$GLOBALS['SITE_DB']->query_update('modules',array('module_version'=>$sitetree_version),array('module_the_name'=>'cms_comcode_pages'),'',1);
		}
		if ($version_database<8.0)
		{
			actual_delete_zone_lite('personalzone');
		}
		set_value('version',float_to_raw_string($version_files));

		return true;
	}

	return false;
}

/**
 * Rename a zone in the database and move any custom pages in it.
 *
 * @param  ID_TEXT		The old name of the zone
 * @param  ID_TEXT		The new name of the zone
 * @param  boolean		Whether to assume the main zone row has already been renamed as part of a wider editing operation
 */
function fu_rename_zone($zone,$new_zone,$dont_bother_with_main_row=false)
{
	if (function_exists('set_time_limit')) @set_time_limit(0);

	require_code('zones2');
	if (file_exists(get_file_base().'/sources/zones3.php')) require_code('zones3');
	actual_rename_zone_lite($zone,$new_zone,$dont_bother_with_main_row);
	$pages=find_all_pages_wrap($zone,true,false,FIND_ALL_PAGES__ALL);
	foreach ($pages as $page=>$type)
	{
		$path=get_file_base().'/'.$zone.'/pages/'.$type.'/'.$page;
		$new_path=get_file_base().'/'.$new_zone.'/pages/'.$type.'/'.$page;
		if ((is_writable_wrap($path)) && (is_writable_wrap($new_path)))
		{
			rename($path,$new_path);
			sync_file_move($path,$new_path);
		}
	}
}

/**
 * Upgrade all modules.
 *
 * @return string		List of upgraded/installed modules/blocks
 */
function upgrade_modules()
{
	$out='';

	require_code('zones2');
	if (file_exists(get_file_base().'/sources/zones3.php')) require_code('zones3');

	$ret=upgrade_module('adminzone','admin_version');
	if ($ret==1) $out.='<li>'.do_lang('FU_UPGRADED_MODULE','<kbd>admin_version</kbd>').'</li>';

	$zones=find_all_zones();
	if (!in_array('adminzone',$zones)) $zones[]='adminzone';
	if (!in_array('cms',$zones)) $zones[]='cms';
	if (!in_array('site',$zones)) $zones[]='site';
	foreach ($zones as $zone)
	{
		$modules=find_all_modules($zone);
		foreach ($modules as $module=>$type)
		{
			$ret=upgrade_module($zone,$module);
			if ($ret==1) $out.='<li>'.do_lang('FU_UPGRADED_MODULE','<kbd>'.escape_html($module).'</kbd>').'</li>';
			elseif ($ret==-2)
			{
				if ($type=='modules_custom') continue;

				if (reinstall_module($zone,$module))
				{
					$out.='<li>'.do_lang('FU_INSTALLED_MODULE','<kbd>'.escape_html($module).'</kbd>').'</li>';
				}
			}
		}
	}

	require_code('zones2');
	if (file_exists(get_file_base().'/sources/zones3.php')) require_code('zones3');
	$blocks=find_all_blocks();
	foreach ($blocks as $block=>$type)
	{
		$ret=upgrade_block($block);
		if ($ret==1) $out.='<li>'.do_lang('FU_UPGRADED_BLOCK','<kbd>'.escape_html($block).'</kbd>').'</li>';
		elseif ($ret==-2)
		{
			if ($type=='sources_custom') continue;

			if (reinstall_block($block))
			{
				$out.='<li>'.do_lang('FU_INSTALLED_BLOCK','<kbd>'.escape_html($block).'</kbd>').'</li>';
			}
		}
	}

	return $out;
}

/**
 * Upgrade OCF if appropriate.
 *
 * @return boolean		Whether anything was done
 */
function ocf_upgrade()
{
	$version_files=ocp_version_number();
	$version_database=floatval(get_value('ocf_version'));
	if (is_null($version_database)) $version_database=2.1;

	if ($version_files!=$version_database)
	{
		global $SITE_INFO;
		$SITE_INFO['db_forums']=$SITE_INFO['db_site'];
		$SITE_INFO['db_forums_host']=array_key_exists('db_site_host',$SITE_INFO)?$SITE_INFO['db_site_host']:'localhost';
		$SITE_INFO['db_forums_user']=array_key_exists('db_site_user',$SITE_INFO)?$SITE_INFO['db_site_user']:'root';
		$SITE_INFO['db_forums_password']=array_key_exists('db_site_password',$SITE_INFO)?$SITE_INFO['db_site_password']:'';
		$GLOBALS['FORUM_DB']=$GLOBALS['SITE_DB'];

		require_code('forum/ocf');
		$GLOBALS['FORUM_DRIVER']=object_factory('forum_driver_ocf');
		$GLOBALS['FORUM_DRIVER']->connection=$GLOBALS['SITE_DB'];

		require_code('ocf_install');
		install_ocf($version_database);

		set_value('ocf_version',float_to_raw_string($version_files));

		return true;

	} return false;
}

/**
 * Make sure the site database has the correct character set internally. ocPortal already ensures the communication charset makes sense for what ocPortal is using, this makes sure it stores sanely too.
 */
function fix_mysql_database_charset()
{
	global $SITE_INFO;
	if (!array_key_exists('database_charset',$SITE_INFO)) $SITE_INFO['database_charset']=(strtolower(get_charset())=='utf-8')?'utf8':'latin1';
	change_mysql_database_charset($SITE_INFO['database_charset'],$GLOBALS['SITE_DB']);
}

/**
 * Refresh a MySQL database's character set is correct.
 *
 * @param  ID_TEXT		Character set
 * @param  object			Database
 * @param  boolean		Whether to let MySQL do a reencoding of the characters (if this is set to false we actually are adjusting the interpretation whilst leaving the disk data the same)
 */
function change_mysql_database_charset($new_charset,$db,$reencode=false)
{
	@ob_end_clean();

	if (function_exists('set_time_limit')) @set_time_limit(0);

	$bak=$GLOBALS['NO_DB_SCOPE_CHECK'];
	$GLOBALS['NO_DB_SCOPE_CHECK']=true;

	$fulltext_indices=$GLOBALS['SITE_DB']->query_select('db_meta_indices',array('*'));
	foreach ($fulltext_indices as $index)
	{
		if (substr($index['i_name'],0,1)=='#')
		{
			echo 'Deleting index: '.$index['i_table'].'/'.$index['i_name']."\n";
			flush();

			$GLOBALS['SITE_DB']->delete_index_if_exists($index['i_table'],$index['i_name']);
		}
	}

	echo 'Changing overall character set for database'."\n";
	flush();
	$db->query('ALTER DATABASE '.get_db_site().' CHARACTER SET '.$new_charset);

	$remap=$db->static_ob->db_get_type_remap();

	$tables=collapse_1d_complexity('m_table',$db->query_select('db_meta',array('DISTINCT m_table')));
	foreach ($tables as $table)
	{
		echo 'Changing character sets for: '.$table."\n";
		flush();

		$fields=$db->query_select('db_meta',array('m_name','m_table','m_type'),array('m_table'=>$table));

		$db->query('ALTER TABLE '.$db->get_table_prefix().$table.' CHARACTER SET '.$new_charset);
		foreach ($fields as $field)
		{
			$db_type=strtoupper($remap[str_replace(array('*','?'),array('',''),$field['m_type'])]);
			if ((strpos($db_type,'TEXT')!==false) || (strpos($db_type,'CHAR')!==false))
			{
				$db_type_temp=$db_type;
				if (substr($db_type,0,4)=='CHAR') $db_type_temp=str_replace('CHAR','BINARY',$db_type);
				elseif (substr($db_type,0,7)=='VARCHAR') $db_type_temp=str_replace('VARCHAR','VARBINARY',$db_type);
				elseif (substr($db_type,0,4)=='LONGTEXT') $db_type_temp=str_replace('LONGTEXT','LONGBLOB',$db_type);

				foreach ($reencode?array($db_type):array($db_type_temp,$db_type) as $i=>$db_type)
				{
					$query='ALTER TABLE '.$db->get_table_prefix().$table.' CHANGE '.$field['m_name'].' '.$field['m_name'].' '.$db_type;
					if ($i==1 || $reencode) $query.=' CHARACTER SET '.$new_charset;
					$query.=' '.((strpos($field['m_name'],'?')!==false)?'NULL':'NOT NULL');
					$db->query($query);
				}
			}
		}
	}

	foreach ($fulltext_indices as $index)
	{
		if (substr($index['i_name'],0,1)=='#')
		{
			echo 'Rebuilding index: '.$index['i_table'].'/'.$index['i_name']."\n";
			flush();

			$GLOBALS['SITE_DB']->create_index($index['i_table'],$index['i_name'],explode(',',$index['i_fields']));
		}
	}

	$GLOBALS['NO_DB_SCOPE_CHECK']=$bak;
}

/**
 * Upgrade all themes.
 *
 * @return  string	HTML output
 */
function upgrade_themes()
{
	$test_run=(get_param_integer('live_run',0)==0);

	$str='';

	$str.='<h2>Theme upgrade: '.($test_run?'test run':'live results').'</h2>';

	require_code('themes2');
	$themes=find_all_themes();
	$has_errors=false;
	foreach (array_keys($themes) as $theme)
	{
		$from=round(ocp_version_number())-1;
		$to=ocp_version_number();
		list($errors,$successes)=upgrade_theme($theme,$from,$to,$test_run);

		$str.='<h3>'.escape_html($theme).'</h3>';

		foreach ($errors as $error)
		{
			$str.='<p style="background: #DDD; margin: 1em; padding: 1em">&#x2717; '.$error->evaluate().'</p>';
			$has_errors=true;
		}

		foreach ($successes as $success)
		{
			$str.='<p style="background: #DDD; margin: 1em; padding: 1em">&#x2713; '.$success->evaluate().'</p>';
		}
	}

	if ($test_run)
	{
		if ($has_errors)
		{
			$str.='<p>'.do_lang('FU_THEME_ERRORS').'</p>';
		}

		$l_theme_upgrade=fu_link('upgrader.php?type=theme_upgrade&live_run=1',do_lang('FU_THEME_UPGRADE_FINAL'));
		$str.=$l_theme_upgrade;
	}

	return $str;
}

/**
 * Upgrade a theme automatically, using hand-coded migration arrays.
 *
 * @param   ID_TEXT	Theme to be upgraded
 * @param   float		From version
 * @param   float		Target version
 * @param   boolean	Whether executing a test run (i.e. not do anything)
 * @return  array		A pair: List of errors, List of successes
 */
function upgrade_theme($theme,$from_version,$to_version,$test_run=true)
{
	$errors=array();
	$successes=array();

	if (!$test_run)
	{
		require_code('abstract_file_manager');
		force_have_afm_details();
	}

	$css_replace__single_match=array();
	$css_prepend__single_match=array();
	$css_append__single_match=array();
	$css_replace__multi_match=array();
	$css_prepend__multi_match=array();
	$css_append__multi_match=array();
	$css_file_append=array();
	$theme_images_new=array();
	$theme_images_renames=array();
	$templates_replace=array();
	$templates_rename=array();
	$templates_borked=array();

	if (($from_version<8.0) && ($to_version>=8.0) && ($to_version<9.0))
	{
		$css_recognition_string='2004-2011'; // Must be defined. Ensures theme is right version.

		$css_replace__multi_match=array(
			'*'=>array(
				"2004-2011"=>"2004-2012",
				"gradiant"=>"gradient",
				"\$IMG,"=>"\$IMG;,",
				"url(\""=>"url('",
				"\")"=>"')",
			),
			'global.css'=>array(
				"comments_outer"=>"comments_posting_form_outer",
				"comments_inner"=>"comments_posting_form_inner",
				"comments_end"=>"comments_posting_form_end",
				"comments_emoticons"=>"comments_posting_form_emoticons",
				"comments_links"=>"comments_posting_form_links",
			),
		);

		$css_replace__single_match=array(
			'adminzone.css'=>array(
				"template_edit_guid__true"=>"template_edit_guid_1",
				"template_edit_guid__false"=>"template_edit_guid_0",
			),
			'calendar.css'=>array(
				".calendar_week_hour {\n	width: 90px;\n}"=>".calendar_week_hour {\n	width: 90px;\n	height: 30px;\n	border: 1px solid #6b81a1; /* {\$,dottedborder.border, 95% (seed sat_to 33) + 5% !W/B}*/\n}",
			),
			'chat.css'=>array(
				".chat_lobby_convos_area {\n}"=>".chat_lobby_convos_area {\n	overflow: hidden;\n	width: 100%;\n}",
			),
			'global.css'=>array(
				"tt, kbd, samp {\n	font-size: 1.25em;\n	font-weight: bold;\n}"=>"tt, kbd, samp {\n	font-weight: bold;\n}",
				"input[type=\"text\"],input[type=\"password\"],textarea,select { /* Normally a browser default, but gets inherited on some phones */"=>"input[type=\"text\"],input[type=\"password\"],input[type=\"color\"],input[type=\"email\"],input[type=\"number\"],input[type=\"range\"],input[type=\"search\"],input[type=\"tel\"],input[type=\"url\"],textarea,select { /* Normally a browser default, but gets inherited on some phones */",
				".breadcrumbs {\n	padding: 5px 0 0 0;\n	float: {!en_right};\n	margin-left: 5px;\n	zoom: 1;\n}"=>".breadcrumbs {\n	padding: 5px 0 0 0;\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		float: {!en_right};\n		margin-left: 5px;\n	{+END}\n	zoom: 1;\n}\n\n.breadcrumbs abbr {\n	white-space: nowrap;\n}",
				".standardbox_wrap_panel img {\n	max-width: 100%;\n}"=>".standardbox_wrap_panel img {\n	max-width: 98%;\n}",				".standardbox_classic, .standardbox_links_classic {"=>".standardbox_classic, .standardbox_wrap_classic .standardbox_links_classic {",
				".scale_down { /* {\$,Membership of this class is used as a tag to turn on image scaling} */\n	max-width: 100%;\n}"=>".scale_down { /* {\$,Membership of this class is used as a tag to turn on image scaling} */\n	max-width: 100%;\n	box-sizing: border-box;\n}",
				"ul.compact_list {"=>"ul.compact_list, ol.compact_list {",
				"ul.compact_list li {"=>"ul.compact_list li, ol.compact_list li {",
				"ul.spaced_list, .spaced_list ul {"=>"ul.spaced_list, .spaced_list ul, ol.spaced_list, .spaced_list ol {",
				".trinav_right {\n	float: right;\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		margin-left: 10px;\n	{+END}\n	{+START,IF,{\$MOBILE}}\n		width: 33%;\n	{+END}\n	text-align: right;\n}\n"=>".trinav_right {\n	float: right;\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		margin-left: 10px;\n		margin-right: 26px;\n	{+END}\n	{+START,IF,{\$MOBILE}}\n		width: 33%;\n	{+END}\n	text-align: right;\n}\n",
				".category_entry {\n	padding: 6px 0;\n	margin: 6px 0;\n	clear: both;\n}"=>".category_entry {\n	padding: 6px 0;\n	margin: 6px 0;\n	clear: both;\n	overflow: hidden;\n	width: 100%;\n}",
				"ul.actions_list li, ul.actions_list_compact li, ul.actions_list_super_compact li {\n	padding: 0;\n	margin: 0;\n	list-style-type: none;\n}"=>"ul.actions_list li, ul.actions_list_compact li, ul.actions_list_super_compact li {\n	padding: 0;\n	margin: 0;\n	list-style-type: none;\n	list-style-image: none;\n}",
				".non_link:link,\n.non_link:visited,\n.non_link:hover,\n.non_link:active {\n	color: #0d1522; /* {\$,wizard, 20% seed + 80% !W/B} */\n	text-decoration: none;\n	cursor: default;\n}"=>".non_link,\n.non_link:link,\n.non_link:visited,\n.non_link:hover,\n.non_link:active {\n	color: #0d1522 !important; /* {\$,wizard, 20% seed + 80% !W/B} */\n	text-decoration: none;\n	cursor: default;\n}",
				"text-shadow: 1px 1px 1px #000000; /* {\$,wizard, 100% !W/B} */\n	margin: 0 2px;\n}"=>"text-shadow: 1px 1px 1px #000000; /* {\$,wizard, 100% !W/B} */\n	margin: 0 2px;\n	overflow: visible; /* stops button padding on IE7 */\n}",
				".inline_image {\n	vertical-align: top;\n}\n\n.inline_image_2 {\n	vertical-align: middle;\n}\n\n.inline_image_3 {\n	vertical-align: baseline;\n}\n\n.inline_image_4 {\n	margin-top: -4px;\n}"=>".inline_image {\n	vertical-align: top !important;\n}\n\n.inline_image_2 {\n	vertical-align: middle !important;\n}\n\n.inline_image_3 {\n	vertical-align: baseline !important;\n}\n\n.inline_image_4 {\n	margin-top: -4px !important;\n}",
				".gallery_media_full_expose {\n	overflow: hidden;\n	width: 100%;\n	outline: 0;\n	margin: {\$?,{\$MOBILE},1,3}em 0;\n}\n\n.gallery_media_full_expose {\n	text-align: center;\n}"=>".gallery_media_full_expose {\n	overflow: hidden;\n	width: 100%;\n	outline: 0;\n	margin: {\$?,{\$MOBILE},1,3}em 0;\n	text-align: center;\n	position: relative;\n}",
				".gallery_media_full_expose img, .img_thumb {\n	border: 1px solid #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	-webkit-box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	-moz-box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	max-width: 100%;\n}"=>".gallery_media_full_expose img, .img_thumb {\n	border: 1px solid #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	-webkit-box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	-moz-box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	box-shadow: 3px 3px 10px #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	max-width: 100%;\n	box-sizing: border-box;\n}",
				".form_field_name {\n	margin: 4px 0;\n}"=>".form_field_name {\n	margin: 4px;\n	display: inline-block;\n}",
				".input_author, .input_username, .input_colour, .input_email,\n"=>".input_author, .input_username, .input_colour, .input_email, .input_codename,\n",
				".input_author_required, .input_username_required, .input_colour_required, .input_email_required,\n"=>".input_author_required, .input_username_required, .input_colour_required, .input_email_required, .input_codename_required,\n",
				".members_viewing {\n	border-top: 0;\n	padding: 4px;\n	text-indent: 25px;\n	padding-{!en_left}: 0;\n}"=>".members_viewing {\n	padding: 4px;\n	text-indent: 25px;\n	padding-{!en_left}: 0;\n}\n\n.ocf_topic_0 .members_viewing {\n	border-top: 0;\n}",
				".post .post_edit_link {\n}"=>".post .post_action_link {\n}\n\n.post .post_thread_children {\n	margin-top: 1em;\n	{+START,IF,{\$MOBILE}}\n		margin-left: 7px;\n	{+END}\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		margin-left: 20px;\n	{+END}\n}\n\n.post .ocf_post_buttons {\n	margin-top: 1.3em;\n}\n\n.ocf_post_buttons a {\n	opacity: 0.0;\n	-webkit-transition-property : opacity;\n	-webkit-transition-duration : 0.5s;\n	-moz-transition-property : opacity;\n	-moz-transition-duration : 0.5s;\n	-o-transition-property : opacity;\n	-o-transition-duration : 0.5s;\n	transition-property : opacity;\n	transition-duration : 0.5s;\n}\n\n.ocf_post_buttons a[rel=\"add reply\"] {\n	opacity: 1.0;\n}\n\n.ocf_post_buttons:hover a {\n	opacity: 1.0;\n}\n\n.post_show_more {\n	text-align: center;\n	border: 1px dashed #c1cee3; /* {\$,wizard, 100% lightborder} */\n	border-bottom-left-radius: 40px;\n	border-bottom-right-radius: 40px;\n	padding: 15px;\n	font-weight: bold;\n	font-size: 0.85em;\n}\n\n.post .post_show_more {\n	margin-left: 20px;\n}",
				"ul.sitemap {\n	list-style-type: none;\n	margin-left: 0;\n	padding-left: 0;\n}"=>"ul.sitemap {\n	list-style-type: none;\n	list-style-image: none;\n	margin-left: 0;\n	padding-left: 0;\n}",
				".rating_inner {\n	text-align: center;\n	white-space: nowrap;\n}"=>".RATING_BOX .rating_inner {\n	text-align: center;\n}\n\n.RATING_INLINE_DYNAMIC .rating_inner, .RATING_INLINE_DYNAMIC form {\n	display: inline;\n}\n\n.post_action_link .RATING_INLINE_DYNAMIC {\n	padding-left: 20px;\n}\n\n.rating_inner {\n	white-space: nowrap;\n}\n\n.rating_inner img {\n	cursor: pointer;\n}",
				".tab {\n	float: left;\n	background: url('{\$IMG,tab}');\n	padding: 3px 5px 0 5px;\n	height: 20px;\n	text-align: center;\n	cursor: pointer;\n}"=>".tab {\n	float: left;\n	background: url('{\$IMG;,tab}') !important;\n	padding: 3px 7px 0 7px !important;\n	height: 20px;\n	text-align: center;\n	cursor: pointer;\n}",
				".tab_active, .tab:hover {\n	font-weight: bold;\n}"=>".tab_active {\n	font-weight: bold;\n}\n\n.tab:hover {\n	text-decoration: underline !important;\n}",
				".nl li {\n	display: block;\n	margin-{!en_left}: 0;\n	padding-{!en_left}: 0;\n	list-style-type: none;\n}"=>".nl li {\n	display: block;\n	margin-{!en_left}: 0;\n	padding-{!en_left}: 0;\n	list-style-type: none;\n	list-style-image: none;\n}",
				".menu_type__popup li a:link a:hover {\n	color: #9C202F; /* {\$,wizard, 100% a.hover}*/\n}"=>".menu_type__popup li a:hover {\n	color: #9C202F !important; /* {\$,wizard, 100% a.hover}*/\n}",
				".menu_type__top li, .menu_type__dropdown li.toplevel {\n	float: {!en_left};\n	border-{!en_left}: 1px solid #0d1522; /* {\$,wizard, 20% seed + 80% !W/B} */\n	margin-{!en_right}: -1px;"=>".menu_type__top li, .menu_type__dropdown li.toplevel {\n	float: {!en_left};\n	border-{!en_left}: 1px solid #0d1522; /* {\$,wizard, 20% seed + 80% !W/B} */\n	margin-{!en_right}: -1px;\n	margin-bottom: 0;",
				".menu_type__top img, .menu_type__dropdown li.toplevel img {\n	float: {!en_left};\n	padding: 0 8px 0 3px;\n	margin-top: -2px;\n}"=>".menu_type__top img, .menu_type__dropdown .toplevel_link img {\n	margin-top: -2px;\n}\n\n.menu_type__top img, .menu_type__dropdown img {\n	float: {!en_left};\n	padding: 0 8px 0 3px;\n}",
				".menu_type__top .menu_spacer, .menu_type__dropdown li.toplevel.menu_spacer {\n	height: 1.15em;\n	width: 4em;\n	padding: 4px;\n}"=>".menu_type__top .menu_spacer, .menu_type__dropdown li.toplevel.menu_spacer {\n	height: 1.15em;\n	width: 4em;\n	padding: 4px;\n	float: {!en_left};\n}",
				".menu_type__zone {\n	font-size: 0.9em;\n}"=>".menu_type__zone {\n	font-size: 0.9em;\n	max-height: 15px;\n}",
				".menu_type__zone li {\n	display: inline;\n	padding: 0;\n	list-style-type: none;\n}"=>".menu_type__zone li {\n	display: inline;\n	padding: 0;\n	list-style-type: none;\n	list-style-image: none;\n}\n\n.menu_type__zone li * {\n	vertical-align: middle;\n}",
				".edit_menu_link_inline {\n	position: absolute;\n	right: 1px;\n}"=>"*>.edit_menu_link_inline {\n	display: none;\n}\n\n*:hover>.edit_menu_link_inline {\n	display: block;\n}\n\n.edit_menu_link_inline {\n	position: absolute;\n	right: 1px;\n	z-index: 10000;\n}",
				".radio_list_picture {\n	float: {!en_left};\n	white-space: nowrap;\n	padding: 3px;\n	min-width: 35px;\n	min-height: 35px;\n}"=>".radio_list_picture {\n	float: {!en_left};\n	white-space: nowrap;\n	padding: 3px;\n	min-width: 40px;\n	min-height: 40px;\n	font-size: 0.8em;\n	min-height: 65px;\n	min-width: 85px;\n}",
			),
			'news.css'=>array(
				".standardbox_wrap_classic .news_piece_summary h3, .rss_summary h3 {\n	margin-{!en_right}: 130px;\n	border-bottom: 1px solid #6b81a1; /* {\$,wizard, 100% medborder.border} */\n}"=>".news_piece_summary h3, .rss_summary h3 {\n	margin-{!en_right}: 130px !important;\n	border-bottom: 1px solid #6b81a1 !important; /* {\$,wizard, 100% medborder.border} */\n}\n\n.rss_summary nobr { /* Stops naughty Google news from breaking layout */\n	white-space: normal;\n}",
			),
			'ocf.css'=>array(
				".ocf_post_details_date {\n	float: {!en_left};\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		width: 25em;\n	{+END}\n	padding-{!en_left}: 4px;\n}"=>".ocf_post_details_date {\n	float: {!en_left};\n	padding-{!en_left}: 4px;\n}\n\n.ocf_post_details_rating {\n	float: {!en_left};\n	padding-{!en_left}: 20px;\n	white-space: nowrap;\n}",
				".ocf_information_bar { /* {\$,either OCF_GUEST_BAR.tpl or OCF_MEMBER_BAR.tpl} */\n	background-color: #eef2f7; /* {\$,wizard, 60% bgcol + 40% W/B} */\n	font-size: 0.85em;\n	border-collapse: collapse;\n	white-space: nowrap;\n	width: 100%;\n}"=>".ocf_information_bar { /* {\$,either OCF_GUEST_BAR.tpl or OCF_MEMBER_BAR.tpl} */\n	background-color: #eef2f7; /* {\$,wizard, 60% bgcol + 40% W/B} */\n	font-size: 0.85em;\n	border-collapse: collapse;\n	white-space: nowrap;\n	width: 100%;\n	padding: 0;\n}",
				".ocf_member_column_d {\n	{+START,IF,{\$NOT,{\$MOBILE}}}\n		width: 11.3em;\n	{+END}\n	{+START,IF,{\$MOBILE}}\n		float: left;\n	{+END}\n	white-space: nowrap;\n}"=>".ocf_member_column_d {\n	white-space: nowrap;\n}",
				".ocf_member_column_e {\n	white-space: nowrap;\n}\n\n"=>"",
				".ocf_post_details_unvalidated {\n	float: {!en_left};\n	}"=>".ocf_post_details_unvalidated {\n	float: {!en_left};\n	padding-{!en_left}: 7px;\n	}",
			),
			'points.css'=>array(
				".points_give_choices .sub_option {\n	font-size: 0.9em;\n}"=>".points_give_choices .sub_option {\n	font-size: 0.9em;\n	white-space: nowrap;\n}",
			),
			'swfupload.css'=>array(
				"width: 365px;"=>"{+START,IF,{\$NOT,{\$MOBILE}}}\n		width: 365px;\n	{+END}",
			),
			'tickets.css'=>array(
				".closed_ticket {\n	font-weight: bold;\n	padding-{!en_left}: 30px;\n}"=>".closed_ticket {\n	font-style: italic;\n	float: right;\n	padding-{!en_left}: 30px;\n}",
			),
		);

		$css_prepend__single_match=array(
			'adminzone.css'=>array(
				".css_colour_strip"=>".dottedborder .css_colour_chooser_name {\n	width: 190px;\n}\n\n.dottedborder .css_colour_chooser {\n	width: 680px;\n	margin: 0;\n}\n\n",
				".menu_editor_rh_side"=>".menu_editor_page.docked .menu_editor_rh_side {\n	overflow-y: scroll;\n	max-height: 380px;\n	margin-right: 10px;\n}\n\n",
				".menu_editor_lh_side"=>".menu_editor_page.docked #mini_form_hider {\n	margin-top: 1em;\n	border-top: 3px dotted #8b96df !important; /* {\$,wizard, 61% seed + 39% W/B} */\n	position: fixed;\n	left: 0;\n	bottom: 0;\n	background: #ffffff; /* {\$,wizard, 100% W/B} */\n	font-size: 0.9em;\n}\n\n.docked .menu_edit_main {\n	padding-bottom: 30em;\n}\n\n.dock_button {\n	float: right;\n	padding: 5px;\n	cursor: pointer;\n}\n\n",
			),
			'calendar.css'=>array(
				".top_navigation"=>"abbr.dtstart, abbr.dtend {\n	border-bottom: 0;\n}\n\n",
			),
			'galleries.css'=>array(
				".nav_mid"=>"#gallery_entry_screen {\n	width: 100%;\n	min-height: 100%;\n}\n\n",
				"/* side_root galleries block */"=>".slideshow_speed {\n	position: absolute;\n	right: 0;\n	top: 0;\n}\n\n.slideshow_speed input {\n	width: 3em;\n}\n\n#changer {\n	font-weight: bold;\n	font-family: Courier;\n	font-size: 1.2em;\n}\n\n",
			),
			'global.css'=>array(
				".standardbox_title_classic a"=>"h3.standardbox_title_classic {\n	border-bottom: 0;\n}\n\n",
				".no_stbox_padding .dottedborder {"=>".overlay .dottedborder_huge_a, .overlay .dottedborder_barrier_a_nonrequired, .overlay .dottedborder_barrier_b_nonrequired, .overlay .dottedborder_divider, .overlay .dottedborder_divider_continue, .overlay .no_stbox_padding .forcedottedborder, .overlay .dottedborder {\n	border: 0;\n}\n\n",
				".edited {"=>".bookmarks_menu_box {\n	width: 320px;\n}\n\n",
				"\na.poster_member:hover"=>".post_poster a.poster_member:link, .post_poster a.poster_member:active, .post_poster a.poster_member:visited, .post_poster a.poster_member:hover {\n	display: inline-block;\n}\n",
				".menu_type__dropdown ul.nlevel, .menu_type__popup ul"=>".menu_type__popup {\n	min-width: 150px;\n}\n\n",
				".comments_posting_form_inner table"=>".comments_posting_form_inner textarea {\n	color: #94979d; /* {\$,wizard, 65% bgcol + 35% !W/B} */\n}\n\n",
			),
		);

		$css_append__single_match=array(
			'global.css'=>array(
				".medborder_detailhead a:hover {\n	color: #9C202F; /* {\$,wizard, 100% a.hover}*/\n}\n\n"=>".global_side .medborder_detailhead_wrap {\n	padding: 0;\n}\n\n.global_side .medborder_detailhead {\n	border-bottom: 0;\n	padding-left: 0;\n	padding-top: 5px;\n}\n\n",
				"	top: -256000px;\n	left: 0;\n"=>"	display: block; /* stops browser bugs where it interacts with the layout flow incorrectly */\n",
				".page_icon {\n	vertical-align: middle;\n	{+START,IF,{\$MOBILE}}\n		margin-bottom: 5px;\n	{+END}\n}\n\n"=>".standardbox_title_classic .page_icon {\n	margin: -1px 3px 0 0;\n}\n\n",
				".input_huge_field {\n}\n\n"=>".password_strength {\n	float: right;\n	width: 100px;\n	border: 1px solid #6b81a1; /* {\$,wizard, 100% medborder.border} */\n	display: none;\n}\n\n.password_strength_inner {\n	height: 1em;\n	width: 0px;\n}\n\n",
				".radio_list_picture {\n	float: {!en_left};\n	white-space: nowrap;\n	padding: 3px;\n	min-width: 40px;\n	min-height: 40px;\n}\n\n"=>"#page_running_admin_themes .radio_list_picture {\n	float: none;\n	margin: 15px;\n	border: 1px solid #c1cee3; /* {\$,wizard, 100% lightborder} */\n}\n\n.radio_list_picture img {\n	max-width: 100px;\n}\n\n",
				".tab_last {\n	border-right: 1px solid;\n	border-color: #b5b5b5; /* {\$,wizard, 100% b5b5b5} */\n}\n\n"=>".tab_surround .tab { /* subtabs */\n	padding-top: 5px !important;\n	height: 18px;\n	font-size: 0.88em;\n}\n\n",
				"#screen_actions .digg {\n	background-image: url('{\$IMG,recommend/digg}');\n}"=>"\n#screen_actions .google_plusone {\n	margin-top: 1px;\n}\n",
			),
		);

		$css_file_append=array(
			'galleries.css'=>array(
				"\n/* Miscellaneous media handling */\n\n.gallery_pdf {\n	width: 100%;\n	height: 600px;\n}",
			),
			'no_cache.css'=>array(
				"\n{\$BROWSER,opera,,tt\, kbd\, samp \{ font-size: 1.25em; \}}\n",
			),
		);

		// NB: This UNIX command can work out what theme images are added...
		// OLD=/Library/WebServer/Documents/test/themes/default/images ; NEW=/Library/WebServer/Documents/git/themes/default/images ; diff -r $OLD $NEW | grep "Only in $NEW" | grep -v .DS_Store | sed "s#Only in "$NEW"##g" | sed "s#: #/#g" | sed "s#^/##g" | sed "s#^EN/##g" | sed "s#\.*$##"
		// Obviously only theme-wizable images should go here
		$theme_images_new=array(
			'page/add_ticket',
			'page/disable_notifications',
			'page/enable_notifications',
			'page/forum',
			'page/send_message',
			'pageitem/disable_notifications',
			'pageitem/enable_notifications',
			'pageitem/reply',
			'pageitem/send_message',
		);

		$theme_images_renames=array(
			'standardboxes/title_gradiant'=>'standardboxes/title_gradient',
			'quote_gradiant'=>'quote_gradient',
			'zone_gradiant'=>'zone_gradient',
		);

		$templates_replace=array(
			'*'=>array(
				'_true'=>'1',
				'_false'=>'0',
				'TOPIC_NAME'=>'TOPIC_TITLE',
				'load_XML_doc'=>'do_ajax_request',
				'DESPATCH'=>'DISPATCH',
			),
		);

		/*Find deleted/renamed templates:
		OLD=/Library/WebServer/Documents/test/themes/default/templates ; NEW=/Library/WebServer/Documents/git/themes/default/templates ; diff -r $OLD $NEW | grep .tpl$ | grep "Only in "$OLD | sed "s#Only in "$OLD": ##"*/
		$templates_rename=array(
			'COMMENTS.tpl'=>'COMMENTS_POSTING_FORM.tpl',
			'CEDI_RATING_INSIDE.tpl'=>'CEDI_RATING_FORM.tpl',
			'RATING_INSIDE.tpl'=>'RATING_FORM.tpl',
			'RATING.tpl'=>'RATING_BOX.tpl',
			'RATING_INLINE.tpl'=>'RATING_INLINE_STATIC.tpl',
		);

		/*Find diff of changes templates
		OLD=/Library/WebServer/Documents/test/themes/default/templates ; NEW=/Library/WebServer/Documents/git/themes/default/templates ; diff -u $OLD $NEW > ~/Desktop/diff.txt*/
		$templates_borked=array(
			'COMMENTS_POSTING_FORM.tpl',
			'CEDI_RATING_FORM.tpl',
			'RATING_FORM.tpl',
			'RATING_BOX.tpl',
			'RATING_INLINE_STATIC.tpl',

			'COMMENTS_WRAPPER.tpl',
			'CEDI_RATING.tpl',
			'OCF_MEMBER_PROFILE_SCREEN.tpl',
			'ATTACHMENT.tpl',
			'POSTING_FORM.tpl',
			'POSTING_FIELD.tpl',
			'ATTACHMENTS.tpl',
			'BLOCK_HELPER_DONE.tpl',
			'ATTACHMENT_IMG.tpl',
			'ATTACHMENT_IMG_MINI.tpl',
			'CATALOGUE_DEFAULT_CATEGORY_SCREEN.tpl',
			'JAVASCRIPT.tpl',
			'JAVASCRIPT_AJAX.tpl',
			'JAVASCRIPT_AJAX_PEOPLE_LISTS.tpl',
			'JAVASCRIPT_CHAT.tpl',
			'JAVASCRIPT_DATE_CHOOSER.tpl',
			'JAVASCRIPT_EDITING.tpl',
			'JAVASCRIPT_JWPLAYER.tpl',
			'JAVASCRIPT_MENU_EDITOR.tpl',
			'JAVASCRIPT_PERMISSIONS.tpl',
			'JAVASCRIPT_POSTING.tpl',
			'JAVASCRIPT_SOUND.tpl',
			'JAVASCRIPT_STAFF.tpl',
			'JAVASCRIPT_SWFUPLOAD.tpl',
			'JAVASCRIPT_THUMBNAILS.tpl',
			'JAVASCRIPT_TREE_LIST.tpl',
			'JAVASCRIPT_VALIDATION.tpl',
			'JAVASCRIPT_YAHOO_EVENTS.tpl',
			'JAVASCRIPT_ZONE_EDITOR.tpl',
			'FORM_SCREEN_INPUT_CAPTCHA.tpl',
			'FORM_SCREEN_INPUT_DATE.tpl',
			'FORM_SCREEN_INPUT_PASSWORD.tpl',
			'FORM_SCREEN_INPUT_RADIO_LIST.tpl',
			'FORM_SCREEN_INPUT_RADIO_LIST_ENTRY_PICTURE_2.tpl',
			'FORM_SCREEN_INPUT_TICK.tpl',
			'FORM_SCREEN_INPUT_TREE_LIST.tpl',
			'FORM_SCREEN_INPUT_UPLOAD.tpl',
			'FORM_SCREEN_INPUT_UPLOAD_MULTI.tpl',
			'GALLERY_NAV.tpl',
			'MENU_EDITOR_BRANCH_WRAP.tpl',
			'MENU_EDITOR_SCREEN.tpl',
			'OCF_FORUM.tpl',
			'OCF_MEMBER_BAR.tpl',
			'OCF_TOPIC_WRAP.tpl',
			'PAGE_LINK_CHOOSER.tpl',
			'POINTS_SCREEN.tpl',
			'SUPPORT_TICKETS_SCREEN.tpl',
			'SUPPORT_TICKET_SCREEN.tpl',
		);
	} else
	{
		$errors[]=do_lang_tempcode('NO_DEFINED_THEME_UPGRADER');
		return array($errors,array());
	}

	if (addon_installed('themewizard'))
	{
		require_code('themewizard');
		$seed=find_theme_seed($theme);
		$dark=find_theme_dark($theme);
		list($colours,$landscape)=calculate_theme($seed,'default','equations','colours',$dark);
	}

	// CSS
	$css_dir=get_custom_file_base().'/themes/'.filter_naughty($theme).'/css_custom/';
	$dh=@opendir($css_dir);
	if ($dh!==false)
	{
		while (($css_file=readdir($dh))!==false)
		{
			if (substr($css_file,-4)!='.css') continue;
			if (substr($css_file,0,1)=='.') continue;

			$css_file_contents=file_get_contents($css_dir.$css_file);
			$orig_css_file_contents=$css_file_contents;
			if (strpos($css_file_contents,$css_recognition_string)===false)
			{
				$errors[]=do_lang_tempcode('NON_RECOGNISED_CSS_FILE',escape_html($css_file),escape_html(float_to_raw_string($from_version)));
				//continue;		Actually we'll let it pass
			}

			// Apply single match rules. First check single match rules apply exactly once (means rule is bogus if it matches more than once, or unusable if not at all)
			foreach (array('css_replace'=>$css_replace__single_match,'css_prepend'=>$css_prepend__single_match,'css_append'=>$css_append__single_match) as $rule_set_type=>$rule_set)
			{
				foreach ($rule_set as $target_file=>$_rule_set)
				{
					// If people have moved CSS into global.css, to optimise page load times
					if (($target_file!='*') && ($target_file!='global.css') && ($css_file=='global.css'))
					{
						if ((file_exists($css_dir.$target_file)) && (strlen(trim(file_get_contents($css_dir.$target_file)))==0))
						{
							$target_file='global.css';
						}
					}

					if (($target_file=='*') || ($target_file==$css_file))
					{
						foreach ($_rule_set as $from=>$to)
						{
							// Apply theme wizard to $to
							if (addon_installed('themewizard'))
								$to=theme_wizard_colours_to_css($to,$landscape,'default','equations',$seed);

							$occurrences=substr_count($css_file_contents,$from);
							if ($occurrences==0) // Try after applying theme wizard
							{
								if (addon_installed('themewizard'))
								{
									$from=theme_wizard_colours_to_css($from,$landscape,'default','equations',$seed);
									$occurrences=substr_count($css_file_contents,$from);
								}
							}
							if ($occurrences==0)
							{
								$errors[]=do_lang_tempcode('CSS_RULE_UNMATCHED_'.$rule_set_type,escape_html($from),escape_html($to),escape_html($target_file));
							}
							elseif ($occurrences>1)
							{
								$errors[]=do_lang_tempcode('CSS_RULE_OVERMATCHED_'.$rule_set_type,escape_html($from),escape_html($to),escape_html($target_file));
							} else
							{
								switch ($rule_set_type)
								{
									case 'css_replace':
										$css_file_contents=str_replace($from,$to,$css_file_contents);
										break;

									case 'css_prepend':
										$pos=strpos($css_file_contents,$from);
										if (substr($css_file_contents,$pos-strlen($to),strlen($to))!=$to)
										{
											$css_file_contents=substr($css_file_contents,0,$pos).$to.substr($css_file_contents,$pos);
										}
										break;

									case 'css_append':
										$pos=strpos($css_file_contents,$from)+strlen($from);
										if (substr($css_file_contents,$pos,strlen($to))!=$to)
										{
											$css_file_contents=substr($css_file_contents,0,$pos).$to.substr($css_file_contents,$pos);
										}
										break;
								}
							}
						}
					}
				}
			}

			// Apply multi-match rules
			foreach (array('css_replace'=>$css_replace__multi_match,'css_prepend'=>$css_prepend__multi_match,'css_append'=>$css_append__multi_match) as $rule_set_type=>$rule_set)
			{
				foreach ($rule_set as $target_file=>$_rule_set)
				{
					if (($target_file=='*') || ($target_file==$css_file))
					{
						foreach ($_rule_set as $from=>$to)
						{
							// Apply theme wizard to $to
							if (addon_installed('themewizard'))
								$to=theme_wizard_colours_to_css($to,$landscape,'default','equations',$seed);

							$froms=array($from);
							if (addon_installed('themewizard'))
								$froms[]=theme_wizard_colours_to_css($from,$landscape,'default','equations',$seed);
							foreach ($froms as $from)
							{
								switch ($rule_set_type)
								{
									case 'css_replace':
										$css_file_contents=str_replace($from,$to,$css_file_contents);
										break;

									case 'css_prepend':
										$pos=0;
										do
										{
											$pos=strpos($css_file_contents,$from,$pos);
											if ($pos!==false)
											{
												if (substr($css_file_contents,$pos,-strlen($to))!=$to)
												{
													$css_file_contents=substr($css_file_contents,0,$pos).$to.substr($css_file_contents,$pos);
													$pos+=strlen($to)+strlen($from);
												} else
												{
													$pos+=strlen($from);
												}
											}
										}
										while ($pos!==false);
										break;

									case 'css_append':
										$pos=0;
										do
										{
											$pos=strpos($css_file_contents,$from,$pos);
											if ($pos!==false)
											{
												if (substr($css_file_contents,$pos,strlen($to))!=$to)
												{
													$pos+=strlen($from);
													$css_file_contents=substr($css_file_contents,0,$pos).$to.substr($css_file_contents,$pos);
													$pos+=strlen($to);
												} else
												{
													$pos+=strlen($from);
												}
											}
										}
										while ($pos!==false);
										break;
								}
							}
						}
					}
				}
			}

			// Apply unmatched rules
			foreach ($css_file_append as $target_file=>$rule_set)
			{
				if (($target_file=='*') || ($target_file==$css_file))
				{
					foreach ($rule_set as $to)
					{
						$css_file_contents.=$to;
					}
				}
			}

			if (!$test_run)
			{
				// Take revision
				$revision_file=$css_dir.$css_file.'.'.strval(time());
				if (@copy($css_dir.$css_file,$revision_file)!==false)
				{
					fix_permissions($revision_file);
					sync_file($revision_file);
				}

				// Save
				if ($orig_css_file_contents!=$css_file_contents)
				{
					$outfile=@fopen($css_dir.$css_file,'wb') OR intelligent_write_error($css_dir.$css_file);
					fwrite($outfile,$css_file_contents);
					fclose($outfile);
				}

				$successes[]=do_lang_tempcode('CSS_FILE_UPGRADED',escape_html($css_file));
			}
		}

		closedir($dh);
	}

	// Theme images
	require_code('themes2');
	$langs=array('EN'=>'lang');//find_all_langs();
	foreach ($theme_images_renames as $old=>$new)
	{
		foreach (array_keys($langs) as $lang)
		{
			$path=urldecode(find_theme_image($old,true,true,$theme,$lang));
			if ($path!='')
			{
				$new_path=str_replace('/'.$old,'/'.$new,$path);
				if (!$test_run)
				{
					if (!file_exists(get_custom_file_base().'/'.$new_path))
					{
						if (file_exists($path))
							afm_move($path,$new_path);

						$where_map=array('theme'=>$theme,'id'=>$new);
						if (($lang!='') && (!is_null($lang))) $where_map['lang']=$lang;
						$GLOBALS['SITE_DB']->query_delete('theme_images',$where_map);

						actual_edit_theme_image($old,$theme,$lang,$new,$new_path);

						$successes[]=do_lang_tempcode('THEME_IMAGE_RENAMED',escape_html($old),escape_html($new));
					}
				}
			}
		}
	}
	if (addon_installed('themewizard'))
	{
		if ($theme!='default')
		{
			foreach ($theme_images_new as $new)
			{
				foreach (array_keys($langs) as $lang)
				{
					$path=urldecode(find_theme_image($new,true,true,'default',$lang));
					if ($path!='')
					{
						$new_path=str_replace('themes/default/images/','themes/'.$theme.'/images/',$path);
						if (!file_exists(get_custom_file_base().'/'.$new_path))
						{
							if (!$test_run)
							{
								afm_make_directory(dirname($new_path),true,true);
							}

							$image=calculate_theme($seed,'default','equations',$new,$dark,$colours,$landscape,$lang);
							if (!is_null($image))
							{
								if (!$test_run)
								{
									@imagepng($image,get_custom_file_base().'/'.$new_path) OR intelligent_write_error(get_custom_file_base().'/'.$new_path);
									imagedestroy($image);
									fix_permissions(get_custom_file_base().'/'.$new_path);
									sync_file(get_custom_file_base().'/'.$new_path);

									$successes[]=do_lang_tempcode('THEME_IMAGE_NEW',escape_html($new));
								}
							}
						}
					}
				}
			}
		}
	}

	// Templates
	$templates_dir=get_custom_file_base().'/themes/'.filter_naughty($theme).'/templates_custom/';
	$dh=@opendir($templates_dir);
	if ($dh!==false)
	{
		while (($templates_file=readdir($dh))!==false)
		{
			if (substr($templates_file,-4)!='.tpl') continue;

			$templates_file_contents=file_get_contents($templates_dir.$templates_file);
			$orig_templates_file_contents=$templates_file_contents;

			foreach ($templates_replace as $target_file=>$rule_set)
			{
				if (($target_file=='*') || ($target_file==$templates_file))
				{
					foreach ($rule_set as $from=>$to)
					{
						$templates_file_contents=str_replace($from,$to,$templates_file_contents);
					}
				}
			}
			if (array_key_exists($templates_file,$templates_rename))
			{
				if (!$test_run)
				{
					@rename($templates_dir.$templates_file,$templates_dir.$templates_rename[$templates_file]) OR intelligent_write_error($templates_dir.$templates_rename[$templates_file]);
					$successes[]=do_lang_tempcode('TEMPLATE_RENAMED',escape_html($templates_file),escape_html($templates_rename[$templates_file]));
				}
				$templates_file=$templates_rename[$templates_file];
			}
			if ($templates_file_contents!=$orig_templates_file_contents)
			{
				if (!$test_run)
				{
					$successes[]=do_lang_tempcode('TEMPLATE_ALTERED',escape_html($templates_file));

					// Save
					$outfile=@fopen($templates_dir.$templates_file,'wb') OR intelligent_write_error($templates_dir.$templates_file);
					fwrite($outfile,$templates_file_contents);
					fclose($outfile);
				}
			}

			if (in_array($templates_file,$templates_borked))
			{
				$errors[]=do_lang_tempcode('TEMPLATE_WILL_NEED_RESTORING',escape_html($templates_file));
			}
		}

		closedir($dh);
	}

	return array($errors,$successes);
}

/**
 * Upgrade shared installs.
 */
function upgrade_sharedinstall_sites()
{
	global $CURRENT_SHARE_USER,$SITE_INFO,$TABLE_LANG_FIELDS;

	// Find sites
	$sites=array();
	foreach (array_keys($SITE_INFO) as $key)
	{
		$matches=array();
		if (preg_match('#^custom_user_(.*)#',$key,$matches)!=0)
		{
			$sites[]=$matches[1];
		}
	}

	disable_php_memory_limit();

	foreach ($sites as $i=>$site)
	{
		if (function_exists('set_time_limit')) @set_time_limit(0);

		// Change active site
		$CURRENT_SHARE_USER=$site;
		$TABLE_LANG_FIELDS=array();
		_general_db_init();

		// Reset DB
		$GLOBALS['SITE_DB']=new database_driver(get_db_site(),get_db_site_host(),get_db_site_user(),get_db_site_password(),get_table_prefix());
		$GLOBALS['FORUM_DB']=$GLOBALS['SITE_DB'];

		// NB: File path will be ok

		// NB: Other internal caching could need changing in the future, but works at time of writing

		// Go!
		automate_upgrade();

		echo 'Upgraded '.htmlentities($site).'<br />';
		flush();
	}
}

/**
 * Automatically go through full upgrade for current site.
 */
function automate_upgrade()
{
	// Database
	clear_caches_1();
	clear_caches_2();
	version_specific();
	upgrade_modules();

	// OCF
	ocf_upgrade();

	// Themes
	require_code('themes2');
	$themes=find_all_themes();
	foreach (array_keys($themes) as $theme)
	{
		$from=round(ocp_version_number())-1;
		$to=ocp_version_number();
		upgrade_theme($theme,$from,$to,false);
	}
}
