aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/install_old
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/install_old')
-rw-r--r--phpBB/install_old/convertors/convert_phpbb20.php975
-rw-r--r--phpBB/install_old/convertors/functions_phpbb20.php1984
-rw-r--r--phpBB/install_old/data/confusables.php645
-rw-r--r--phpBB/install_old/database_update.php267
-rw-r--r--phpBB/install_old/index.php867
-rw-r--r--phpBB/install_old/install_convert.php2153
-rw-r--r--phpBB/install_old/install_update.php1790
-rw-r--r--phpBB/install_old/phpinfo.php14
8 files changed, 8695 insertions, 0 deletions
diff --git a/phpBB/install_old/convertors/convert_phpbb20.php b/phpBB/install_old/convertors/convert_phpbb20.php
new file mode 100644
index 0000000000..a19bb2504b
--- /dev/null
+++ b/phpBB/install_old/convertors/convert_phpbb20.php
@@ -0,0 +1,975 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* NOTE to potential convertor authors. Please use this file to get
+* familiar with the structure since we added some bare explanations here.
+*
+* Since this file gets included more than once on one page you are not able to add functions to it.
+* Instead use a functions_ file.
+*
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
+extract($phpbb_config_php_file->get_all());
+unset($dbpasswd);
+
+$dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+/**
+* $convertor_data provides some basic information about this convertor which is
+* used on the initial list of convertors and to populate the default settings
+*/
+$convertor_data = array(
+ 'forum_name' => 'phpBB 2.0.x',
+ 'version' => '1.0.3',
+ 'phpbb_version' => '3.1.5',
+ 'author' => '<a href="https://www.phpbb.com/">phpBB Limited</a>',
+ 'dbms' => $dbms,
+ 'dbhost' => $dbhost,
+ 'dbport' => $dbport,
+ 'dbuser' => $dbuser,
+ 'dbpasswd' => '',
+ 'dbname' => $dbname,
+ 'table_prefix' => 'phpbb_',
+ 'forum_path' => '../forums',
+ 'author_notes' => '',
+);
+
+/**
+* $tables is a list of the tables (minus prefix) which we expect to find in the
+* source forum. It is used to guess the prefix if the specified prefix is incorrect
+*/
+$tables = array(
+ 'auth_access',
+ 'banlist',
+ 'categories',
+ 'disallow',
+ 'forum_prune',
+ 'forums',
+ 'groups',
+ 'posts',
+ 'posts_text',
+ 'privmsgs',
+ 'privmsgs_text',
+ 'ranks',
+ 'smilies',
+ 'topics',
+ 'topics_watch',
+ 'user_group',
+ 'users',
+ 'vote_desc',
+ 'vote_results',
+ 'vote_voters',
+ 'words'
+);
+
+/**
+* $config_schema details how the board configuration information is stored in the source forum.
+*
+* 'table_format' can take the value 'file' to indicate a config file. In this case array_name
+* is set to indicate the name of the array the config values are stored in
+* Example of using a file:
+* $config_schema = array(
+* 'table_format' => 'file',
+* 'filename' => 'NAME OF FILE', // If the file is not in the root directory, the path needs to be added with no leading slash
+* 'array_name' => 'NAME OF ARRAY', // Only used if the configuration file stores the setting in an array.
+* 'settings' => array(
+* 'board_email' => 'SUPPORT_EMAIL', // target config name => source target name
+* )
+* );
+* 'table_format' can be an array if the values are stored in a table which is an assosciative array
+* (as per phpBB 2.0.x)
+* If left empty, values are assumed to be stored in a table where each config setting is
+* a column (as per phpBB 1.x)
+*
+* In either of the latter cases 'table_name' indicates the name of the table in the database
+*
+* 'settings' is an array which maps the name of the config directive in the source forum
+* to the config directive in phpBB3. It can either be a direct mapping or use a function.
+* Please note that the contents of the old config value are passed to the function, therefore
+* an in-built function requiring the variable passed by reference is not able to be used. Since
+* empty() is such a function we created the function is_empty() to be used instead.
+*/
+$config_schema = array(
+ 'table_name' => 'config',
+ 'table_format' => array('config_name' => 'config_value'),
+ 'settings' => array(
+ 'allow_bbcode' => 'allow_bbcode',
+ 'allow_smilies' => 'allow_smilies',
+ 'allow_sig' => 'allow_sig',
+ 'allow_namechange' => 'allow_namechange',
+ 'allow_avatar_local' => 'allow_avatar_local',
+ 'allow_avatar_remote' => 'allow_avatar_remote',
+ 'allow_avatar_upload' => 'allow_avatar_upload',
+ 'board_disable' => 'board_disable',
+ 'sitename' => 'phpbb_set_encoding(sitename)',
+ 'site_desc' => 'phpbb_set_encoding(site_desc)',
+ 'session_length' => 'session_length',
+ 'board_email_sig' => 'phpbb_set_encoding(board_email_sig)',
+ 'posts_per_page' => 'posts_per_page',
+ 'topics_per_page' => 'topics_per_page',
+ 'enable_confirm' => 'enable_confirm',
+ 'board_email_form' => 'board_email_form',
+ 'override_user_style' => 'override_user_style',
+ 'hot_threshold' => 'hot_threshold',
+ 'max_poll_options' => 'max_poll_options',
+ 'max_sig_chars' => 'max_sig_chars',
+ 'pm_max_msgs' => 'max_inbox_privmsgs',
+ 'smtp_delivery' => 'smtp_delivery',
+ 'smtp_host' => 'smtp_host',
+ 'smtp_username' => 'smtp_username',
+ 'smtp_password' => 'smtp_password',
+ 'require_activation' => 'require_activation',
+ 'flood_interval' => 'flood_interval',
+ 'avatar_filesize' => 'avatar_filesize',
+ 'avatar_max_width' => 'avatar_max_width',
+ 'avatar_max_height' => 'avatar_max_height',
+ 'default_dateformat' => 'phpbb_set_encoding(default_dateformat)',
+ 'board_timezone' => 'phpbb_convert_timezone(board_timezone)',
+ 'allow_privmsg' => 'not(privmsg_disable)',
+ 'gzip_compress' => 'gzip_compress',
+ 'coppa_enable' => '!is_empty(coppa_mail)',
+ 'coppa_fax' => 'coppa_fax',
+ 'coppa_mail' => 'coppa_mail',
+ 'record_online_users' => 'record_online_users',
+ 'record_online_date' => 'record_online_date',
+ 'board_startdate' => 'board_startdate',
+ )
+);
+
+/**
+* $test_file is the name of a file which is present on the source
+* forum which can be used to check that the path specified by the
+* user was correct
+*/
+$test_file = 'modcp.php';
+
+/**
+* If this is set then we are not generating the first page of information but getting the conversion information.
+*/
+if (!$get_info)
+{
+ // Test to see if the birthday MOD is installed on the source forum
+ // Niels' birthday mod
+ if (get_config_value('birthday_required') !== false || get_config_value('bday_require') !== false)
+ {
+ define('MOD_BIRTHDAY', true);
+ }
+
+ // TerraFrost's validated birthday mod
+ if (get_config_value('bday_require') !== false)
+ {
+ define('MOD_BIRTHDAY_TERRA', true);
+ }
+
+ // Test to see if the attachment MOD is installed on the source forum
+ // If it is, we will convert this data as well
+ $src_db->sql_return_on_error(true);
+
+ $sql = "SELECT config_value
+ FROM {$convert->src_table_prefix}attachments_config
+ WHERE config_name = 'upload_dir'";
+ $result = $src_db->sql_query($sql);
+
+ if ($result && $row = $src_db->sql_fetchrow($result))
+ {
+ // Here the constant is defined
+ define('MOD_ATTACHMENT', true);
+
+ // Here i add more tables to be checked in the old forum
+ $tables += array(
+ 'attachments',
+ 'attachments_desc',
+ 'extensions',
+ 'extension_groups'
+ );
+
+ $src_db->sql_freeresult($result);
+ }
+ else if ($result)
+ {
+ $src_db->sql_freeresult($result);
+ }
+
+
+ /**
+ * Tests for further MODs can be included here.
+ * Please use constants for this, prefixing them with MOD_
+ */
+
+ $src_db->sql_return_on_error(false);
+
+ // Now let us set a temporary config variable for user id incrementing
+ $sql = "SELECT user_id
+ FROM {$convert->src_table_prefix}users
+ WHERE user_id = 1";
+ $result = $src_db->sql_query($sql);
+ $user_id = (int) $src_db->sql_fetchfield('user_id');
+ $src_db->sql_freeresult($result);
+
+ // If there is a user id 1, we need to increment user ids. :/
+ if ($user_id === 1)
+ {
+ // Try to get the maximum user id possible...
+ $sql = "SELECT MAX(user_id) AS max_user_id
+ FROM {$convert->src_table_prefix}users";
+ $result = $src_db->sql_query($sql);
+ $user_id = (int) $src_db->sql_fetchfield('max_user_id');
+ $src_db->sql_freeresult($result);
+
+ $config->set('increment_user_id', ($user_id + 1), false);
+ }
+ else
+ {
+ $config->set('increment_user_id', 0, false);
+ }
+
+ // Overwrite maximum avatar width/height
+ @define('DEFAULT_AVATAR_X_CUSTOM', get_config_value('avatar_max_width'));
+ @define('DEFAULT_AVATAR_Y_CUSTOM', get_config_value('avatar_max_height'));
+
+ // additional table used only during conversion
+ @define('USERCONV_TABLE', $table_prefix . 'userconv');
+
+/**
+* Description on how to use the convertor framework.
+*
+* 'schema' Syntax Description
+* -> 'target' => Target Table. If not specified the next table will be handled
+* -> 'primary' => Primary Key. If this is specified then this table is processed in batches
+* -> 'query_first' => array('target' or 'src', Query to execute before beginning the process
+* (if more than one then specified as array))
+* -> 'function_first' => Function to execute before beginning the process (if more than one then specified as array)
+* (This is mostly useful if variables need to be given to the converting process)
+* -> 'test_file' => This is not used at the moment but should be filled with a file from the old installation
+*
+* // DB Functions
+* 'distinct' => Add DISTINCT to the select query
+* 'where' => Add WHERE to the select query
+* 'group_by' => Add GROUP BY to the select query
+* 'left_join' => Add LEFT JOIN to the select query (if more than one joins specified as array)
+* 'having' => Add HAVING to the select query
+*
+* // DB INSERT array
+* This one consist of three parameters
+* First Parameter:
+* The key need to be filled within the target table
+* If this is empty, the target table gets not assigned the source value
+* Second Parameter:
+* Source value. If the first parameter is specified, it will be assigned this value.
+* If the first parameter is empty, this only gets added to the select query
+* Third Parameter:
+* Custom Function. Function to execute while storing source value into target table.
+* The functions return value get stored.
+* The function parameter consist of the value of the second parameter.
+*
+* types:
+* - empty string == execute nothing
+* - string == function to execute
+* - array == complex execution instructions
+*
+* Complex execution instructions:
+* @todo test complex execution instructions - in theory they will work fine
+*
+* By defining an array as the third parameter you are able to define some statements to be executed. The key
+* is defining what to execute, numbers can be appended...
+*
+* 'function' => execute function
+* 'execute' => run code, whereby all occurrences of {VALUE} get replaced by the last returned value.
+* The result *must* be assigned/stored to {RESULT}.
+* 'typecast' => typecast value
+*
+* The returned variables will be made always available to the next function to continue to work with.
+*
+* example (variable inputted is an integer of 1):
+*
+* array(
+* 'function1' => 'increment_by_one', // returned variable is 2
+* 'typecast' => 'string', // typecast variable to be a string
+* 'execute' => '{RESULT} = {VALUE} . ' is good';', // returned variable is '2 is good'
+* 'function2' => 'replace_good_with_bad', // returned variable is '2 is bad'
+* ),
+*
+*/
+
+ $convertor = array(
+ 'test_file' => 'viewtopic.php',
+
+ 'avatar_path' => get_config_value('avatar_path') . '/',
+ 'avatar_gallery_path' => get_config_value('avatar_gallery_path') . '/',
+ 'smilies_path' => get_config_value('smilies_path') . '/',
+ 'upload_path' => (defined('MOD_ATTACHMENT')) ? phpbb_get_files_dir() . '/' : '',
+ 'thumbnails' => (defined('MOD_ATTACHMENT')) ? array('thumbs/', 't_') : '',
+ 'ranks_path' => false, // phpBB 2.0.x had no config value for a ranks path
+
+ // We empty some tables to have clean data available
+ 'query_first' => array(
+ array('target', $convert->truncate_statement . SEARCH_RESULTS_TABLE),
+ array('target', $convert->truncate_statement . SEARCH_WORDLIST_TABLE),
+ array('target', $convert->truncate_statement . SEARCH_WORDMATCH_TABLE),
+ array('target', $convert->truncate_statement . LOG_TABLE),
+ ),
+
+// with this you are able to import all attachment files on the fly. For large boards this is not an option, therefore commented out by default.
+// Instead every file gets copied while processing the corresponding attachment entry.
+// if (defined("MOD_ATTACHMENT")) { import_attachment_files(); phpbb_copy_thumbnails(); }
+
+ // phpBB2 allowed some similar usernames to coexist which would have the same
+ // username_clean in phpBB3 which is not possible, so we'll give the admin a list
+ // of user ids and usernames and let him deicde what he wants to do with them
+ 'execute_first' => '
+ phpbb_create_userconv_table();
+ import_avatar_gallery();
+ if (defined("MOD_ATTACHMENT")) phpbb_import_attach_config();
+ phpbb_insert_forums();
+ ',
+
+ 'execute_last' => array('
+ add_bots();
+ ', '
+ update_folder_pm_count();
+ ', '
+ update_unread_count();
+ ', (defined('MOD_ATTACHMENT')) ? '
+ phpbb_attachment_extension_group_name();
+ ' : '
+ ', '
+ phpbb_convert_authentication(\'start\');
+ ', '
+ phpbb_convert_authentication(\'first\');
+ ', '
+ phpbb_convert_authentication(\'second\');
+ ', '
+ phpbb_convert_authentication(\'third\');
+ '),
+
+ 'schema' => array(
+ array(
+ 'target' => USERCONV_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . USERCONV_TABLE),
+
+
+ array('user_id', 'users.user_id', ''),
+ array('username_clean', 'users.username', array('function1' => 'phpbb_set_encoding', 'function2' => 'utf8_clean_string')),
+ ),
+
+ array(
+ 'target' => (defined('MOD_ATTACHMENT')) ? ATTACHMENTS_TABLE : '',
+ 'primary' => 'attachments.attach_id',
+ 'query_first' => (defined('MOD_ATTACHMENT')) ? array('target', $convert->truncate_statement . ATTACHMENTS_TABLE) : '',
+ 'autoincrement' => 'attach_id',
+
+ array('attach_id', 'attachments.attach_id', ''),
+ array('post_msg_id', 'attachments.post_id', ''),
+ array('topic_id', 'posts.topic_id', ''),
+ array('in_message', 0, ''),
+ array('is_orphan', 0, ''),
+ array('poster_id', 'attachments.user_id_1 AS poster_id', 'phpbb_user_id'),
+ array('physical_filename', 'attachments_desc.physical_filename', 'import_attachment'),
+ array('real_filename', 'attachments_desc.real_filename', 'phpbb_set_encoding'),
+ array('download_count', 'attachments_desc.download_count', ''),
+ array('attach_comment', 'attachments_desc.comment', array('function1' => 'phpbb_set_encoding', 'function2' => 'utf8_htmlspecialchars')),
+ array('extension', 'attachments_desc.extension', ''),
+ array('mimetype', 'attachments_desc.mimetype', ''),
+ array('filesize', 'attachments_desc.filesize', ''),
+ array('filetime', 'attachments_desc.filetime', ''),
+ array('thumbnail', 'attachments_desc.thumbnail', ''),
+
+ 'where' => 'attachments_desc.attach_id = attachments.attach_id AND attachments.privmsgs_id = 0 AND posts.post_id = attachments.post_id',
+ 'group_by' => 'attachments.attach_id'
+ ),
+
+ array(
+ 'target' => (defined('MOD_ATTACHMENT')) ? ATTACHMENTS_TABLE : '',
+ 'primary' => 'attachments.attach_id',
+ 'autoincrement' => 'attach_id',
+
+ array('attach_id', 'attachments.attach_id', ''),
+ array('post_msg_id', 'attachments.privmsgs_id', ''),
+ array('topic_id', 0, ''),
+ array('in_message', 1, ''),
+ array('is_orphan', 0, ''),
+ array('poster_id', 'attachments.user_id_1 AS poster_id', 'phpbb_user_id'),
+ array('physical_filename', 'attachments_desc.physical_filename', 'import_attachment'),
+ array('real_filename', 'attachments_desc.real_filename', 'phpbb_set_encoding'),
+ array('download_count', 'attachments_desc.download_count', ''),
+ array('attach_comment', 'attachments_desc.comment', array('function1' => 'phpbb_set_encoding', 'function2' => 'utf8_htmlspecialchars')),
+ array('extension', 'attachments_desc.extension', ''),
+ array('mimetype', 'attachments_desc.mimetype', ''),
+ array('filesize', 'attachments_desc.filesize', ''),
+ array('filetime', 'attachments_desc.filetime', ''),
+ array('thumbnail', 'attachments_desc.thumbnail', ''),
+
+ 'where' => 'attachments_desc.attach_id = attachments.attach_id AND attachments.post_id = 0',
+ 'group_by' => 'attachments.attach_id'
+ ),
+
+ array(
+ 'target' => (defined('MOD_ATTACHMENT')) ? EXTENSIONS_TABLE : '',
+ 'query_first' => (defined('MOD_ATTACHMENT')) ? array('target', $convert->truncate_statement . EXTENSIONS_TABLE) : '',
+ 'autoincrement' => 'extension_id',
+
+ array('extension_id', 'extensions.ext_id', ''),
+ array('group_id', 'extensions.group_id', ''),
+ array('extension', 'extensions.extension', ''),
+ ),
+
+ array(
+ 'target' => (defined('MOD_ATTACHMENT')) ? EXTENSION_GROUPS_TABLE : '',
+ 'query_first' => (defined('MOD_ATTACHMENT')) ? array('target', $convert->truncate_statement . EXTENSION_GROUPS_TABLE) : '',
+ 'autoincrement' => 'group_id',
+
+ array('group_id', 'extension_groups.group_id', ''),
+ array('group_name', 'extension_groups.group_name', array('function1' => 'phpbb_set_encoding', 'function2' => 'utf8_htmlspecialchars')),
+ array('cat_id', 'extension_groups.cat_id', 'phpbb_attachment_category'),
+ array('allow_group', 'extension_groups.allow_group', ''),
+ array('download_mode', 1, ''),
+ array('upload_icon', '', ''),
+ array('max_filesize', 'extension_groups.max_filesize', ''),
+ array('allowed_forums', 'extension_groups.forum_permissions', 'phpbb_attachment_forum_perms'),
+ array('allow_in_pm', 1, ''),
+ ),
+
+ array(
+ 'target' => BANLIST_TABLE,
+ 'execute_first' => 'phpbb_check_username_collisions();',
+ 'query_first' => array('target', $convert->truncate_statement . BANLIST_TABLE),
+
+ array('ban_ip', 'banlist.ban_ip', 'decode_ban_ip'),
+ array('ban_userid', 'banlist.ban_userid', 'phpbb_user_id'),
+ array('ban_email', 'banlist.ban_email', ''),
+ array('ban_reason', '', ''),
+ array('ban_give_reason', '', ''),
+
+ 'where' => "banlist.ban_ip NOT LIKE '%.%'",
+ ),
+
+ array(
+ 'target' => BANLIST_TABLE,
+
+ array('ban_ip', 'banlist.ban_ip', ''),
+ array('ban_userid', 0, ''),
+ array('ban_email', '', ''),
+ array('ban_reason', '', ''),
+ array('ban_give_reason', '', ''),
+
+ 'where' => "banlist.ban_ip LIKE '%.%'",
+ ),
+
+ array(
+ 'target' => DISALLOW_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . DISALLOW_TABLE),
+
+ array('disallow_username', 'disallow.disallow_username', 'phpbb_disallowed_username'),
+ ),
+
+ array(
+ 'target' => RANKS_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . RANKS_TABLE),
+ 'autoincrement' => 'rank_id',
+
+ array('rank_id', 'ranks.rank_id', ''),
+ array('rank_title', 'ranks.rank_title', array('function1' => 'phpbb_set_default_encoding', 'function2' => 'utf8_htmlspecialchars')),
+ array('rank_min', 'ranks.rank_min', array('typecast' => 'int', 'execute' => '{RESULT} = ({VALUE}[0] < 0) ? 0 : {VALUE}[0];')),
+ array('rank_special', 'ranks.rank_special', ''),
+ array('rank_image', 'ranks.rank_image', 'import_rank'),
+ ),
+
+ array(
+ 'target' => TOPICS_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . TOPICS_TABLE),
+ 'primary' => 'topics.topic_id',
+ 'autoincrement' => 'topic_id',
+
+ array('topic_id', 'topics.topic_id', ''),
+ array('forum_id', 'topics.forum_id', ''),
+ array('icon_id', 0, ''),
+ array('topic_poster', 'topics.topic_poster AS poster_id', 'phpbb_user_id'),
+ array('topic_attachment', ((defined('MOD_ATTACHMENT')) ? 'topics.topic_attachment' : 0), ''),
+ array('topic_title', 'topics.topic_title', 'phpbb_set_encoding'),
+ array('topic_time', 'topics.topic_time', ''),
+ array('topic_views', 'topics.topic_views', ''),
+ array('topic_posts_approved', 'topics.topic_replies', 'phpbb_topic_replies_to_posts'),
+ array('topic_posts_unapproved', 0, ''),
+ array('topic_posts_softdeleted',0, ''),
+ array('topic_last_post_id', 'topics.topic_last_post_id', ''),
+ array('topic_status', 'topics.topic_status', 'is_topic_locked'),
+ array('topic_moved_id', 0, ''),
+ array('topic_type', 'topics.topic_type', 'phpbb_convert_topic_type'),
+ array('topic_first_post_id', 'topics.topic_first_post_id', ''),
+ array('topic_last_view_time', 'posts.post_time', 'intval'),
+ array('topic_visibility', ITEM_APPROVED, ''),
+
+ array('poll_title', 'vote_desc.vote_text', array('function1' => 'null_to_str', 'function2' => 'phpbb_set_encoding', 'function3' => 'htmlspecialchars_decode', 'function4' => 'utf8_htmlspecialchars')),
+ array('poll_start', 'vote_desc.vote_start', 'null_to_zero'),
+ array('poll_length', 'vote_desc.vote_length', 'null_to_zero'),
+ array('poll_max_options', 1, ''),
+ array('poll_vote_change', 0, ''),
+
+ 'left_join' => array ( 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1',
+ 'topics LEFT JOIN posts ON topics.topic_last_post_id = posts.post_id',
+ ),
+ 'where' => 'topics.topic_moved_id = 0',
+ ),
+
+ array(
+ 'target' => TOPICS_TABLE,
+ 'primary' => 'topics.topic_id',
+ 'autoincrement' => 'topic_id',
+
+ array('topic_id', 'topics.topic_id', ''),
+ array('forum_id', 'topics.forum_id', ''),
+ array('icon_id', 0, ''),
+ array('topic_poster', 'topics.topic_poster AS poster_id', 'phpbb_user_id'),
+ array('topic_attachment', ((defined('MOD_ATTACHMENT')) ? 'topics.topic_attachment' : 0), ''),
+ array('topic_title', 'topics.topic_title', 'phpbb_set_encoding'),
+ array('topic_time', 'topics.topic_time', ''),
+ array('topic_views', 'topics.topic_views', ''),
+ array('topic_posts_approved', 'topics.topic_replies', 'phpbb_topic_replies_to_posts'),
+ array('topic_posts_unapproved', 0, ''),
+ array('topic_posts_softdeleted',0, ''),
+ array('topic_last_post_id', 'topics.topic_last_post_id', ''),
+ array('topic_status', ITEM_MOVED, ''),
+ array('topic_moved_id', 'topics.topic_moved_id', ''),
+ array('topic_type', 'topics.topic_type', 'phpbb_convert_topic_type'),
+ array('topic_first_post_id', 'topics.topic_first_post_id', ''),
+ array('topic_visibility', ITEM_APPROVED, ''),
+
+ array('poll_title', 'vote_desc.vote_text', array('function1' => 'null_to_str', 'function2' => 'phpbb_set_encoding', 'function3' => 'htmlspecialchars_decode', 'function4' => 'utf8_htmlspecialchars')),
+ array('poll_start', 'vote_desc.vote_start', 'null_to_zero'),
+ array('poll_length', 'vote_desc.vote_length', 'null_to_zero'),
+ array('poll_max_options', 1, ''),
+ array('poll_vote_change', 0, ''),
+
+ 'left_join' => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1',
+ 'where' => 'topics.topic_moved_id <> 0',
+ ),
+
+ array(
+ 'target' => TOPICS_WATCH_TABLE,
+ 'primary' => 'topics_watch.topic_id',
+ 'query_first' => array('target', $convert->truncate_statement . TOPICS_WATCH_TABLE),
+
+ array('topic_id', 'topics_watch.topic_id', ''),
+ array('user_id', 'topics_watch.user_id', 'phpbb_user_id'),
+ array('notify_status', 'topics_watch.notify_status', ''),
+ ),
+
+ array(
+ 'target' => SMILIES_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . SMILIES_TABLE),
+ 'autoincrement' => 'smiley_id',
+
+ array('smiley_id', 'smilies.smilies_id', ''),
+ array('code', 'smilies.code', array('function1' => 'phpbb_smilie_html_decode', 'function2' => 'phpbb_set_encoding', 'function3' => 'utf8_htmlspecialchars')),
+ array('emotion', 'smilies.emoticon', 'phpbb_set_encoding'),
+ array('smiley_url', 'smilies.smile_url', 'import_smiley'),
+ array('smiley_width', 'smilies.smile_url', 'get_smiley_width'),
+ array('smiley_height', 'smilies.smile_url', 'get_smiley_height'),
+ array('smiley_order', 'smilies.smilies_id', ''),
+ array('display_on_posting', 'smilies.smilies_id', 'get_smiley_display'),
+
+ 'order_by' => 'smilies.smilies_id ASC',
+ ),
+
+ array(
+ 'target' => POLL_OPTIONS_TABLE,
+ 'primary' => 'vote_results.vote_option_id',
+ 'query_first' => array('target', $convert->truncate_statement . POLL_OPTIONS_TABLE),
+
+ array('poll_option_id', 'vote_results.vote_option_id', ''),
+ array('topic_id', 'vote_desc.topic_id', ''),
+ array('', 'topics.topic_poster AS poster_id', 'phpbb_user_id'),
+ array('poll_option_text', 'vote_results.vote_option_text', array('function1' => 'phpbb_set_encoding', 'function2' => 'htmlspecialchars_decode', 'function3' => 'utf8_htmlspecialchars')),
+ array('poll_option_total', 'vote_results.vote_result', ''),
+
+ 'where' => 'vote_results.vote_id = vote_desc.vote_id',
+ 'left_join' => 'vote_desc LEFT JOIN topics ON topics.topic_id = vote_desc.topic_id',
+ ),
+
+ array(
+ 'target' => POLL_VOTES_TABLE,
+ 'primary' => 'vote_desc.topic_id',
+ 'query_first' => array('target', $convert->truncate_statement . POLL_VOTES_TABLE),
+
+ array('poll_option_id', VOTE_CONVERTED, ''),
+ array('topic_id', 'vote_desc.topic_id', ''),
+ array('vote_user_id', 'vote_voters.vote_user_id', 'phpbb_user_id'),
+ array('vote_user_ip', 'vote_voters.vote_user_ip', 'decode_ip'),
+
+ 'where' => 'vote_voters.vote_id = vote_desc.vote_id',
+ ),
+
+ array(
+ 'target' => WORDS_TABLE,
+ 'primary' => 'words.word_id',
+ 'query_first' => array('target', $convert->truncate_statement . WORDS_TABLE),
+ 'autoincrement' => 'word_id',
+
+ array('word_id', 'words.word_id', ''),
+ array('word', 'words.word', 'phpbb_set_encoding'),
+ array('replacement', 'words.replacement', 'phpbb_set_encoding'),
+ ),
+
+ array(
+ 'target' => POSTS_TABLE,
+ 'primary' => 'posts.post_id',
+ 'autoincrement' => 'post_id',
+ 'query_first' => array('target', $convert->truncate_statement . POSTS_TABLE),
+ 'execute_first' => '
+ $config["max_post_chars"] = 0;
+ $config["min_post_chars"] = 0;
+ $config["max_quote_depth"] = 0;
+ ',
+
+ array('post_id', 'posts.post_id', ''),
+ array('topic_id', 'posts.topic_id', ''),
+ array('forum_id', 'posts.forum_id', ''),
+ array('poster_id', 'posts.poster_id', 'phpbb_user_id'),
+ array('icon_id', 0, ''),
+ array('poster_ip', 'posts.poster_ip', 'decode_ip'),
+ array('post_time', 'posts.post_time', ''),
+ array('enable_bbcode', 'posts.enable_bbcode', ''),
+ array('', 'posts.enable_html', ''),
+ array('enable_smilies', 'posts.enable_smilies', ''),
+ array('enable_sig', 'posts.enable_sig', ''),
+ array('enable_magic_url', 1, ''),
+ array('post_username', 'posts.post_username', 'phpbb_set_encoding'),
+ array('post_subject', 'posts_text.post_subject', 'phpbb_set_encoding'),
+ array('post_attachment', ((defined('MOD_ATTACHMENT')) ? 'posts.post_attachment' : 0), ''),
+ array('post_edit_time', 'posts.post_edit_time', array('typecast' => 'int')),
+ array('post_edit_count', 'posts.post_edit_count', ''),
+ array('post_edit_reason', '', ''),
+ array('post_edit_user', '', 'phpbb_post_edit_user'),
+ array('post_visibility', ITEM_APPROVED, ''),
+
+ array('bbcode_uid', 'posts.post_time', 'make_uid'),
+ array('post_text', 'posts_text.post_text', 'phpbb_prepare_message'),
+ array('', 'posts_text.bbcode_uid AS old_bbcode_uid', ''),
+ array('bbcode_bitfield', '', 'get_bbcode_bitfield'),
+ array('post_checksum', '', ''),
+
+ // Commented out inline search indexing, this takes up a LOT of time. :D
+ // @todo We either need to enable this or call the rebuild search functionality post convert
+/* array('', '', 'search_indexing'),
+ array('', 'posts_text.post_text AS message', ''),
+ array('', 'posts_text.post_subject AS title', ''),*/
+
+ 'where' => 'posts.post_id = posts_text.post_id'
+ ),
+
+ array(
+ 'target' => PRIVMSGS_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+ 'autoincrement' => 'msg_id',
+ 'query_first' => array(
+ array('target', $convert->truncate_statement . PRIVMSGS_TABLE),
+ array('target', $convert->truncate_statement . PRIVMSGS_RULES_TABLE),
+ ),
+
+ 'execute_first' => '
+ $config["max_post_chars"] = 0;
+ $config["min_post_chars"] = 0;
+ $config["max_quote_depth"] = 0;
+ ',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('root_level', 0, ''),
+ array('author_id', 'privmsgs.privmsgs_from_userid AS poster_id', 'phpbb_user_id'),
+ array('icon_id', 0, ''),
+ array('author_ip', 'privmsgs.privmsgs_ip', 'decode_ip'),
+ array('message_time', 'privmsgs.privmsgs_date', ''),
+ array('enable_bbcode', 'privmsgs.privmsgs_enable_bbcode AS enable_bbcode', ''),
+ array('', 'privmsgs.privmsgs_enable_html AS enable_html', ''),
+ array('enable_smilies', 'privmsgs.privmsgs_enable_smilies AS enable_smilies', ''),
+ array('enable_magic_url', 1, ''),
+ array('enable_sig', 'privmsgs.privmsgs_attach_sig', ''),
+ array('message_subject', 'privmsgs.privmsgs_subject', 'phpbb_set_encoding'), // Already specialchared in 2.0.x
+ array('message_attachment', ((defined('MOD_ATTACHMENT')) ? 'privmsgs.privmsgs_attachment' : 0), ''),
+ array('message_edit_reason', '', ''),
+ array('message_edit_user', 0, ''),
+ array('message_edit_time', 0, ''),
+ array('message_edit_count', 0, ''),
+
+ array('bbcode_uid', 'privmsgs.privmsgs_date AS post_time', 'make_uid'),
+ array('message_text', 'privmsgs_text.privmsgs_text', 'phpbb_prepare_message'),
+ array('', 'privmsgs_text.privmsgs_bbcode_uid AS old_bbcode_uid', ''),
+ array('bbcode_bitfield', '', 'get_bbcode_bitfield'),
+ array('to_address', 'privmsgs.privmsgs_to_userid', 'phpbb_privmsgs_to_userid'),
+ array('bcc_address', '', ''),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id'
+ ),
+
+ array(
+ 'target' => PRIVMSGS_FOLDER_TABLE,
+ 'primary' => 'users.user_id',
+ 'query_first' => array('target', $convert->truncate_statement . PRIVMSGS_FOLDER_TABLE),
+
+ array('user_id', 'users.user_id', 'phpbb_user_id'),
+ array('folder_name', $user->lang['CONV_SAVED_MESSAGES'], ''),
+ array('pm_count', 0, ''),
+
+ 'where' => 'users.user_id <> -1',
+ ),
+
+ // Inbox
+ array(
+ 'target' => PRIVMSGS_TO_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+ 'query_first' => array('target', $convert->truncate_statement . PRIVMSGS_TO_TABLE),
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('user_id', 'privmsgs.privmsgs_to_userid', 'phpbb_user_id'),
+ array('author_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('pm_deleted', 0, ''),
+ array('pm_new', 'privmsgs.privmsgs_type', 'phpbb_new_pm'),
+ array('pm_unread', 'privmsgs.privmsgs_type', 'phpbb_unread_pm'),
+ array('pm_replied', 0, ''),
+ array('pm_marked', 0, ''),
+ array('pm_forwarded', 0, ''),
+ array('folder_id', PRIVMSGS_INBOX, ''),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id
+ AND (privmsgs.privmsgs_type = 0 OR privmsgs.privmsgs_type = 1 OR privmsgs.privmsgs_type = 5)',
+ ),
+
+ // Outbox
+ array(
+ 'target' => PRIVMSGS_TO_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('user_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('author_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('pm_deleted', 0, ''),
+ array('pm_new', 0, ''),
+ array('pm_unread', 0, ''),
+ array('pm_replied', 0, ''),
+ array('pm_marked', 0, ''),
+ array('pm_forwarded', 0, ''),
+ array('folder_id', PRIVMSGS_OUTBOX, ''),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id
+ AND (privmsgs.privmsgs_type = 1 OR privmsgs.privmsgs_type = 5)',
+ ),
+
+ // Sentbox
+ array(
+ 'target' => PRIVMSGS_TO_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('user_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('author_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('pm_deleted', 0, ''),
+ array('pm_new', 'privmsgs.privmsgs_type', 'phpbb_new_pm'),
+ array('pm_unread', 'privmsgs.privmsgs_type', 'phpbb_unread_pm'),
+ array('pm_replied', 0, ''),
+ array('pm_marked', 0, ''),
+ array('pm_forwarded', 0, ''),
+ array('folder_id', PRIVMSGS_SENTBOX, ''),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id
+ AND privmsgs.privmsgs_type = 2',
+ ),
+
+ // Savebox (SAVED IN)
+ array(
+ 'target' => PRIVMSGS_TO_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('user_id', 'privmsgs.privmsgs_to_userid', 'phpbb_user_id'),
+ array('author_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('pm_deleted', 0, ''),
+ array('pm_new', 'privmsgs.privmsgs_type', 'phpbb_new_pm'),
+ array('pm_unread', 'privmsgs.privmsgs_type', 'phpbb_unread_pm'),
+ array('pm_replied', 0, ''),
+ array('pm_marked', 0, ''),
+ array('pm_forwarded', 0, ''),
+ array('folder_id', 'privmsgs.privmsgs_to_userid', 'phpbb_get_savebox_id'),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id
+ AND privmsgs.privmsgs_type = 3',
+ ),
+
+ // Savebox (SAVED OUT)
+ array(
+ 'target' => PRIVMSGS_TO_TABLE,
+ 'primary' => 'privmsgs.privmsgs_id',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('user_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('author_id', 'privmsgs.privmsgs_from_userid', 'phpbb_user_id'),
+ array('pm_deleted', 0, ''),
+ array('pm_new', 'privmsgs.privmsgs_type', 'phpbb_new_pm'),
+ array('pm_unread', 'privmsgs.privmsgs_type', 'phpbb_unread_pm'),
+ array('pm_replied', 0, ''),
+ array('pm_marked', 0, ''),
+ array('pm_forwarded', 0, ''),
+ array('folder_id', 'privmsgs.privmsgs_from_userid', 'phpbb_get_savebox_id'),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id
+ AND privmsgs.privmsgs_type = 4',
+ ),
+
+ array(
+ 'target' => GROUPS_TABLE,
+ 'autoincrement' => 'group_id',
+ 'query_first' => array(
+ array('target', $convert->truncate_statement . GROUPS_TABLE),
+ array('target', $convert->truncate_statement . TEAMPAGE_TABLE),
+ ),
+
+ array('group_id', 'groups.group_id', ''),
+ array('group_type', 'groups.group_type', 'phpbb_convert_group_type'),
+ array('group_display', 0, ''),
+ array('group_legend', 0, ''),
+ array('group_name', 'groups.group_name', 'phpbb_convert_group_name'), // phpbb_set_encoding called in phpbb_convert_group_name
+ array('group_desc', 'groups.group_description', 'phpbb_set_encoding'),
+
+ 'where' => 'groups.group_single_user = 0',
+ ),
+
+ array(
+ 'target' => USER_GROUP_TABLE,
+ 'query_first' => array('target', $convert->truncate_statement . USER_GROUP_TABLE),
+ 'execute_first' => '
+ add_default_groups();
+ add_groups_to_teampage();
+ ',
+
+ array('group_id', 'groups.group_id', ''),
+ array('user_id', 'groups.group_moderator', 'phpbb_user_id'),
+ array('group_leader', 1, ''),
+ array('user_pending', 0, ''),
+
+ 'where' => 'groups.group_single_user = 0 AND groups.group_moderator <> 0',
+ ),
+
+ array(
+ 'target' => USER_GROUP_TABLE,
+
+ array('group_id', 'user_group.group_id', ''),
+ array('user_id', 'user_group.user_id', 'phpbb_user_id'),
+ array('group_leader', 0, ''),
+ array('user_pending', 'user_group.user_pending', ''),
+
+ 'where' => 'user_group.group_id = groups.group_id AND groups.group_single_user = 0 AND groups.group_moderator <> user_group.user_id',
+ ),
+
+ array(
+ 'target' => USERS_TABLE,
+ 'primary' => 'users.user_id',
+ 'autoincrement' => 'user_id',
+ 'query_first' => array(
+ array('target', 'DELETE FROM ' . USERS_TABLE . ' WHERE user_id <> ' . ANONYMOUS),
+ array('target', $convert->truncate_statement . BOTS_TABLE),
+ array('target', $convert->truncate_statement . USER_NOTIFICATIONS_TABLE),
+ ),
+
+ 'execute_last' => '
+ remove_invalid_users();
+ ',
+
+ array('user_id', 'users.user_id', 'phpbb_user_id'),
+ array('', 'users.user_id AS poster_id', 'phpbb_user_id'),
+ array('user_type', 'users.user_active', 'set_user_type'),
+ array('group_id', 'users.user_level', 'phpbb_set_primary_group'),
+ array('user_regdate', 'users.user_regdate', ''),
+ array('username', 'users.username', 'phpbb_set_default_encoding'), // recode to utf8 with default lang
+ array('username_clean', 'users.username', array('function1' => 'phpbb_set_default_encoding', 'function2' => 'utf8_clean_string')),
+ array('user_password', 'users.user_password', 'phpbb_convert_password_hash'),
+ array('user_posts', 'users.user_posts', 'intval'),
+ array('user_email', 'users.user_email', 'strtolower'),
+ array('user_email_hash', 'users.user_email', 'gen_email_hash'),
+ array('user_birthday', ((defined('MOD_BIRTHDAY')) ? 'users.user_birthday' : ''), 'phpbb_get_birthday'),
+ array('user_lastvisit', 'users.user_lastvisit', 'intval'),
+ array('user_lastmark', 'users.user_lastvisit', 'intval'),
+ array('user_lang', $config['default_lang'], ''),
+ array('', 'users.user_lang', ''),
+ array('user_timezone', 'users.user_timezone', 'phpbb_convert_timezone'),
+ array('user_dateformat', 'users.user_dateformat', array('function1' => 'phpbb_set_encoding', 'function2' => 'fill_dateformat')),
+ array('user_inactive_reason', '', 'phpbb_inactive_reason'),
+ array('user_inactive_time', '', 'phpbb_inactive_time'),
+
+ array('user_jabber', '', ''),
+ array('user_rank', 'users.user_rank', 'intval'),
+ array('user_permissions', '', ''),
+
+ array('user_avatar', 'users.user_avatar', 'phpbb_import_avatar'),
+ array('user_avatar_type', 'users.user_avatar_type', 'phpbb_avatar_type'),
+ array('user_avatar_width', 'users.user_avatar', 'phpbb_get_avatar_width'),
+ array('user_avatar_height', 'users.user_avatar', 'phpbb_get_avatar_height'),
+
+ array('user_new_privmsg', 'users.user_new_privmsg', ''),
+ array('user_unread_privmsg', 0, ''), //'users.user_unread_privmsg'
+ array('user_last_privmsg', 'users.user_last_privmsg', 'intval'),
+ array('user_emailtime', 'users.user_emailtime', 'null_to_zero'),
+ array('user_notify', 'users.user_notify', 'intval'),
+ array('user_notify_pm', 'users.user_notify_pm', 'intval'),
+ array('user_notify_type', NOTIFY_EMAIL, ''),
+ array('user_allow_pm', 'users.user_allow_pm', 'intval'),
+ array('user_allow_viewonline', 'users.user_allow_viewonline', 'intval'),
+ array('user_allow_viewemail', 'users.user_viewemail', 'intval'),
+ array('user_actkey', 'users.user_actkey', ''),
+ array('user_newpasswd', '', ''), // Users need to re-request their password...
+ array('user_style', $config['default_style'], ''),
+
+ array('user_options', '', 'set_user_options'),
+ array('', 'users.user_popup_pm AS popuppm', ''),
+ array('', 'users.user_allowhtml AS html', ''),
+ array('', 'users.user_allowbbcode AS bbcode', ''),
+ array('', 'users.user_allowsmile AS smile', ''),
+ array('', 'users.user_attachsig AS attachsig',''),
+
+ array('user_sig_bbcode_uid', 'users.user_regdate', 'make_uid'),
+ array('user_sig', 'users.user_sig', 'phpbb_prepare_message'),
+ array('', 'users.user_sig_bbcode_uid AS old_bbcode_uid', ''),
+ array('user_sig_bbcode_bitfield', '', 'get_bbcode_bitfield'),
+ array('', 'users.user_regdate AS post_time', ''),
+
+ array('', 'users.user_notify_pm', 'phpbb_add_notification_options'),
+
+ 'where' => 'users.user_id <> -1',
+ ),
+
+ array(
+ 'target' => PROFILE_FIELDS_DATA_TABLE,
+ 'primary' => 'users.user_id',
+ 'query_first' => array(
+ array('target', $convert->truncate_statement . PROFILE_FIELDS_DATA_TABLE),
+ ),
+
+ array('user_id', 'users.user_id', 'phpbb_user_id'),
+ array('pf_phpbb_occupation', 'users.user_occ', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_interests', 'users.user_interests', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_location', 'users.user_from', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_icq', 'users.user_icq', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_wlm', 'users.user_msnm', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_yahoo', 'users.user_yim', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_aol', 'users.user_aim', array('function1' => 'phpbb_set_encoding')),
+ array('pf_phpbb_website', 'users.user_website', 'validate_website'),
+
+ 'where' => 'users.user_id <> -1',
+ ),
+ ),
+ );
+}
diff --git a/phpBB/install_old/convertors/functions_phpbb20.php b/phpBB/install_old/convertors/functions_phpbb20.php
new file mode 100644
index 0000000000..48cff426b8
--- /dev/null
+++ b/phpBB/install_old/convertors/functions_phpbb20.php
@@ -0,0 +1,1984 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Helper functions for phpBB 2.0.x to phpBB 3.1.x conversion
+*/
+
+/**
+* Set forum flags - only prune old polls by default
+*/
+function phpbb_forum_flags()
+{
+ // Set forum flags
+ $forum_flags = 0;
+
+ // FORUM_FLAG_LINK_TRACK
+ $forum_flags += 0;
+
+ // FORUM_FLAG_PRUNE_POLL
+ $forum_flags += FORUM_FLAG_PRUNE_POLL;
+
+ // FORUM_FLAG_PRUNE_ANNOUNCE
+ $forum_flags += 0;
+
+ // FORUM_FLAG_PRUNE_STICKY
+ $forum_flags += 0;
+
+ // FORUM_FLAG_ACTIVE_TOPICS
+ $forum_flags += 0;
+
+ // FORUM_FLAG_POST_REVIEW
+ $forum_flags += FORUM_FLAG_POST_REVIEW;
+
+ return $forum_flags;
+}
+
+/**
+* Insert/Convert forums
+*/
+function phpbb_insert_forums()
+{
+ global $db, $src_db, $same_db, $convert, $user, $config;
+
+ $db->sql_query($convert->truncate_statement . FORUMS_TABLE);
+
+ // Determine the highest id used within the old forums table (we add the categories after the forum ids)
+ $sql = 'SELECT MAX(forum_id) AS max_forum_id
+ FROM ' . $convert->src_table_prefix . 'forums';
+ $result = $src_db->sql_query($sql);
+ $max_forum_id = (int) $src_db->sql_fetchfield('max_forum_id');
+ $src_db->sql_freeresult($result);
+
+ $max_forum_id++;
+
+ // pruning disabled globally?
+ $sql = "SELECT config_value
+ FROM {$convert->src_table_prefix}config
+ WHERE config_name = 'prune_enable'";
+ $result = $src_db->sql_query($sql);
+ $prune_enabled = (int) $src_db->sql_fetchfield('config_value');
+ $src_db->sql_freeresult($result);
+
+ // Insert categories
+ $sql = 'SELECT cat_id, cat_title
+ FROM ' . $convert->src_table_prefix . 'categories
+ ORDER BY cat_order';
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $result = $src_db->sql_query($sql);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ switch ($db->get_sql_layer())
+ {
+ case 'mssql':
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . FORUMS_TABLE . ' ON');
+ break;
+ }
+
+ $cats_added = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $sql_ary = array(
+ 'forum_id' => (int) $max_forum_id,
+ 'forum_name' => ($row['cat_title']) ? htmlspecialchars(phpbb_set_default_encoding($row['cat_title']), ENT_COMPAT, 'UTF-8') : $user->lang['CATEGORY'],
+ 'parent_id' => 0,
+ 'forum_parents' => '',
+ 'forum_desc' => '',
+ 'forum_type' => FORUM_CAT,
+ 'forum_status' => ITEM_UNLOCKED,
+ 'forum_rules' => '',
+ );
+
+ $sql = 'SELECT MAX(right_id) AS right_id
+ FROM ' . FORUMS_TABLE;
+ $_result = $db->sql_query($sql);
+ $cat_row = $db->sql_fetchrow($_result);
+ $db->sql_freeresult($_result);
+
+ $sql_ary['left_id'] = (int) ($cat_row['right_id'] + 1);
+ $sql_ary['right_id'] = (int) ($cat_row['right_id'] + 2);
+
+ $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
+ $db->sql_query($sql);
+
+ $cats_added[$row['cat_id']] = $max_forum_id;
+ $max_forum_id++;
+ }
+ $src_db->sql_freeresult($result);
+
+ // There may be installations having forums with non-existant category ids.
+ // We try to catch them and add them to an "unknown" category instead of leaving them out.
+ $sql = 'SELECT cat_id
+ FROM ' . $convert->src_table_prefix . 'forums
+ GROUP BY cat_id';
+ $result = $src_db->sql_query($sql);
+
+ $unknown_cat_id = false;
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ // Catch those categories not been added before
+ if (!isset($cats_added[$row['cat_id']]))
+ {
+ $unknown_cat_id = true;
+ }
+ }
+ $src_db->sql_freeresult($result);
+
+ // Is there at least one category not known?
+ if ($unknown_cat_id === true)
+ {
+ $unknown_cat_id = 'ghost';
+
+ $sql_ary = array(
+ 'forum_id' => (int) $max_forum_id,
+ 'forum_name' => (string) $user->lang['CATEGORY'],
+ 'parent_id' => 0,
+ 'forum_parents' => '',
+ 'forum_desc' => '',
+ 'forum_type' => FORUM_CAT,
+ 'forum_status' => ITEM_UNLOCKED,
+ 'forum_rules' => '',
+ );
+
+ $sql = 'SELECT MAX(right_id) AS right_id
+ FROM ' . FORUMS_TABLE;
+ $_result = $db->sql_query($sql);
+ $cat_row = $db->sql_fetchrow($_result);
+ $db->sql_freeresult($_result);
+
+ $sql_ary['left_id'] = (int) ($cat_row['right_id'] + 1);
+ $sql_ary['right_id'] = (int) ($cat_row['right_id'] + 2);
+
+ $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
+ $db->sql_query($sql);
+
+ $cats_added[$unknown_cat_id] = $max_forum_id;
+ $max_forum_id++;
+ }
+
+ // Now insert the forums
+ $sql = 'SELECT f.forum_id, f.forum_name, f.cat_id, f.forum_desc, f.forum_status, f.prune_enable, f.prune_next, fp.prune_days, fp.prune_freq FROM ' . $convert->src_table_prefix . 'forums f
+ LEFT JOIN ' . $convert->src_table_prefix . 'forum_prune fp ON f.forum_id = fp.forum_id
+ GROUP BY f.forum_id, f.forum_name, f.cat_id, f.forum_desc, f.forum_status, f.prune_enable, f.prune_next, f.forum_order, fp.prune_days, fp.prune_freq
+ ORDER BY f.cat_id, f.forum_order';
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $result = $src_db->sql_query($sql);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ // Some might have forums here with an id not being "possible"...
+ // To be somewhat friendly we "change" the category id for those to a previously created ghost category
+ if (!isset($cats_added[$row['cat_id']]) && $unknown_cat_id !== false)
+ {
+ $row['cat_id'] = $unknown_cat_id;
+ }
+
+ if (!isset($cats_added[$row['cat_id']]))
+ {
+ continue;
+ }
+
+ // Define the new forums sql ary
+ $sql_ary = array(
+ 'forum_id' => (int) $row['forum_id'],
+ 'forum_name' => htmlspecialchars(phpbb_set_default_encoding($row['forum_name']), ENT_COMPAT, 'UTF-8'),
+ 'parent_id' => (int) $cats_added[$row['cat_id']],
+ 'forum_parents' => '',
+ 'forum_desc' => htmlspecialchars(phpbb_set_default_encoding($row['forum_desc']), ENT_COMPAT, 'UTF-8'),
+ 'forum_type' => FORUM_POST,
+ 'forum_status' => is_item_locked($row['forum_status']),
+ 'enable_prune' => ($prune_enabled) ? (int) $row['prune_enable'] : 0,
+ 'prune_next' => (int) null_to_zero($row['prune_next']),
+ 'prune_days' => (int) null_to_zero($row['prune_days']),
+ 'prune_viewed' => 0,
+ 'prune_freq' => (int) null_to_zero($row['prune_freq']),
+
+ 'forum_flags' => phpbb_forum_flags(),
+ 'forum_options' => 0,
+
+ // Default values
+ 'forum_desc_bitfield' => '',
+ 'forum_desc_options' => 7,
+ 'forum_desc_uid' => '',
+ 'forum_link' => '',
+ 'forum_password' => '',
+ 'forum_style' => 0,
+ 'forum_image' => '',
+ 'forum_rules' => '',
+ 'forum_rules_link' => '',
+ 'forum_rules_bitfield' => '',
+ 'forum_rules_options' => 7,
+ 'forum_rules_uid' => '',
+ 'forum_topics_per_page' => 0,
+ 'forum_posts_approved' => 0,
+ 'forum_posts_unapproved' => 0,
+ 'forum_posts_softdeleted' => 0,
+ 'forum_topics_approved' => 0,
+ 'forum_topics_unapproved' => 0,
+ 'forum_topics_softdeleted' => 0,
+ 'forum_last_post_id' => 0,
+ 'forum_last_poster_id' => 0,
+ 'forum_last_post_subject' => '',
+ 'forum_last_post_time' => 0,
+ 'forum_last_poster_name' => '',
+ 'forum_last_poster_colour' => '',
+ 'display_on_index' => 1,
+ 'enable_indexing' => 1,
+ 'enable_icons' => 0,
+ );
+
+ // Now add the forums with proper left/right ids
+ $sql = 'SELECT left_id, right_id
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . $cats_added[$row['cat_id']];
+ $_result = $db->sql_query($sql);
+ $cat_row = $db->sql_fetchrow($_result);
+ $db->sql_freeresult($_result);
+
+ $sql = 'UPDATE ' . FORUMS_TABLE . '
+ SET left_id = left_id + 2, right_id = right_id + 2
+ WHERE left_id > ' . $cat_row['right_id'];
+ $db->sql_query($sql);
+
+ $sql = 'UPDATE ' . FORUMS_TABLE . '
+ SET right_id = right_id + 2
+ WHERE ' . $cat_row['left_id'] . ' BETWEEN left_id AND right_id';
+ $db->sql_query($sql);
+
+ $sql_ary['left_id'] = (int) $cat_row['right_id'];
+ $sql_ary['right_id'] = (int) ($cat_row['right_id'] + 1);
+
+ $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
+ $db->sql_query($sql);
+ }
+ $src_db->sql_freeresult($result);
+
+ switch ($db->get_sql_layer())
+ {
+ case 'postgres':
+ $db->sql_query("SELECT SETVAL('" . FORUMS_TABLE . "_seq',(select case when max(forum_id)>0 then max(forum_id)+1 else 1 end from " . FORUMS_TABLE . '));');
+ break;
+
+ case 'mssql':
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . FORUMS_TABLE . ' OFF');
+ break;
+
+ case 'oracle':
+ $result = $db->sql_query('SELECT MAX(forum_id) as max_id FROM ' . FORUMS_TABLE);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $largest_id = (int) $row['max_id'];
+
+ if ($largest_id)
+ {
+ $db->sql_query('DROP SEQUENCE ' . FORUMS_TABLE . '_seq');
+ $db->sql_query('CREATE SEQUENCE ' . FORUMS_TABLE . '_seq START WITH ' . ($largest_id + 1));
+ }
+ break;
+ }
+}
+
+/**
+* Function for recoding text with the default language
+*
+* @param string $text text to recode to utf8
+* @param bool $grab_user_lang if set to true the function tries to use $convert_row['user_lang'] (and falls back to $convert_row['poster_id']) instead of the boards default language
+*/
+function phpbb_set_encoding($text, $grab_user_lang = true)
+{
+ global $lang_enc_array, $convert_row;
+ global $convert, $phpEx;
+
+ /*static $lang_enc_array = array(
+ 'korean' => 'euc-kr',
+ 'serbian' => 'windows-1250',
+ 'polish' => 'iso-8859-2',
+ 'kurdish' => 'windows-1254',
+ 'slovak' => 'Windows-1250',
+ 'russian' => 'windows-1251',
+ 'estonian' => 'iso-8859-4',
+ 'chinese_simplified' => 'gb2312',
+ 'macedonian' => 'windows-1251',
+ 'azerbaijani' => 'UTF-8',
+ 'romanian' => 'iso-8859-2',
+ 'romanian_diacritice' => 'iso-8859-2',
+ 'lithuanian' => 'windows-1257',
+ 'turkish' => 'iso-8859-9',
+ 'ukrainian' => 'windows-1251',
+ 'japanese' => 'shift_jis',
+ 'hungarian' => 'ISO-8859-2',
+ 'romanian_no_diacritics' => 'iso-8859-2',
+ 'mongolian' => 'UTF-8',
+ 'slovenian' => 'windows-1250',
+ 'bosnian' => 'windows-1250',
+ 'czech' => 'Windows-1250',
+ 'farsi' => 'Windows-1256',
+ 'croatian' => 'windows-1250',
+ 'greek' => 'iso-8859-7',
+ 'russian_tu' => 'windows-1251',
+ 'sakha' => 'UTF-8',
+ 'serbian_cyrillic' => 'windows-1251',
+ 'bulgarian' => 'windows-1251',
+ 'chinese_traditional_taiwan' => 'big5',
+ 'chinese_traditional' => 'big5',
+ 'arabic' => 'windows-1256',
+ 'hebrew' => 'WINDOWS-1255',
+ 'thai' => 'windows-874',
+ //'chinese_traditional_taiwan' => 'utf-8' // custom modified, we may have to do an include :-(
+ );*/
+
+ if (empty($lang_enc_array))
+ {
+ $lang_enc_array = array();
+ }
+
+ $get_lang = trim(get_config_value('default_lang'));
+
+ // Do we need the users language encoding?
+ if ($grab_user_lang && !empty($convert_row))
+ {
+ if (!empty($convert_row['user_lang']))
+ {
+ $get_lang = trim($convert_row['user_lang']);
+ }
+ else if (!empty($convert_row['poster_id']))
+ {
+ global $src_db, $same_db;
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $sql = 'SELECT user_lang
+ FROM ' . $convert->src_table_prefix . 'users
+ WHERE user_id = ' . (int) $convert_row['poster_id'];
+ $result = $src_db->sql_query($sql);
+ $get_lang = (string) $src_db->sql_fetchfield('user_lang');
+ $src_db->sql_freeresult($result);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ $get_lang = (!trim($get_lang)) ? trim(get_config_value('default_lang')) : trim($get_lang);
+ }
+ }
+
+ if (!isset($lang_enc_array[$get_lang]))
+ {
+ $filename = $convert->options['forum_path'] . '/language/lang_' . $get_lang . '/lang_main.' . $phpEx;
+
+ if (!file_exists($filename))
+ {
+ $get_lang = trim(get_config_value('default_lang'));
+ }
+
+ if (!isset($lang_enc_array[$get_lang]))
+ {
+ include($convert->options['forum_path'] . '/language/lang_' . $get_lang . '/lang_main.' . $phpEx);
+ $lang_enc_array[$get_lang] = $lang['ENCODING'];
+ unset($lang);
+ }
+ }
+
+ $encoding = $lang_enc_array[$get_lang];
+
+ return utf8_recode($text, $lang_enc_array[$get_lang]);
+}
+
+/**
+* Same as phpbb_set_encoding, but forcing boards default language
+*/
+function phpbb_set_default_encoding($text)
+{
+ return phpbb_set_encoding($text, false);
+}
+
+/**
+* Convert Birthday from Birthday MOD to phpBB Format
+*/
+function phpbb_get_birthday($birthday = '')
+{
+ if (defined('MOD_BIRTHDAY_TERRA'))
+ {
+ $birthday = (string) $birthday;
+
+ // stored as month, day, year
+ if (!$birthday)
+ {
+ return ' 0- 0- 0';
+ }
+
+ // We use the original mod code to retrieve the birthday (not ideal)
+ preg_match('/(..)(..)(....)/', sprintf('%08d', $birthday), $birthday_parts);
+
+ $month = $birthday_parts[1];
+ $day = $birthday_parts[2];
+ $year = $birthday_parts[3];
+
+ return sprintf('%2d-%2d-%4d', $day, $month, $year);
+ }
+ else
+ {
+ $birthday = (int) $birthday;
+
+ if (!$birthday || $birthday == 999999)
+ {
+ return ' 0- 0- 0';
+ }
+
+ // The birthday mod from niels is using this code to transform to day/month/year
+ return sprintf('%2d-%2d-%4d', gmdate('j', $birthday * 86400 + 1), gmdate('n', $birthday * 86400 + 1), gmdate('Y', $birthday * 86400 + 1));
+ }
+}
+
+/**
+* Return correct user id value
+* Everyone's id will be one higher to allow the guest/anonymous user to have a positive id as well
+*/
+function phpbb_user_id($user_id)
+{
+ global $config;
+
+ // Increment user id if the old forum is having a user with the id 1
+ if (!isset($config['increment_user_id']))
+ {
+ global $src_db, $same_db, $convert;
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ // Now let us set a temporary config variable for user id incrementing
+ $sql = "SELECT user_id
+ FROM {$convert->src_table_prefix}users
+ WHERE user_id = 1";
+ $result = $src_db->sql_query($sql);
+ $id = (int) $src_db->sql_fetchfield('user_id');
+ $src_db->sql_freeresult($result);
+
+ // Try to get the maximum user id possible...
+ $sql = "SELECT MAX(user_id) AS max_user_id
+ FROM {$convert->src_table_prefix}users";
+ $result = $src_db->sql_query($sql);
+ $max_id = (int) $src_db->sql_fetchfield('max_user_id');
+ $src_db->sql_freeresult($result);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ // If there is a user id 1, we need to increment user ids. :/
+ if ($id === 1)
+ {
+ $config->set('increment_user_id', ($max_id + 1), false);
+ $config['increment_user_id'] = $max_id + 1;
+ }
+ else
+ {
+ $config->set('increment_user_id', 0, false);
+ $config['increment_user_id'] = 0;
+ }
+ }
+
+ // If the old user id is -1 in 2.0.x it is the anonymous user...
+ if ($user_id == -1)
+ {
+ return ANONYMOUS;
+ }
+
+ if (!empty($config['increment_user_id']) && $user_id == 1)
+ {
+ return $config['increment_user_id'];
+ }
+
+ // A user id of 0 can happen, for example within the ban table if no user is banned...
+ // Within the posts and topics table this can be "dangerous" but is the fault of the user
+ // having mods installed (a poster id of 0 is not possible in 2.0.x).
+ // Therefore, we return the user id "as is".
+
+ return (int) $user_id;
+}
+
+/**
+* Return correct user id value
+* Everyone's id will be one higher to allow the guest/anonymous user to have a positive id as well
+*/
+function phpbb_topic_replies_to_posts($num_replies)
+{
+ return (int) $num_replies + 1;
+}
+
+/* Copy additional table fields from old forum to new forum if user wants this (for Mod compatibility for example)
+function phpbb_copy_table_fields()
+{
+}
+*/
+
+/**
+* Convert authentication
+* user, group and forum table has to be filled in order to work
+*/
+function phpbb_convert_authentication($mode)
+{
+ global $db, $src_db, $same_db, $convert, $user, $config, $cache;
+
+ if ($mode == 'start')
+ {
+ $db->sql_query($convert->truncate_statement . ACL_USERS_TABLE);
+ $db->sql_query($convert->truncate_statement . ACL_GROUPS_TABLE);
+
+ // What we will do is handling all 2.0.x admins as founder to replicate what is common in 2.0.x.
+ // After conversion the main admin need to make sure he is removing permissions and the founder status if wanted.
+
+ // Grab user ids of users with user_level of ADMIN
+ $sql = "SELECT user_id
+ FROM {$convert->src_table_prefix}users
+ WHERE user_level = 1
+ ORDER BY user_regdate ASC";
+ $result = $src_db->sql_query($sql);
+
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $user_id = (int) phpbb_user_id($row['user_id']);
+ // Set founder admin...
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET user_type = ' . USER_FOUNDER . "
+ WHERE user_id = $user_id";
+ $db->sql_query($sql);
+ }
+ $src_db->sql_freeresult($result);
+
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = '" . $db->sql_escape('BOTS') . "'";
+ $result = $db->sql_query($sql);
+ $bot_group_id = (int) $db->sql_fetchfield('group_id');
+ $db->sql_freeresult($result);
+ }
+
+ // Grab forum auth information
+ $sql = "SELECT *
+ FROM {$convert->src_table_prefix}forums";
+ $result = $src_db->sql_query($sql);
+
+ $forum_access = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $forum_access[$row['forum_id']] = $row;
+ }
+ $src_db->sql_freeresult($result);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+ // Grab user auth information from 2.0.x board
+ $sql = "SELECT ug.user_id, aa.*
+ FROM {$convert->src_table_prefix}auth_access aa, {$convert->src_table_prefix}user_group ug, {$convert->src_table_prefix}groups g, {$convert->src_table_prefix}forums f
+ WHERE g.group_id = aa.group_id
+ AND g.group_single_user = 1
+ AND ug.group_id = g.group_id
+ AND f.forum_id = aa.forum_id";
+ $result = $src_db->sql_query($sql);
+
+ $user_access = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $user_access[$row['forum_id']][] = $row;
+ }
+ $src_db->sql_freeresult($result);
+
+ // Grab group auth information
+ $sql = "SELECT g.group_id, aa.*
+ FROM {$convert->src_table_prefix}auth_access aa, {$convert->src_table_prefix}groups g
+ WHERE g.group_id = aa.group_id
+ AND g.group_single_user <> 1";
+ $result = $src_db->sql_query($sql);
+
+ $group_access = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $group_access[$row['forum_id']][] = $row;
+ }
+ $src_db->sql_freeresult($result);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ // Add Forum Access List
+ $auth_map = array(
+ 'auth_view' => array('f_', 'f_list'),
+ 'auth_read' => array('f_read', 'f_search'),
+ 'auth_post' => array('f_post', 'f_bbcode', 'f_smilies', 'f_img', 'f_sigs', 'f_postcount', 'f_report', 'f_subscribe', 'f_print', 'f_email'),
+ 'auth_reply' => 'f_reply',
+ 'auth_edit' => 'f_edit',
+ 'auth_delete' => 'f_delete',
+ 'auth_pollcreate' => 'f_poll',
+ 'auth_vote' => 'f_vote',
+ 'auth_announce' => 'f_announce',
+ 'auth_sticky' => 'f_sticky',
+ 'auth_attachments' => array('f_attach', 'f_download'),
+ 'auth_download' => 'f_download',
+ );
+
+ // Define the ACL constants used in 2.0 to make the code slightly more readable
+ define('AUTH_ALL', 0);
+ define('AUTH_REG', 1);
+ define('AUTH_ACL', 2);
+ define('AUTH_MOD', 3);
+ define('AUTH_ADMIN', 5);
+
+ // A mapping of the simple permissions used by 2.0
+ $simple_auth_ary = array(
+ 'public' => array(
+ 'auth_view' => AUTH_ALL,
+ 'auth_read' => AUTH_ALL,
+ 'auth_post' => AUTH_ALL,
+ 'auth_reply' => AUTH_ALL,
+ 'auth_edit' => AUTH_REG,
+ 'auth_delete' => AUTH_REG,
+ 'auth_sticky' => AUTH_MOD,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_REG,
+ 'auth_pollcreate' => AUTH_REG,
+ ),
+ 'registered' => array(
+ 'auth_view' => AUTH_ALL,
+ 'auth_read' => AUTH_ALL,
+ 'auth_post' => AUTH_REG,
+ 'auth_reply' => AUTH_REG,
+ 'auth_edit' => AUTH_REG,
+ 'auth_delete' => AUTH_REG,
+ 'auth_sticky' => AUTH_MOD,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_REG,
+ 'auth_pollcreate' => AUTH_REG,
+ ),
+ 'registered_hidden' => array(
+ 'auth_view' => AUTH_REG,
+ 'auth_read' => AUTH_REG,
+ 'auth_post' => AUTH_REG,
+ 'auth_reply' => AUTH_REG,
+ 'auth_edit' => AUTH_REG,
+ 'auth_delete' => AUTH_REG,
+ 'auth_sticky' => AUTH_MOD,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_REG,
+ 'auth_pollcreate' => AUTH_REG,
+ ),
+ 'private' => array(
+ 'auth_view' => AUTH_ALL,
+ 'auth_read' => AUTH_ACL,
+ 'auth_post' => AUTH_ACL,
+ 'auth_reply' => AUTH_ACL,
+ 'auth_edit' => AUTH_ACL,
+ 'auth_delete' => AUTH_ACL,
+ 'auth_sticky' => AUTH_ACL,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_ACL,
+ 'auth_pollcreate' => AUTH_ACL,
+ ),
+ 'private_hidden' => array(
+ 'auth_view' => AUTH_ACL,
+ 'auth_read' => AUTH_ACL,
+ 'auth_post' => AUTH_ACL,
+ 'auth_reply' => AUTH_ACL,
+ 'auth_edit' => AUTH_ACL,
+ 'auth_delete' => AUTH_ACL,
+ 'auth_sticky' => AUTH_ACL,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_ACL,
+ 'auth_pollcreate' => AUTH_ACL,
+ ),
+ 'moderator' => array(
+ 'auth_view' => AUTH_ALL,
+ 'auth_read' => AUTH_MOD,
+ 'auth_post' => AUTH_MOD,
+ 'auth_reply' => AUTH_MOD,
+ 'auth_edit' => AUTH_MOD,
+ 'auth_delete' => AUTH_MOD,
+ 'auth_sticky' => AUTH_MOD,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_MOD,
+ 'auth_pollcreate' => AUTH_MOD,
+ ),
+ 'moderator_hidden' => array(
+ 'auth_view' => AUTH_MOD,
+ 'auth_read' => AUTH_MOD,
+ 'auth_post' => AUTH_MOD,
+ 'auth_reply' => AUTH_MOD,
+ 'auth_edit' => AUTH_MOD,
+ 'auth_delete' => AUTH_MOD,
+ 'auth_sticky' => AUTH_MOD,
+ 'auth_announce' => AUTH_MOD,
+ 'auth_vote' => AUTH_MOD,
+ 'auth_pollcreate' => AUTH_MOD,
+ ),
+ );
+
+ if ($mode == 'start')
+ {
+ user_group_auth('guests', 'SELECT user_id, {GUESTS} FROM ' . USERS_TABLE . ' WHERE user_id = ' . ANONYMOUS, false);
+ user_group_auth('registered', 'SELECT user_id, {REGISTERED} FROM ' . USERS_TABLE . ' WHERE user_id <> ' . ANONYMOUS . " AND group_id <> $bot_group_id", false);
+
+ // Selecting from old table
+ if (!empty($config['increment_user_id']))
+ {
+ $auth_sql = 'SELECT user_id, {ADMINISTRATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1 AND user_id <> 1';
+ user_group_auth('administrators', $auth_sql, true);
+
+ $auth_sql = 'SELECT ' . $config['increment_user_id'] . ' as user_id, {ADMINISTRATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1 AND user_id = 1';
+ user_group_auth('administrators', $auth_sql, true);
+ }
+ else
+ {
+ $auth_sql = 'SELECT user_id, {ADMINISTRATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1';
+ user_group_auth('administrators', $auth_sql, true);
+ }
+
+ if (!empty($config['increment_user_id']))
+ {
+ $auth_sql = 'SELECT user_id, {GLOBAL_MODERATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1 AND user_id <> 1';
+ user_group_auth('global_moderators', $auth_sql, true);
+
+ $auth_sql = 'SELECT ' . $config['increment_user_id'] . ' as user_id, {GLOBAL_MODERATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1 AND user_id = 1';
+ user_group_auth('global_moderators', $auth_sql, true);
+ }
+ else
+ {
+ $auth_sql = 'SELECT user_id, {GLOBAL_MODERATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1';
+ user_group_auth('global_moderators', $auth_sql, true);
+ }
+ }
+ else if ($mode == 'first')
+ {
+ // Go through all 2.0.x forums
+ foreach ($forum_access as $forum)
+ {
+ $new_forum_id = (int) $forum['forum_id'];
+
+ // Administrators have full access to all forums whatever happens
+ mass_auth('group_role', $new_forum_id, 'administrators', 'FORUM_FULL');
+
+ $matched_type = '';
+ foreach ($simple_auth_ary as $key => $auth_levels)
+ {
+ $matched = 1;
+ foreach ($auth_levels as $k => $level)
+ {
+ if ($forum[$k] != $auth_levels[$k])
+ {
+ $matched = 0;
+ }
+ }
+
+ if ($matched)
+ {
+ $matched_type = $key;
+ break;
+ }
+ }
+
+ switch ($matched_type)
+ {
+ case 'public':
+ mass_auth('group_role', $new_forum_id, 'guests', 'FORUM_LIMITED');
+ mass_auth('group_role', $new_forum_id, 'registered', 'FORUM_LIMITED_POLLS');
+ mass_auth('group_role', $new_forum_id, 'bots', 'FORUM_BOT');
+ break;
+
+ case 'registered':
+ mass_auth('group_role', $new_forum_id, 'guests', 'FORUM_READONLY');
+ mass_auth('group_role', $new_forum_id, 'bots', 'FORUM_BOT');
+
+ // no break;
+
+ case 'registered_hidden':
+ mass_auth('group_role', $new_forum_id, 'registered', 'FORUM_POLLS');
+ break;
+
+ case 'private':
+ case 'private_hidden':
+ case 'moderator':
+ case 'moderator_hidden':
+ default:
+ // The permissions don't match a simple set, so we're going to have to map them directly
+
+ // No post approval for all, in 2.0.x this feature does not exist
+ mass_auth('group', $new_forum_id, 'guests', 'f_noapprove', ACL_YES);
+ mass_auth('group', $new_forum_id, 'registered', 'f_noapprove', ACL_YES);
+
+ // Go through authentication map
+ foreach ($auth_map as $old_auth_key => $new_acl)
+ {
+ // If old authentication key does not exist we continue
+ // This is helpful for mods adding additional authentication fields, we need to add them to the auth_map array
+ if (!isset($forum[$old_auth_key]))
+ {
+ continue;
+ }
+
+ // Now set the new ACL correctly
+ switch ($forum[$old_auth_key])
+ {
+ // AUTH_ALL
+ case AUTH_ALL:
+ mass_auth('group', $new_forum_id, 'guests', $new_acl, ACL_YES);
+ mass_auth('group', $new_forum_id, 'bots', $new_acl, ACL_YES);
+ mass_auth('group', $new_forum_id, 'registered', $new_acl, ACL_YES);
+ break;
+
+ // AUTH_REG
+ case AUTH_REG:
+ mass_auth('group', $new_forum_id, 'registered', $new_acl, ACL_YES);
+ break;
+
+ // AUTH_ACL
+ case AUTH_ACL:
+ // Go through the old group access list for this forum
+ if (isset($group_access[$forum['forum_id']]))
+ {
+ foreach ($group_access[$forum['forum_id']] as $index => $access)
+ {
+ // We only check for ACL_YES equivalence entry
+ if (isset($access[$old_auth_key]) && $access[$old_auth_key] == 1)
+ {
+ mass_auth('group', $new_forum_id, (int) $access['group_id'], $new_acl, ACL_YES);
+ }
+ }
+ }
+
+ if (isset($user_access[$forum['forum_id']]))
+ {
+ foreach ($user_access[$forum['forum_id']] as $index => $access)
+ {
+ // We only check for ACL_YES equivalence entry
+ if (isset($access[$old_auth_key]) && $access[$old_auth_key] == 1)
+ {
+ mass_auth('user', $new_forum_id, (int) phpbb_user_id($access['user_id']), $new_acl, ACL_YES);
+ }
+ }
+ }
+ break;
+
+ // AUTH_MOD
+ case AUTH_MOD:
+ if (isset($group_access[$forum['forum_id']]))
+ {
+ foreach ($group_access[$forum['forum_id']] as $index => $access)
+ {
+ // We only check for ACL_YES equivalence entry
+ if (isset($access[$old_auth_key]) && $access[$old_auth_key] == 1)
+ {
+ mass_auth('group', $new_forum_id, (int) $access['group_id'], $new_acl, ACL_YES);
+ }
+ }
+ }
+
+ if (isset($user_access[$forum['forum_id']]))
+ {
+ foreach ($user_access[$forum['forum_id']] as $index => $access)
+ {
+ // We only check for ACL_YES equivalence entry
+ if (isset($access[$old_auth_key]) && $access[$old_auth_key] == 1)
+ {
+ mass_auth('user', $new_forum_id, (int) phpbb_user_id($access['user_id']), $new_acl, ACL_YES);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if ($mode == 'second')
+ {
+ // Assign permission roles and other default permissions
+
+ // guests having u_download and u_search ability
+ $db->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) SELECT ' . get_group_id('guests') . ', 0, auth_option_id, 0, 1 FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option IN ('u_', 'u_download', 'u_search')");
+
+ // administrators/global mods having full user features
+ mass_auth('group_role', 0, 'administrators', 'USER_FULL');
+ mass_auth('group_role', 0, 'global_moderators', 'USER_FULL');
+
+ // By default all converted administrators are given full access
+ mass_auth('group_role', 0, 'administrators', 'ADMIN_FULL');
+
+ // All registered users are assigned the standard user role
+ mass_auth('group_role', 0, 'registered', 'USER_STANDARD');
+ mass_auth('group_role', 0, 'registered_coppa', 'USER_STANDARD');
+
+ // Instead of administrators being global moderators we give the MOD_FULL role to global mods (admins already assigned to this group)
+ mass_auth('group_role', 0, 'global_moderators', 'MOD_FULL');
+
+ // And now those who have had their avatar rights removed get assigned a more restrictive role
+ $sql = 'SELECT user_id FROM ' . $convert->src_table_prefix . 'users
+ WHERE user_allowavatar = 0
+ AND user_id > 0';
+ $result = $src_db->sql_query($sql);
+
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ mass_auth('user_role', 0, (int) phpbb_user_id($row['user_id']), 'USER_NOAVATAR');
+ }
+ $src_db->sql_freeresult($result);
+
+ // And the same for those who have had their PM rights removed
+ $sql = 'SELECT user_id FROM ' . $convert->src_table_prefix . 'users
+ WHERE user_allow_pm = 0
+ AND user_id > 0';
+ $result = $src_db->sql_query($sql);
+
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ mass_auth('user_role', 0, (int) phpbb_user_id($row['user_id']), 'USER_NOPM');
+ }
+ $src_db->sql_freeresult($result);
+ }
+ else if ($mode == 'third')
+ {
+ // And now the moderators
+ // We make sure that they have at least standard access to the forums they moderate in addition to the moderating permissions
+
+ $mod_post_map = array(
+ 'auth_announce' => 'f_announce',
+ 'auth_sticky' => 'f_sticky'
+ );
+
+ foreach ($user_access as $forum_id => $access_map)
+ {
+ $forum_id = (int) $forum_id;
+
+ foreach ($access_map as $access)
+ {
+ if (isset($access['auth_mod']) && $access['auth_mod'] == 1)
+ {
+ mass_auth('user_role', $forum_id, (int) phpbb_user_id($access['user_id']), 'MOD_STANDARD');
+ mass_auth('user_role', $forum_id, (int) phpbb_user_id($access['user_id']), 'FORUM_STANDARD');
+ foreach ($mod_post_map as $old => $new)
+ {
+ if (isset($forum_access[$forum_id]) && isset($forum_access[$forum_id][$old]) && $forum_access[$forum_id][$old] == AUTH_MOD)
+ {
+ mass_auth('user', $forum_id, (int) phpbb_user_id($access['user_id']), $new, ACL_YES);
+ }
+ }
+ }
+ }
+ }
+
+ foreach ($group_access as $forum_id => $access_map)
+ {
+ $forum_id = (int) $forum_id;
+
+ foreach ($access_map as $access)
+ {
+ if (isset($access['auth_mod']) && $access['auth_mod'] == 1)
+ {
+ mass_auth('group_role', $forum_id, (int) $access['group_id'], 'MOD_STANDARD');
+ mass_auth('group_role', $forum_id, (int) $access['group_id'], 'FORUM_STANDARD');
+ foreach ($mod_post_map as $old => $new)
+ {
+ if (isset($forum_access[$forum_id]) && isset($forum_access[$forum_id][$old]) && $forum_access[$forum_id][$old] == AUTH_MOD)
+ {
+ mass_auth('group', $forum_id, (int) $access['group_id'], $new, ACL_YES);
+ }
+ }
+ }
+ }
+ }
+
+ // We grant everyone readonly access to the categories to ensure that the forums are visible
+ $sql = 'SELECT forum_id, forum_name, parent_id, left_id, right_id
+ FROM ' . FORUMS_TABLE . '
+ ORDER BY left_id ASC';
+ $result = $db->sql_query($sql);
+
+ $parent_forums = $forums = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ if ($row['parent_id'] == 0)
+ {
+ mass_auth('group_role', $row['forum_id'], 'administrators', 'FORUM_FULL');
+ mass_auth('group_role', $row['forum_id'], 'global_moderators', 'FORUM_FULL');
+ $parent_forums[] = $row;
+ }
+ else
+ {
+ $forums[] = $row;
+ }
+ }
+ $db->sql_freeresult($result);
+
+ global $auth;
+
+ // Let us see which groups have access to these forums...
+ foreach ($parent_forums as $row)
+ {
+ // Get the children
+ $branch = $forum_ids = array();
+
+ foreach ($forums as $key => $_row)
+ {
+ if ($_row['left_id'] > $row['left_id'] && $_row['left_id'] < $row['right_id'])
+ {
+ $branch[] = $_row;
+ $forum_ids[] = $_row['forum_id'];
+ continue;
+ }
+ }
+
+ if (sizeof($forum_ids))
+ {
+ // Now make sure the user is able to read these forums
+ $hold_ary = $auth->acl_group_raw_data(false, 'f_list', $forum_ids);
+
+ if (empty($hold_ary))
+ {
+ continue;
+ }
+
+ foreach ($hold_ary as $g_id => $f_id_ary)
+ {
+ $set_group = false;
+
+ foreach ($f_id_ary as $f_id => $auth_ary)
+ {
+ foreach ($auth_ary as $auth_option => $setting)
+ {
+ if ($setting == ACL_YES)
+ {
+ $set_group = true;
+ break 2;
+ }
+ }
+ }
+
+ if ($set_group)
+ {
+ mass_auth('group', $row['forum_id'], $g_id, 'f_list', ACL_YES);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+* Set primary group.
+* Really simple and only based on user_level (remaining groups will be assigned later)
+*/
+function phpbb_set_primary_group($user_level)
+{
+ global $convert_row;
+
+ if ($user_level == 1)
+ {
+ return get_group_id('administrators');
+ }
+/* else if ($user_level == 2)
+ {
+ return get_group_id('global_moderators');
+ }
+ else if ($user_level == 0 && $convert_row['user_active'])*/
+ else if ($convert_row['user_active'])
+ {
+ return get_group_id('registered');
+ }
+
+ return 0;
+}
+
+/**
+* Convert the group name, making sure to avoid conflicts with 3.0 special groups
+*/
+function phpbb_convert_group_name($group_name)
+{
+ $default_groups = array(
+ 'GUESTS',
+ 'REGISTERED',
+ 'REGISTERED_COPPA',
+ 'GLOBAL_MODERATORS',
+ 'ADMINISTRATORS',
+ 'BOTS',
+ );
+
+ if (in_array(strtoupper($group_name), $default_groups))
+ {
+ return 'phpBB2 - ' . $group_name;
+ }
+
+ return phpbb_set_default_encoding($group_name);
+}
+
+/**
+* Convert the group type constants
+*/
+function phpbb_convert_group_type($group_type)
+{
+ switch ($group_type)
+ {
+ case 0:
+ return GROUP_OPEN;
+ break;
+
+ case 1:
+ return GROUP_CLOSED;
+ break;
+
+ case 2:
+ return GROUP_HIDDEN;
+ break;
+ }
+
+ // Never return GROUP_SPECIAL here, because only phpBB3's default groups are allowed to have this type set.
+ return GROUP_HIDDEN;
+}
+
+/**
+* Convert the topic type constants
+*/
+function phpbb_convert_topic_type($topic_type)
+{
+ switch ($topic_type)
+ {
+ case 0:
+ return POST_NORMAL;
+ break;
+
+ case 1:
+ return POST_STICKY;
+ break;
+
+ case 2:
+ return POST_ANNOUNCE;
+ break;
+
+ case 3:
+ return POST_GLOBAL;
+ break;
+ }
+
+ return POST_NORMAL;
+}
+
+function phpbb_replace_size($matches)
+{
+ return '[size=' . min(200, ceil(100.0 * (((double) $matches[1])/12.0))) . ':' . $matches[2] . ']';
+}
+
+/**
+* Reparse the message stripping out the bbcode_uid values and adding new ones and setting the bitfield
+* @todo What do we want to do about HTML in messages - currently it gets converted to the entities, but there may be some objections to this
+*/
+function phpbb_prepare_message($message)
+{
+ global $phpbb_root_path, $phpEx, $db, $convert, $user, $config, $cache, $convert_row, $message_parser;
+
+ if (!$message)
+ {
+ $convert->row['mp_bbcode_bitfield'] = $convert_row['mp_bbcode_bitfield'] = 0;
+ return '';
+ }
+
+ // Decode phpBB 2.0.x Message
+ if (isset($convert->row['old_bbcode_uid']) && $convert->row['old_bbcode_uid'] != '')
+ {
+ // Adjust size...
+ if (strpos($message, '[size=') !== false)
+ {
+ $message = preg_replace_callback('/\[size=(\d*):(' . $convert->row['old_bbcode_uid'] . ')\]/', 'phpbb_replace_size', $message);
+ }
+
+ $message = preg_replace('/\:(([a-z0-9]:)?)' . $convert->row['old_bbcode_uid'] . '/s', '', $message);
+ }
+
+ if (strpos($message, '[quote=') !== false)
+ {
+ $message = preg_replace('/\[quote="(.*?)"\]/s', '[quote=&quot;\1&quot;]', $message);
+ $message = preg_replace('/\[quote=\\\"(.*?)\\\"\]/s', '[quote=&quot;\1&quot;]', $message);
+
+ // let's hope that this solves more problems than it causes. Deal with escaped quotes.
+ $message = str_replace('\"', '&quot;', $message);
+ $message = str_replace('\&quot;', '&quot;', $message);
+ }
+
+ // Already the new user id ;)
+ $user_id = $convert->row['poster_id'];
+
+ $message = str_replace('<br />', "\n", $message);
+ $message = str_replace('<', '&lt;', $message);
+ $message = str_replace('>', '&gt;', $message);
+
+ // make the post UTF-8
+ $message = phpbb_set_encoding($message);
+
+ $message_parser->warn_msg = array(); // Reset the errors from the previous message
+ $message_parser->bbcode_uid = make_uid($convert->row['post_time']);
+ $message_parser->message = $message;
+ unset($message);
+
+ // Make sure options are set.
+// $enable_html = (!isset($row['enable_html'])) ? false : $row['enable_html'];
+ $enable_bbcode = (!isset($convert->row['enable_bbcode'])) ? true : $convert->row['enable_bbcode'];
+ $enable_smilies = (!isset($convert->row['enable_smilies'])) ? true : $convert->row['enable_smilies'];
+ $enable_magic_url = (!isset($convert->row['enable_magic_url'])) ? true : $convert->row['enable_magic_url'];
+
+ // parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post')
+ $message_parser->parse($enable_bbcode, $enable_magic_url, $enable_smilies);
+
+ if (sizeof($message_parser->warn_msg))
+ {
+ $msg_id = isset($convert->row['post_id']) ? $convert->row['post_id'] : $convert->row['privmsgs_id'];
+ $convert->p_master->error('<span style="color:red">' . $user->lang['POST_ID'] . ': ' . $msg_id . ' ' . $user->lang['CONV_ERROR_MESSAGE_PARSER'] . ': <br /><br />' . implode('<br />', $message_parser->warn_msg), __LINE__, __FILE__, true);
+ }
+
+ $convert->row['mp_bbcode_bitfield'] = $convert_row['mp_bbcode_bitfield'] = $message_parser->bbcode_bitfield;
+
+ $message = $message_parser->message;
+ unset($message_parser->message);
+
+ return $message;
+}
+
+/**
+* Return the bitfield calculated by the previous function
+*/
+function get_bbcode_bitfield()
+{
+ global $convert_row;
+
+ return $convert_row['mp_bbcode_bitfield'];
+}
+
+/**
+* Determine the last user to edit a post
+* In practice we only tracked edits by the original poster in 2.0.x so this will only be set if they had edited their own post
+*/
+function phpbb_post_edit_user()
+{
+ global $convert_row, $config;
+
+ if (isset($convert_row['post_edit_count']))
+ {
+ return phpbb_user_id($convert_row['poster_id']);
+ }
+
+ return 0;
+}
+
+/**
+* Obtain the path to uploaded files on the 2.0.x forum
+* This is only used if the Attachment MOD was installed
+*/
+function phpbb_get_files_dir()
+{
+ if (!defined('MOD_ATTACHMENT'))
+ {
+ return;
+ }
+
+ global $src_db, $same_db, $convert, $user, $config, $cache;
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+ $sql = 'SELECT config_value AS upload_dir
+ FROM ' . $convert->src_table_prefix . "attachments_config
+ WHERE config_name = 'upload_dir'";
+ $result = $src_db->sql_query($sql);
+ $upload_path = $src_db->sql_fetchfield('upload_dir');
+ $src_db->sql_freeresult($result);
+
+ $sql = 'SELECT config_value AS ftp_upload
+ FROM ' . $convert->src_table_prefix . "attachments_config
+ WHERE config_name = 'allow_ftp_upload'";
+ $result = $src_db->sql_query($sql);
+ $ftp_upload = (int) $src_db->sql_fetchfield('ftp_upload');
+ $src_db->sql_freeresult($result);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ if ($ftp_upload)
+ {
+ $convert->p_master->error($user->lang['CONV_ERROR_ATTACH_FTP_DIR'], __LINE__, __FILE__);
+ }
+
+ return $upload_path;
+}
+
+/**
+* Copy thumbnails of uploaded images from the 2.0.x forum
+* This is only used if the Attachment MOD was installed
+*/
+function phpbb_copy_thumbnails()
+{
+ global $db, $convert, $user, $config, $cache, $phpbb_root_path;
+
+ $src_path = $convert->options['forum_path'] . '/' . phpbb_get_files_dir() . '/thumbs/';
+
+ if ($handle = @opendir($src_path))
+ {
+ while ($entry = readdir($handle))
+ {
+ if ($entry[0] == '.')
+ {
+ continue;
+ }
+
+ if (is_dir($src_path . $entry))
+ {
+ continue;
+ }
+ else
+ {
+ copy_file($src_path . $entry, $config['upload_path'] . '/' . preg_replace('/^t_/', 'thumb_', $entry));
+ @unlink($phpbb_root_path . $config['upload_path'] . '/thumbs/' . $entry);
+ }
+ }
+ closedir($handle);
+ }
+}
+
+/**
+* Convert the attachment category constants
+* This is only used if the Attachment MOD was installed
+*/
+function phpbb_attachment_category($cat_id)
+{
+ switch ($cat_id)
+ {
+ case 1:
+ return ATTACHMENT_CATEGORY_IMAGE;
+ break;
+
+ case 2:
+ return ATTACHMENT_CATEGORY_WM;
+ break;
+
+ case 3:
+ return ATTACHMENT_CATEGORY_FLASH;
+ break;
+ }
+
+ return ATTACHMENT_CATEGORY_NONE;
+}
+
+/**
+* Convert the attachment extension names
+* This is only used if the Attachment MOD was installed
+*/
+function phpbb_attachment_extension_group_name()
+{
+ global $db, $phpbb_root_path, $phpEx;
+
+ // Update file extension group names to use language strings.
+ $sql = 'SELECT lang_dir
+ FROM ' . LANG_TABLE;
+ $result = $db->sql_query($sql);
+
+ $extension_groups_updated = array();
+ while ($lang_dir = $db->sql_fetchfield('lang_dir'))
+ {
+ $lang_dir = basename($lang_dir);
+ $lang_file = $phpbb_root_path . 'language/' . $lang_dir . '/acp/attachments.' . $phpEx;
+
+ if (!file_exists($lang_file))
+ {
+ continue;
+ }
+
+ $lang = array();
+ include($lang_file);
+
+ foreach ($lang as $lang_key => $lang_val)
+ {
+ if (isset($extension_groups_updated[$lang_key]) || strpos($lang_key, 'EXT_GROUP_') !== 0)
+ {
+ continue;
+ }
+
+ $sql_ary = array(
+ 'group_name' => substr($lang_key, 10), // Strip off 'EXT_GROUP_'
+ );
+
+ $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
+ WHERE group_name = '" . $db->sql_escape($lang_val) . "'";
+ $db->sql_query($sql);
+
+ $extension_groups_updated[$lang_key] = true;
+ }
+ }
+ $db->sql_freeresult($result);
+}
+
+/**
+* Obtain list of forums in which different attachment categories can be used
+*/
+function phpbb_attachment_forum_perms($forum_permissions)
+{
+ if (empty($forum_permissions))
+ {
+ return '';
+ }
+
+ // Decode forum permissions
+ $forum_ids = array();
+
+ $one_char_encoding = '#';
+ $two_char_encoding = '.';
+
+ $auth_len = 1;
+ for ($pos = 0; $pos < strlen($forum_permissions); $pos += $auth_len)
+ {
+ $forum_auth = substr($forum_permissions, $pos, 1);
+ if ($forum_auth == $one_char_encoding)
+ {
+ $auth_len = 1;
+ continue;
+ }
+ else if ($forum_auth == $two_char_encoding)
+ {
+ $auth_len = 2;
+ $pos--;
+ continue;
+ }
+
+ $forum_auth = substr($forum_permissions, $pos, $auth_len);
+ $forum_id = base64_unpack($forum_auth);
+
+ $forum_ids[] = (int) $forum_id;
+ }
+
+ if (sizeof($forum_ids))
+ {
+ return attachment_forum_perms($forum_ids);
+ }
+
+ return '';
+}
+
+/**
+* Convert the avatar type constants
+*/
+function phpbb_avatar_type($type)
+{
+ switch ($type)
+ {
+ case 1:
+ return AVATAR_UPLOAD;
+ break;
+
+ case 2:
+ return AVATAR_REMOTE;
+ break;
+
+ case 3:
+ return AVATAR_GALLERY;
+ break;
+ }
+
+ return 0;
+}
+
+
+/**
+* Just undos the replacing of '<' and '>'
+*/
+function phpbb_smilie_html_decode($code)
+{
+ $code = str_replace('&lt;', '<', $code);
+ return str_replace('&gt;', '>', $code);
+}
+
+/**
+* Transfer avatars, copying the image if it was uploaded
+*/
+function phpbb_import_avatar($user_avatar)
+{
+ global $convert_row;
+
+ if (!$convert_row['user_avatar_type'])
+ {
+ return '';
+ }
+ else if ($convert_row['user_avatar_type'] == 1)
+ {
+ // Uploaded avatar
+ return import_avatar($user_avatar, false, $convert_row['user_id']);
+ }
+ else if ($convert_row['user_avatar_type'] == 2)
+ {
+ // Remote avatar
+ return $user_avatar;
+ }
+ else if ($convert_row['user_avatar_type'] == 3)
+ {
+ // Gallery avatar
+ return $user_avatar;
+ }
+
+ return '';
+}
+
+
+/**
+* Find out about the avatar's dimensions
+*/
+function phpbb_get_avatar_height($user_avatar)
+{
+ global $convert_row;
+
+ if (empty($convert_row['user_avatar_type']))
+ {
+ return 0;
+ }
+ return get_avatar_height($user_avatar, 'phpbb_avatar_type', $convert_row['user_avatar_type']);
+}
+
+
+/**
+* Find out about the avatar's dimensions
+*/
+function phpbb_get_avatar_width($user_avatar)
+{
+ global $convert_row;
+
+ if (empty($convert_row['user_avatar_type']))
+ {
+ return 0;
+ }
+
+ return get_avatar_width($user_avatar, 'phpbb_avatar_type', $convert_row['user_avatar_type']);
+}
+
+
+/**
+* Calculate the correct to_address field for private messages
+*/
+function phpbb_privmsgs_to_userid($to_userid)
+{
+ global $config;
+
+ return 'u_' . phpbb_user_id($to_userid);
+}
+
+/**
+* Calculate whether a private message was unread using the bitfield
+*/
+function phpbb_unread_pm($pm_type)
+{
+ return ($pm_type == 5) ? 1 : 0;
+}
+
+/**
+* Calculate whether a private message was new using the bitfield
+*/
+function phpbb_new_pm($pm_type)
+{
+ return ($pm_type == 1) ? 1 : 0;
+}
+
+/**
+* Obtain the folder_id for the custom folder created to replace the savebox from 2.0.x (used to store saved private messages)
+*/
+function phpbb_get_savebox_id($user_id)
+{
+ global $db;
+
+ $user_id = phpbb_user_id($user_id);
+
+ // Only one custom folder, check only one
+ $sql = 'SELECT folder_id
+ FROM ' . PRIVMSGS_FOLDER_TABLE . '
+ WHERE user_id = ' . $user_id;
+ $result = $db->sql_query_limit($sql, 1);
+ $folder_id = (int) $db->sql_fetchfield('folder_id');
+ $db->sql_freeresult($result);
+
+ return $folder_id;
+}
+
+/**
+* Transfer attachment specific configuration options
+* These were not stored in the main config table on 2.0.x
+* This is only used if the Attachment MOD was installed
+*/
+function phpbb_import_attach_config()
+{
+ global $db, $src_db, $same_db, $convert, $config;
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $sql = 'SELECT *
+ FROM ' . $convert->src_table_prefix . 'attachments_config';
+ $result = $src_db->sql_query($sql);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ $attach_config = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $attach_config[$row['config_name']] = $row['config_value'];
+ }
+ $src_db->sql_freeresult($result);
+
+ $config->set('allow_attachments', 1);
+
+ // old attachment mod? Must be very old if this entry do not exist...
+ if (!empty($attach_config['display_order']))
+ {
+ $config->set('display_order', $attach_config['display_order']);
+ }
+ $config->set('max_filesize', $attach_config['max_filesize']);
+ $config->set('max_filesize_pm', $attach_config['max_filesize_pm']);
+ $config->set('attachment_quota', $attach_config['attachment_quota']);
+ $config->set('max_attachments', $attach_config['max_attachments']);
+ $config->set('max_attachments_pm', $attach_config['max_attachments_pm']);
+ $config->set('allow_pm_attach', $attach_config['allow_pm_attach']);
+
+ $config->set('img_display_inlined', $attach_config['img_display_inlined']);
+ $config->set('img_max_width', $attach_config['img_max_width']);
+ $config->set('img_max_height', $attach_config['img_max_height']);
+ $config->set('img_link_width', $attach_config['img_link_width']);
+ $config->set('img_link_height', $attach_config['img_link_height']);
+ $config->set('img_create_thumbnail', $attach_config['img_create_thumbnail']);
+ $config->set('img_max_thumb_width', 400);
+ $config->set('img_min_thumb_filesize', $attach_config['img_min_thumb_filesize']);
+ $config->set('img_imagick', $attach_config['img_imagick']);
+}
+
+/**
+* Calculate the date a user became inactive
+*/
+function phpbb_inactive_time()
+{
+ global $convert_row;
+
+ if ($convert_row['user_active'])
+ {
+ return 0;
+ }
+
+ if ($convert_row['user_lastvisit'])
+ {
+ return $convert_row['user_lastvisit'];
+ }
+
+ return $convert_row['user_regdate'];
+}
+
+/**
+* Calculate the reason a user became inactive
+* We can't actually tell the difference between a manual deactivation and one for profile changes
+* from the data available to assume the latter
+*/
+function phpbb_inactive_reason()
+{
+ global $convert_row;
+
+ if ($convert_row['user_active'])
+ {
+ return 0;
+ }
+
+ if ($convert_row['user_lastvisit'])
+ {
+ return INACTIVE_PROFILE;
+ }
+
+ return INACTIVE_REGISTER;
+}
+
+/**
+* Adjust 2.0.x disallowed names to 3.0.x format
+*/
+function phpbb_disallowed_username($username)
+{
+ // Replace * with %
+ $username = phpbb_set_default_encoding(str_replace('*', '%', $username));
+ return utf8_htmlspecialchars($username);
+}
+
+/**
+* Checks whether there are any usernames on the old board that would map to the same
+* username_clean on phpBB3. Prints out a list if any exist and exits.
+*/
+function phpbb_create_userconv_table()
+{
+ global $db, $src_db, $convert, $table_prefix, $user, $lang;
+
+ $map_dbms = '';
+ switch ($db->get_sql_layer())
+ {
+ case 'mysql':
+ $map_dbms = 'mysql_40';
+ break;
+
+ case 'mysql4':
+ if (version_compare($db->sql_server_info(true), '4.1.3', '>='))
+ {
+ $map_dbms = 'mysql_41';
+ }
+ else
+ {
+ $map_dbms = 'mysql_40';
+ }
+ break;
+
+ case 'mysqli':
+ $map_dbms = 'mysql_41';
+ break;
+
+ case 'mssql':
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $map_dbms = 'mssql';
+ break;
+
+ default:
+ $map_dbms = $db->get_sql_layer();
+ break;
+ }
+
+ // create a temporary table in which we store the clean usernames
+ $drop_sql = 'DROP TABLE ' . USERCONV_TABLE;
+ switch ($map_dbms)
+ {
+ case 'mssql':
+ $create_sql = 'CREATE TABLE [' . USERCONV_TABLE . '] (
+ [user_id] [int] NOT NULL ,
+ [username_clean] [varchar] (255) DEFAULT (\'\') NOT NULL
+ )';
+ break;
+
+ case 'mysql_40':
+ $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
+ user_id mediumint(8) NOT NULL,
+ username_clean blob NOT NULL
+ )';
+ break;
+
+ case 'mysql_41':
+ $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
+ user_id mediumint(8) NOT NULL,
+ username_clean varchar(255) DEFAULT \'\' NOT NULL
+ ) CHARACTER SET `utf8` COLLATE `utf8_bin`';
+ break;
+
+ case 'oracle':
+ $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
+ user_id number(8) NOT NULL,
+ username_clean varchar2(255) DEFAULT \'\'
+ )';
+ break;
+
+ case 'postgres':
+ $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
+ user_id INT4 DEFAULT \'0\',
+ username_clean varchar_ci DEFAULT \'\' NOT NULL
+ )';
+ break;
+
+ case 'sqlite':
+ case 'sqlite3':
+ $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
+ user_id INTEGER NOT NULL DEFAULT \'0\',
+ username_clean varchar(255) NOT NULL DEFAULT \'\'
+ )';
+ break;
+ }
+
+ $db->sql_return_on_error(true);
+ $db->sql_query($drop_sql);
+ $db->sql_return_on_error(false);
+ $db->sql_query($create_sql);
+}
+
+function phpbb_check_username_collisions()
+{
+ global $db, $src_db, $convert, $table_prefix, $user, $lang;
+
+ // now find the clean version of the usernames that collide
+ $sql = 'SELECT username_clean
+ FROM ' . USERCONV_TABLE .'
+ GROUP BY username_clean
+ HAVING COUNT(user_id) > 1';
+ $result = $db->sql_query($sql);
+
+ $colliding_names = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $colliding_names[] = $row['username_clean'];
+ }
+ $db->sql_freeresult($result);
+
+ // there was at least one collision, the admin will have to solve it before conversion can continue
+ if (sizeof($colliding_names))
+ {
+ $sql = 'SELECT user_id, username_clean
+ FROM ' . USERCONV_TABLE . '
+ WHERE ' . $db->sql_in_set('username_clean', $colliding_names);
+ $result = $db->sql_query($sql);
+ unset($colliding_names);
+
+ $colliding_user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $colliding_user_ids[(int) $row['user_id']] = $row['username_clean'];
+ }
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT username, user_id, user_posts
+ FROM ' . $convert->src_table_prefix . 'users
+ WHERE ' . $src_db->sql_in_set('user_id', array_keys($colliding_user_ids));
+ $result = $src_db->sql_query($sql);
+
+ $colliding_users = array();
+ while ($row = $src_db->sql_fetchrow($result))
+ {
+ $row['user_id'] = (int) $row['user_id'];
+ if (isset($colliding_user_ids[$row['user_id']]))
+ {
+ $colliding_users[$colliding_user_ids[$row['user_id']]][] = $row;
+ }
+ }
+ $src_db->sql_freeresult($result);
+ unset($colliding_user_ids);
+
+ $list = '';
+ foreach ($colliding_users as $username_clean => $users)
+ {
+ $list .= sprintf($user->lang['COLLIDING_CLEAN_USERNAME'], $username_clean) . "<br />\n";
+ foreach ($users as $i => $row)
+ {
+ $list .= sprintf($user->lang['COLLIDING_USER'], $row['user_id'], phpbb_set_default_encoding($row['username']), $row['user_posts']) . "<br />\n";
+ }
+ }
+
+ $lang['INST_ERR_FATAL'] = $user->lang['CONV_ERR_FATAL'];
+ $convert->p_master->error('<span style="color:red">' . $user->lang['COLLIDING_USERNAMES_FOUND'] . '</span></b><br /><br />' . $list . '<b>', __LINE__, __FILE__);
+ }
+
+ $drop_sql = 'DROP TABLE ' . USERCONV_TABLE;
+ $db->sql_query($drop_sql);
+}
+
+function phpbb_convert_timezone($timezone)
+{
+ global $config, $db, $phpbb_root_path, $phpEx, $table_prefix;
+
+ $factory = new \phpbb\db\tools\factory();
+ $timezone_migration = new \phpbb\db\migration\data\v310\timezone($config, $db, $factory->get($db), $phpbb_root_path, $phpEx, $table_prefix);
+ return $timezone_migration->convert_phpbb30_timezone($timezone, 0);
+}
+
+function phpbb_add_notification_options($user_notify_pm)
+{
+ global $convert_row, $db;
+
+ $user_id = phpbb_user_id($convert_row['user_id']);
+ if ($user_id == ANONYMOUS)
+ {
+ return;
+ }
+
+ $rows = array();
+
+ $rows[] = array(
+ 'item_type' => 'post',
+ 'item_id' => 0,
+ 'user_id' => (int) $user_id,
+ 'notify' => 1,
+ 'method' => 'email',
+ );
+ $rows[] = array(
+ 'item_type' => 'topic',
+ 'item_id' => 0,
+ 'user_id' => (int) $user_id,
+ 'notify' => 1,
+ 'method' => 'email',
+ );
+ if ($user_notify_pm)
+ {
+ $rows[] = array(
+ 'item_type' => 'pm',
+ 'item_id' => 0,
+ 'user_id' => (int) $user_id,
+ 'notify' => 1,
+ 'method' => 'email',
+ );
+ }
+
+ $sql = $db->sql_multi_insert(USER_NOTIFICATIONS_TABLE, $rows);
+}
+
+function phpbb_convert_password_hash($hash)
+{
+ global $phpbb_container;
+
+ /* @var $manager \phpbb\passwords\manager */
+ $manager = $phpbb_container->get('passwords.manager');
+ $hash = $manager->hash($hash, '$H$');
+
+ return '$CP$' . $hash;
+}
diff --git a/phpBB/install_old/data/confusables.php b/phpBB/install_old/data/confusables.php
new file mode 100644
index 0000000000..992207c1ef
--- /dev/null
+++ b/phpBB/install_old/data/confusables.php
@@ -0,0 +1,645 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+function utf8_new_case_fold($text, $option = 'full')
+{
+ static $uniarray = array();
+ global $phpbb_root_path, $phpEx;
+
+ // common is always set
+ if (!isset($uniarray['c']))
+ {
+ $uniarray['c'] = include($phpbb_root_path . 'includes/utf/data/case_fold_c.' . $phpEx);
+ }
+
+ // only set full if we need to
+ if ($option === 'full' && !isset($uniarray['f']))
+ {
+ $uniarray['f'] = include($phpbb_root_path . 'includes/utf/data/case_fold_f.' . $phpEx);
+ }
+
+ // only set simple if we need to
+ if ($option !== 'full' && !isset($uniarray['s']))
+ {
+ $uniarray['s'] = include($phpbb_root_path . 'includes/utf/data/case_fold_s.' . $phpEx);
+ }
+
+ // common is always replaced
+ $text = strtr($text, $uniarray['c']);
+
+ if ($option === 'full')
+ {
+ // full replaces a character with multiple characters
+ $text = strtr($text, $uniarray['f']);
+ }
+ else
+ {
+ // simple replaces a character with another character
+ $text = strtr($text, $uniarray['s']);
+ }
+
+ return $text;
+}
+
+function utf8_new_case_fold_nfkc($text, $option = 'full')
+{
+ static $fc_nfkc_closure = array(
+ "\xCD\xBA" => "\x20\xCE\xB9",
+ "\xCF\x92" => "\xCF\x85",
+ "\xCF\x93" => "\xCF\x8D",
+ "\xCF\x94" => "\xCF\x8B",
+ "\xCF\xB2" => "\xCF\x83",
+ "\xCF\xB9" => "\xCF\x83",
+ "\xE1\xB4\xAC" => "\x61",
+ "\xE1\xB4\xAD" => "\xC3\xA6",
+ "\xE1\xB4\xAE" => "\x62",
+ "\xE1\xB4\xB0" => "\x64",
+ "\xE1\xB4\xB1" => "\x65",
+ "\xE1\xB4\xB2" => "\xC7\x9D",
+ "\xE1\xB4\xB3" => "\x67",
+ "\xE1\xB4\xB4" => "\x68",
+ "\xE1\xB4\xB5" => "\x69",
+ "\xE1\xB4\xB6" => "\x6A",
+ "\xE1\xB4\xB7" => "\x6B",
+ "\xE1\xB4\xB8" => "\x6C",
+ "\xE1\xB4\xB9" => "\x6D",
+ "\xE1\xB4\xBA" => "\x6E",
+ "\xE1\xB4\xBC" => "\x6F",
+ "\xE1\xB4\xBD" => "\xC8\xA3",
+ "\xE1\xB4\xBE" => "\x70",
+ "\xE1\xB4\xBF" => "\x72",
+ "\xE1\xB5\x80" => "\x74",
+ "\xE1\xB5\x81" => "\x75",
+ "\xE1\xB5\x82" => "\x77",
+ "\xE2\x82\xA8" => "\x72\x73",
+ "\xE2\x84\x82" => "\x63",
+ "\xE2\x84\x83" => "\xC2\xB0\x63",
+ "\xE2\x84\x87" => "\xC9\x9B",
+ "\xE2\x84\x89" => "\xC2\xB0\x66",
+ "\xE2\x84\x8B" => "\x68",
+ "\xE2\x84\x8C" => "\x68",
+ "\xE2\x84\x8D" => "\x68",
+ "\xE2\x84\x90" => "\x69",
+ "\xE2\x84\x91" => "\x69",
+ "\xE2\x84\x92" => "\x6C",
+ "\xE2\x84\x95" => "\x6E",
+ "\xE2\x84\x96" => "\x6E\x6F",
+ "\xE2\x84\x99" => "\x70",
+ "\xE2\x84\x9A" => "\x71",
+ "\xE2\x84\x9B" => "\x72",
+ "\xE2\x84\x9C" => "\x72",
+ "\xE2\x84\x9D" => "\x72",
+ "\xE2\x84\xA0" => "\x73\x6D",
+ "\xE2\x84\xA1" => "\x74\x65\x6C",
+ "\xE2\x84\xA2" => "\x74\x6D",
+ "\xE2\x84\xA4" => "\x7A",
+ "\xE2\x84\xA8" => "\x7A",
+ "\xE2\x84\xAC" => "\x62",
+ "\xE2\x84\xAD" => "\x63",
+ "\xE2\x84\xB0" => "\x65",
+ "\xE2\x84\xB1" => "\x66",
+ "\xE2\x84\xB3" => "\x6D",
+ "\xE2\x84\xBB" => "\x66\x61\x78",
+ "\xE2\x84\xBE" => "\xCE\xB3",
+ "\xE2\x84\xBF" => "\xCF\x80",
+ "\xE2\x85\x85" => "\x64",
+ "\xE3\x89\x90" => "\x70\x74\x65",
+ "\xE3\x8B\x8C" => "\x68\x67",
+ "\xE3\x8B\x8E" => "\x65\x76",
+ "\xE3\x8B\x8F" => "\x6C\x74\x64",
+ "\xE3\x8D\xB1" => "\x68\x70\x61",
+ "\xE3\x8D\xB3" => "\x61\x75",
+ "\xE3\x8D\xB5" => "\x6F\x76",
+ "\xE3\x8D\xBA" => "\x69\x75",
+ "\xE3\x8E\x80" => "\x70\x61",
+ "\xE3\x8E\x81" => "\x6E\x61",
+ "\xE3\x8E\x82" => "\xCE\xBC\x61",
+ "\xE3\x8E\x83" => "\x6D\x61",
+ "\xE3\x8E\x84" => "\x6B\x61",
+ "\xE3\x8E\x85" => "\x6B\x62",
+ "\xE3\x8E\x86" => "\x6D\x62",
+ "\xE3\x8E\x87" => "\x67\x62",
+ "\xE3\x8E\x8A" => "\x70\x66",
+ "\xE3\x8E\x8B" => "\x6E\x66",
+ "\xE3\x8E\x8C" => "\xCE\xBC\x66",
+ "\xE3\x8E\x90" => "\x68\x7A",
+ "\xE3\x8E\x91" => "\x6B\x68\x7A",
+ "\xE3\x8E\x92" => "\x6D\x68\x7A",
+ "\xE3\x8E\x93" => "\x67\x68\x7A",
+ "\xE3\x8E\x94" => "\x74\x68\x7A",
+ "\xE3\x8E\xA9" => "\x70\x61",
+ "\xE3\x8E\xAA" => "\x6B\x70\x61",
+ "\xE3\x8E\xAB" => "\x6D\x70\x61",
+ "\xE3\x8E\xAC" => "\x67\x70\x61",
+ "\xE3\x8E\xB4" => "\x70\x76",
+ "\xE3\x8E\xB5" => "\x6E\x76",
+ "\xE3\x8E\xB6" => "\xCE\xBC\x76",
+ "\xE3\x8E\xB7" => "\x6D\x76",
+ "\xE3\x8E\xB8" => "\x6B\x76",
+ "\xE3\x8E\xB9" => "\x6D\x76",
+ "\xE3\x8E\xBA" => "\x70\x77",
+ "\xE3\x8E\xBB" => "\x6E\x77",
+ "\xE3\x8E\xBC" => "\xCE\xBC\x77",
+ "\xE3\x8E\xBD" => "\x6D\x77",
+ "\xE3\x8E\xBE" => "\x6B\x77",
+ "\xE3\x8E\xBF" => "\x6D\x77",
+ "\xE3\x8F\x80" => "\x6B\xCF\x89",
+ "\xE3\x8F\x81" => "\x6D\xCF\x89",
+ "\xE3\x8F\x83" => "\x62\x71",
+ "\xE3\x8F\x86" => "\x63\xE2\x88\x95\x6B\x67",
+ "\xE3\x8F\x87" => "\x63\x6F\x2E",
+ "\xE3\x8F\x88" => "\x64\x62",
+ "\xE3\x8F\x89" => "\x67\x79",
+ "\xE3\x8F\x8B" => "\x68\x70",
+ "\xE3\x8F\x8D" => "\x6B\x6B",
+ "\xE3\x8F\x8E" => "\x6B\x6D",
+ "\xE3\x8F\x97" => "\x70\x68",
+ "\xE3\x8F\x99" => "\x70\x70\x6D",
+ "\xE3\x8F\x9A" => "\x70\x72",
+ "\xE3\x8F\x9C" => "\x73\x76",
+ "\xE3\x8F\x9D" => "\x77\x62",
+ "\xE3\x8F\x9E" => "\x76\xE2\x88\x95\x6D",
+ "\xE3\x8F\x9F" => "\x61\xE2\x88\x95\x6D",
+ "\xF0\x9D\x90\x80" => "\x61",
+ "\xF0\x9D\x90\x81" => "\x62",
+ "\xF0\x9D\x90\x82" => "\x63",
+ "\xF0\x9D\x90\x83" => "\x64",
+ "\xF0\x9D\x90\x84" => "\x65",
+ "\xF0\x9D\x90\x85" => "\x66",
+ "\xF0\x9D\x90\x86" => "\x67",
+ "\xF0\x9D\x90\x87" => "\x68",
+ "\xF0\x9D\x90\x88" => "\x69",
+ "\xF0\x9D\x90\x89" => "\x6A",
+ "\xF0\x9D\x90\x8A" => "\x6B",
+ "\xF0\x9D\x90\x8B" => "\x6C",
+ "\xF0\x9D\x90\x8C" => "\x6D",
+ "\xF0\x9D\x90\x8D" => "\x6E",
+ "\xF0\x9D\x90\x8E" => "\x6F",
+ "\xF0\x9D\x90\x8F" => "\x70",
+ "\xF0\x9D\x90\x90" => "\x71",
+ "\xF0\x9D\x90\x91" => "\x72",
+ "\xF0\x9D\x90\x92" => "\x73",
+ "\xF0\x9D\x90\x93" => "\x74",
+ "\xF0\x9D\x90\x94" => "\x75",
+ "\xF0\x9D\x90\x95" => "\x76",
+ "\xF0\x9D\x90\x96" => "\x77",
+ "\xF0\x9D\x90\x97" => "\x78",
+ "\xF0\x9D\x90\x98" => "\x79",
+ "\xF0\x9D\x90\x99" => "\x7A",
+ "\xF0\x9D\x90\xB4" => "\x61",
+ "\xF0\x9D\x90\xB5" => "\x62",
+ "\xF0\x9D\x90\xB6" => "\x63",
+ "\xF0\x9D\x90\xB7" => "\x64",
+ "\xF0\x9D\x90\xB8" => "\x65",
+ "\xF0\x9D\x90\xB9" => "\x66",
+ "\xF0\x9D\x90\xBA" => "\x67",
+ "\xF0\x9D\x90\xBB" => "\x68",
+ "\xF0\x9D\x90\xBC" => "\x69",
+ "\xF0\x9D\x90\xBD" => "\x6A",
+ "\xF0\x9D\x90\xBE" => "\x6B",
+ "\xF0\x9D\x90\xBF" => "\x6C",
+ "\xF0\x9D\x91\x80" => "\x6D",
+ "\xF0\x9D\x91\x81" => "\x6E",
+ "\xF0\x9D\x91\x82" => "\x6F",
+ "\xF0\x9D\x91\x83" => "\x70",
+ "\xF0\x9D\x91\x84" => "\x71",
+ "\xF0\x9D\x91\x85" => "\x72",
+ "\xF0\x9D\x91\x86" => "\x73",
+ "\xF0\x9D\x91\x87" => "\x74",
+ "\xF0\x9D\x91\x88" => "\x75",
+ "\xF0\x9D\x91\x89" => "\x76",
+ "\xF0\x9D\x91\x8A" => "\x77",
+ "\xF0\x9D\x91\x8B" => "\x78",
+ "\xF0\x9D\x91\x8C" => "\x79",
+ "\xF0\x9D\x91\x8D" => "\x7A",
+ "\xF0\x9D\x91\xA8" => "\x61",
+ "\xF0\x9D\x91\xA9" => "\x62",
+ "\xF0\x9D\x91\xAA" => "\x63",
+ "\xF0\x9D\x91\xAB" => "\x64",
+ "\xF0\x9D\x91\xAC" => "\x65",
+ "\xF0\x9D\x91\xAD" => "\x66",
+ "\xF0\x9D\x91\xAE" => "\x67",
+ "\xF0\x9D\x91\xAF" => "\x68",
+ "\xF0\x9D\x91\xB0" => "\x69",
+ "\xF0\x9D\x91\xB1" => "\x6A",
+ "\xF0\x9D\x91\xB2" => "\x6B",
+ "\xF0\x9D\x91\xB3" => "\x6C",
+ "\xF0\x9D\x91\xB4" => "\x6D",
+ "\xF0\x9D\x91\xB5" => "\x6E",
+ "\xF0\x9D\x91\xB6" => "\x6F",
+ "\xF0\x9D\x91\xB7" => "\x70",
+ "\xF0\x9D\x91\xB8" => "\x71",
+ "\xF0\x9D\x91\xB9" => "\x72",
+ "\xF0\x9D\x91\xBA" => "\x73",
+ "\xF0\x9D\x91\xBB" => "\x74",
+ "\xF0\x9D\x91\xBC" => "\x75",
+ "\xF0\x9D\x91\xBD" => "\x76",
+ "\xF0\x9D\x91\xBE" => "\x77",
+ "\xF0\x9D\x91\xBF" => "\x78",
+ "\xF0\x9D\x92\x80" => "\x79",
+ "\xF0\x9D\x92\x81" => "\x7A",
+ "\xF0\x9D\x92\x9C" => "\x61",
+ "\xF0\x9D\x92\x9E" => "\x63",
+ "\xF0\x9D\x92\x9F" => "\x64",
+ "\xF0\x9D\x92\xA2" => "\x67",
+ "\xF0\x9D\x92\xA5" => "\x6A",
+ "\xF0\x9D\x92\xA6" => "\x6B",
+ "\xF0\x9D\x92\xA9" => "\x6E",
+ "\xF0\x9D\x92\xAA" => "\x6F",
+ "\xF0\x9D\x92\xAB" => "\x70",
+ "\xF0\x9D\x92\xAC" => "\x71",
+ "\xF0\x9D\x92\xAE" => "\x73",
+ "\xF0\x9D\x92\xAF" => "\x74",
+ "\xF0\x9D\x92\xB0" => "\x75",
+ "\xF0\x9D\x92\xB1" => "\x76",
+ "\xF0\x9D\x92\xB2" => "\x77",
+ "\xF0\x9D\x92\xB3" => "\x78",
+ "\xF0\x9D\x92\xB4" => "\x79",
+ "\xF0\x9D\x92\xB5" => "\x7A",
+ "\xF0\x9D\x93\x90" => "\x61",
+ "\xF0\x9D\x93\x91" => "\x62",
+ "\xF0\x9D\x93\x92" => "\x63",
+ "\xF0\x9D\x93\x93" => "\x64",
+ "\xF0\x9D\x93\x94" => "\x65",
+ "\xF0\x9D\x93\x95" => "\x66",
+ "\xF0\x9D\x93\x96" => "\x67",
+ "\xF0\x9D\x93\x97" => "\x68",
+ "\xF0\x9D\x93\x98" => "\x69",
+ "\xF0\x9D\x93\x99" => "\x6A",
+ "\xF0\x9D\x93\x9A" => "\x6B",
+ "\xF0\x9D\x93\x9B" => "\x6C",
+ "\xF0\x9D\x93\x9C" => "\x6D",
+ "\xF0\x9D\x93\x9D" => "\x6E",
+ "\xF0\x9D\x93\x9E" => "\x6F",
+ "\xF0\x9D\x93\x9F" => "\x70",
+ "\xF0\x9D\x93\xA0" => "\x71",
+ "\xF0\x9D\x93\xA1" => "\x72",
+ "\xF0\x9D\x93\xA2" => "\x73",
+ "\xF0\x9D\x93\xA3" => "\x74",
+ "\xF0\x9D\x93\xA4" => "\x75",
+ "\xF0\x9D\x93\xA5" => "\x76",
+ "\xF0\x9D\x93\xA6" => "\x77",
+ "\xF0\x9D\x93\xA7" => "\x78",
+ "\xF0\x9D\x93\xA8" => "\x79",
+ "\xF0\x9D\x93\xA9" => "\x7A",
+ "\xF0\x9D\x94\x84" => "\x61",
+ "\xF0\x9D\x94\x85" => "\x62",
+ "\xF0\x9D\x94\x87" => "\x64",
+ "\xF0\x9D\x94\x88" => "\x65",
+ "\xF0\x9D\x94\x89" => "\x66",
+ "\xF0\x9D\x94\x8A" => "\x67",
+ "\xF0\x9D\x94\x8D" => "\x6A",
+ "\xF0\x9D\x94\x8E" => "\x6B",
+ "\xF0\x9D\x94\x8F" => "\x6C",
+ "\xF0\x9D\x94\x90" => "\x6D",
+ "\xF0\x9D\x94\x91" => "\x6E",
+ "\xF0\x9D\x94\x92" => "\x6F",
+ "\xF0\x9D\x94\x93" => "\x70",
+ "\xF0\x9D\x94\x94" => "\x71",
+ "\xF0\x9D\x94\x96" => "\x73",
+ "\xF0\x9D\x94\x97" => "\x74",
+ "\xF0\x9D\x94\x98" => "\x75",
+ "\xF0\x9D\x94\x99" => "\x76",
+ "\xF0\x9D\x94\x9A" => "\x77",
+ "\xF0\x9D\x94\x9B" => "\x78",
+ "\xF0\x9D\x94\x9C" => "\x79",
+ "\xF0\x9D\x94\xB8" => "\x61",
+ "\xF0\x9D\x94\xB9" => "\x62",
+ "\xF0\x9D\x94\xBB" => "\x64",
+ "\xF0\x9D\x94\xBC" => "\x65",
+ "\xF0\x9D\x94\xBD" => "\x66",
+ "\xF0\x9D\x94\xBE" => "\x67",
+ "\xF0\x9D\x95\x80" => "\x69",
+ "\xF0\x9D\x95\x81" => "\x6A",
+ "\xF0\x9D\x95\x82" => "\x6B",
+ "\xF0\x9D\x95\x83" => "\x6C",
+ "\xF0\x9D\x95\x84" => "\x6D",
+ "\xF0\x9D\x95\x86" => "\x6F",
+ "\xF0\x9D\x95\x8A" => "\x73",
+ "\xF0\x9D\x95\x8B" => "\x74",
+ "\xF0\x9D\x95\x8C" => "\x75",
+ "\xF0\x9D\x95\x8D" => "\x76",
+ "\xF0\x9D\x95\x8E" => "\x77",
+ "\xF0\x9D\x95\x8F" => "\x78",
+ "\xF0\x9D\x95\x90" => "\x79",
+ "\xF0\x9D\x95\xAC" => "\x61",
+ "\xF0\x9D\x95\xAD" => "\x62",
+ "\xF0\x9D\x95\xAE" => "\x63",
+ "\xF0\x9D\x95\xAF" => "\x64",
+ "\xF0\x9D\x95\xB0" => "\x65",
+ "\xF0\x9D\x95\xB1" => "\x66",
+ "\xF0\x9D\x95\xB2" => "\x67",
+ "\xF0\x9D\x95\xB3" => "\x68",
+ "\xF0\x9D\x95\xB4" => "\x69",
+ "\xF0\x9D\x95\xB5" => "\x6A",
+ "\xF0\x9D\x95\xB6" => "\x6B",
+ "\xF0\x9D\x95\xB7" => "\x6C",
+ "\xF0\x9D\x95\xB8" => "\x6D",
+ "\xF0\x9D\x95\xB9" => "\x6E",
+ "\xF0\x9D\x95\xBA" => "\x6F",
+ "\xF0\x9D\x95\xBB" => "\x70",
+ "\xF0\x9D\x95\xBC" => "\x71",
+ "\xF0\x9D\x95\xBD" => "\x72",
+ "\xF0\x9D\x95\xBE" => "\x73",
+ "\xF0\x9D\x95\xBF" => "\x74",
+ "\xF0\x9D\x96\x80" => "\x75",
+ "\xF0\x9D\x96\x81" => "\x76",
+ "\xF0\x9D\x96\x82" => "\x77",
+ "\xF0\x9D\x96\x83" => "\x78",
+ "\xF0\x9D\x96\x84" => "\x79",
+ "\xF0\x9D\x96\x85" => "\x7A",
+ "\xF0\x9D\x96\xA0" => "\x61",
+ "\xF0\x9D\x96\xA1" => "\x62",
+ "\xF0\x9D\x96\xA2" => "\x63",
+ "\xF0\x9D\x96\xA3" => "\x64",
+ "\xF0\x9D\x96\xA4" => "\x65",
+ "\xF0\x9D\x96\xA5" => "\x66",
+ "\xF0\x9D\x96\xA6" => "\x67",
+ "\xF0\x9D\x96\xA7" => "\x68",
+ "\xF0\x9D\x96\xA8" => "\x69",
+ "\xF0\x9D\x96\xA9" => "\x6A",
+ "\xF0\x9D\x96\xAA" => "\x6B",
+ "\xF0\x9D\x96\xAB" => "\x6C",
+ "\xF0\x9D\x96\xAC" => "\x6D",
+ "\xF0\x9D\x96\xAD" => "\x6E",
+ "\xF0\x9D\x96\xAE" => "\x6F",
+ "\xF0\x9D\x96\xAF" => "\x70",
+ "\xF0\x9D\x96\xB0" => "\x71",
+ "\xF0\x9D\x96\xB1" => "\x72",
+ "\xF0\x9D\x96\xB2" => "\x73",
+ "\xF0\x9D\x96\xB3" => "\x74",
+ "\xF0\x9D\x96\xB4" => "\x75",
+ "\xF0\x9D\x96\xB5" => "\x76",
+ "\xF0\x9D\x96\xB6" => "\x77",
+ "\xF0\x9D\x96\xB7" => "\x78",
+ "\xF0\x9D\x96\xB8" => "\x79",
+ "\xF0\x9D\x96\xB9" => "\x7A",
+ "\xF0\x9D\x97\x94" => "\x61",
+ "\xF0\x9D\x97\x95" => "\x62",
+ "\xF0\x9D\x97\x96" => "\x63",
+ "\xF0\x9D\x97\x97" => "\x64",
+ "\xF0\x9D\x97\x98" => "\x65",
+ "\xF0\x9D\x97\x99" => "\x66",
+ "\xF0\x9D\x97\x9A" => "\x67",
+ "\xF0\x9D\x97\x9B" => "\x68",
+ "\xF0\x9D\x97\x9C" => "\x69",
+ "\xF0\x9D\x97\x9D" => "\x6A",
+ "\xF0\x9D\x97\x9E" => "\x6B",
+ "\xF0\x9D\x97\x9F" => "\x6C",
+ "\xF0\x9D\x97\xA0" => "\x6D",
+ "\xF0\x9D\x97\xA1" => "\x6E",
+ "\xF0\x9D\x97\xA2" => "\x6F",
+ "\xF0\x9D\x97\xA3" => "\x70",
+ "\xF0\x9D\x97\xA4" => "\x71",
+ "\xF0\x9D\x97\xA5" => "\x72",
+ "\xF0\x9D\x97\xA6" => "\x73",
+ "\xF0\x9D\x97\xA7" => "\x74",
+ "\xF0\x9D\x97\xA8" => "\x75",
+ "\xF0\x9D\x97\xA9" => "\x76",
+ "\xF0\x9D\x97\xAA" => "\x77",
+ "\xF0\x9D\x97\xAB" => "\x78",
+ "\xF0\x9D\x97\xAC" => "\x79",
+ "\xF0\x9D\x97\xAD" => "\x7A",
+ "\xF0\x9D\x98\x88" => "\x61",
+ "\xF0\x9D\x98\x89" => "\x62",
+ "\xF0\x9D\x98\x8A" => "\x63",
+ "\xF0\x9D\x98\x8B" => "\x64",
+ "\xF0\x9D\x98\x8C" => "\x65",
+ "\xF0\x9D\x98\x8D" => "\x66",
+ "\xF0\x9D\x98\x8E" => "\x67",
+ "\xF0\x9D\x98\x8F" => "\x68",
+ "\xF0\x9D\x98\x90" => "\x69",
+ "\xF0\x9D\x98\x91" => "\x6A",
+ "\xF0\x9D\x98\x92" => "\x6B",
+ "\xF0\x9D\x98\x93" => "\x6C",
+ "\xF0\x9D\x98\x94" => "\x6D",
+ "\xF0\x9D\x98\x95" => "\x6E",
+ "\xF0\x9D\x98\x96" => "\x6F",
+ "\xF0\x9D\x98\x97" => "\x70",
+ "\xF0\x9D\x98\x98" => "\x71",
+ "\xF0\x9D\x98\x99" => "\x72",
+ "\xF0\x9D\x98\x9A" => "\x73",
+ "\xF0\x9D\x98\x9B" => "\x74",
+ "\xF0\x9D\x98\x9C" => "\x75",
+ "\xF0\x9D\x98\x9D" => "\x76",
+ "\xF0\x9D\x98\x9E" => "\x77",
+ "\xF0\x9D\x98\x9F" => "\x78",
+ "\xF0\x9D\x98\xA0" => "\x79",
+ "\xF0\x9D\x98\xA1" => "\x7A",
+ "\xF0\x9D\x98\xBC" => "\x61",
+ "\xF0\x9D\x98\xBD" => "\x62",
+ "\xF0\x9D\x98\xBE" => "\x63",
+ "\xF0\x9D\x98\xBF" => "\x64",
+ "\xF0\x9D\x99\x80" => "\x65",
+ "\xF0\x9D\x99\x81" => "\x66",
+ "\xF0\x9D\x99\x82" => "\x67",
+ "\xF0\x9D\x99\x83" => "\x68",
+ "\xF0\x9D\x99\x84" => "\x69",
+ "\xF0\x9D\x99\x85" => "\x6A",
+ "\xF0\x9D\x99\x86" => "\x6B",
+ "\xF0\x9D\x99\x87" => "\x6C",
+ "\xF0\x9D\x99\x88" => "\x6D",
+ "\xF0\x9D\x99\x89" => "\x6E",
+ "\xF0\x9D\x99\x8A" => "\x6F",
+ "\xF0\x9D\x99\x8B" => "\x70",
+ "\xF0\x9D\x99\x8C" => "\x71",
+ "\xF0\x9D\x99\x8D" => "\x72",
+ "\xF0\x9D\x99\x8E" => "\x73",
+ "\xF0\x9D\x99\x8F" => "\x74",
+ "\xF0\x9D\x99\x90" => "\x75",
+ "\xF0\x9D\x99\x91" => "\x76",
+ "\xF0\x9D\x99\x92" => "\x77",
+ "\xF0\x9D\x99\x93" => "\x78",
+ "\xF0\x9D\x99\x94" => "\x79",
+ "\xF0\x9D\x99\x95" => "\x7A",
+ "\xF0\x9D\x99\xB0" => "\x61",
+ "\xF0\x9D\x99\xB1" => "\x62",
+ "\xF0\x9D\x99\xB2" => "\x63",
+ "\xF0\x9D\x99\xB3" => "\x64",
+ "\xF0\x9D\x99\xB4" => "\x65",
+ "\xF0\x9D\x99\xB5" => "\x66",
+ "\xF0\x9D\x99\xB6" => "\x67",
+ "\xF0\x9D\x99\xB7" => "\x68",
+ "\xF0\x9D\x99\xB8" => "\x69",
+ "\xF0\x9D\x99\xB9" => "\x6A",
+ "\xF0\x9D\x99\xBA" => "\x6B",
+ "\xF0\x9D\x99\xBB" => "\x6C",
+ "\xF0\x9D\x99\xBC" => "\x6D",
+ "\xF0\x9D\x99\xBD" => "\x6E",
+ "\xF0\x9D\x99\xBE" => "\x6F",
+ "\xF0\x9D\x99\xBF" => "\x70",
+ "\xF0\x9D\x9A\x80" => "\x71",
+ "\xF0\x9D\x9A\x81" => "\x72",
+ "\xF0\x9D\x9A\x82" => "\x73",
+ "\xF0\x9D\x9A\x83" => "\x74",
+ "\xF0\x9D\x9A\x84" => "\x75",
+ "\xF0\x9D\x9A\x85" => "\x76",
+ "\xF0\x9D\x9A\x86" => "\x77",
+ "\xF0\x9D\x9A\x87" => "\x78",
+ "\xF0\x9D\x9A\x88" => "\x79",
+ "\xF0\x9D\x9A\x89" => "\x7A",
+ "\xF0\x9D\x9A\xA8" => "\xCE\xB1",
+ "\xF0\x9D\x9A\xA9" => "\xCE\xB2",
+ "\xF0\x9D\x9A\xAA" => "\xCE\xB3",
+ "\xF0\x9D\x9A\xAB" => "\xCE\xB4",
+ "\xF0\x9D\x9A\xAC" => "\xCE\xB5",
+ "\xF0\x9D\x9A\xAD" => "\xCE\xB6",
+ "\xF0\x9D\x9A\xAE" => "\xCE\xB7",
+ "\xF0\x9D\x9A\xAF" => "\xCE\xB8",
+ "\xF0\x9D\x9A\xB0" => "\xCE\xB9",
+ "\xF0\x9D\x9A\xB1" => "\xCE\xBA",
+ "\xF0\x9D\x9A\xB2" => "\xCE\xBB",
+ "\xF0\x9D\x9A\xB3" => "\xCE\xBC",
+ "\xF0\x9D\x9A\xB4" => "\xCE\xBD",
+ "\xF0\x9D\x9A\xB5" => "\xCE\xBE",
+ "\xF0\x9D\x9A\xB6" => "\xCE\xBF",
+ "\xF0\x9D\x9A\xB7" => "\xCF\x80",
+ "\xF0\x9D\x9A\xB8" => "\xCF\x81",
+ "\xF0\x9D\x9A\xB9" => "\xCE\xB8",
+ "\xF0\x9D\x9A\xBA" => "\xCF\x83",
+ "\xF0\x9D\x9A\xBB" => "\xCF\x84",
+ "\xF0\x9D\x9A\xBC" => "\xCF\x85",
+ "\xF0\x9D\x9A\xBD" => "\xCF\x86",
+ "\xF0\x9D\x9A\xBE" => "\xCF\x87",
+ "\xF0\x9D\x9A\xBF" => "\xCF\x88",
+ "\xF0\x9D\x9B\x80" => "\xCF\x89",
+ "\xF0\x9D\x9B\x93" => "\xCF\x83",
+ "\xF0\x9D\x9B\xA2" => "\xCE\xB1",
+ "\xF0\x9D\x9B\xA3" => "\xCE\xB2",
+ "\xF0\x9D\x9B\xA4" => "\xCE\xB3",
+ "\xF0\x9D\x9B\xA5" => "\xCE\xB4",
+ "\xF0\x9D\x9B\xA6" => "\xCE\xB5",
+ "\xF0\x9D\x9B\xA7" => "\xCE\xB6",
+ "\xF0\x9D\x9B\xA8" => "\xCE\xB7",
+ "\xF0\x9D\x9B\xA9" => "\xCE\xB8",
+ "\xF0\x9D\x9B\xAA" => "\xCE\xB9",
+ "\xF0\x9D\x9B\xAB" => "\xCE\xBA",
+ "\xF0\x9D\x9B\xAC" => "\xCE\xBB",
+ "\xF0\x9D\x9B\xAD" => "\xCE\xBC",
+ "\xF0\x9D\x9B\xAE" => "\xCE\xBD",
+ "\xF0\x9D\x9B\xAF" => "\xCE\xBE",
+ "\xF0\x9D\x9B\xB0" => "\xCE\xBF",
+ "\xF0\x9D\x9B\xB1" => "\xCF\x80",
+ "\xF0\x9D\x9B\xB2" => "\xCF\x81",
+ "\xF0\x9D\x9B\xB3" => "\xCE\xB8",
+ "\xF0\x9D\x9B\xB4" => "\xCF\x83",
+ "\xF0\x9D\x9B\xB5" => "\xCF\x84",
+ "\xF0\x9D\x9B\xB6" => "\xCF\x85",
+ "\xF0\x9D\x9B\xB7" => "\xCF\x86",
+ "\xF0\x9D\x9B\xB8" => "\xCF\x87",
+ "\xF0\x9D\x9B\xB9" => "\xCF\x88",
+ "\xF0\x9D\x9B\xBA" => "\xCF\x89",
+ "\xF0\x9D\x9C\x8D" => "\xCF\x83",
+ "\xF0\x9D\x9C\x9C" => "\xCE\xB1",
+ "\xF0\x9D\x9C\x9D" => "\xCE\xB2",
+ "\xF0\x9D\x9C\x9E" => "\xCE\xB3",
+ "\xF0\x9D\x9C\x9F" => "\xCE\xB4",
+ "\xF0\x9D\x9C\xA0" => "\xCE\xB5",
+ "\xF0\x9D\x9C\xA1" => "\xCE\xB6",
+ "\xF0\x9D\x9C\xA2" => "\xCE\xB7",
+ "\xF0\x9D\x9C\xA3" => "\xCE\xB8",
+ "\xF0\x9D\x9C\xA4" => "\xCE\xB9",
+ "\xF0\x9D\x9C\xA5" => "\xCE\xBA",
+ "\xF0\x9D\x9C\xA6" => "\xCE\xBB",
+ "\xF0\x9D\x9C\xA7" => "\xCE\xBC",
+ "\xF0\x9D\x9C\xA8" => "\xCE\xBD",
+ "\xF0\x9D\x9C\xA9" => "\xCE\xBE",
+ "\xF0\x9D\x9C\xAA" => "\xCE\xBF",
+ "\xF0\x9D\x9C\xAB" => "\xCF\x80",
+ "\xF0\x9D\x9C\xAC" => "\xCF\x81",
+ "\xF0\x9D\x9C\xAD" => "\xCE\xB8",
+ "\xF0\x9D\x9C\xAE" => "\xCF\x83",
+ "\xF0\x9D\x9C\xAF" => "\xCF\x84",
+ "\xF0\x9D\x9C\xB0" => "\xCF\x85",
+ "\xF0\x9D\x9C\xB1" => "\xCF\x86",
+ "\xF0\x9D\x9C\xB2" => "\xCF\x87",
+ "\xF0\x9D\x9C\xB3" => "\xCF\x88",
+ "\xF0\x9D\x9C\xB4" => "\xCF\x89",
+ "\xF0\x9D\x9D\x87" => "\xCF\x83",
+ "\xF0\x9D\x9D\x96" => "\xCE\xB1",
+ "\xF0\x9D\x9D\x97" => "\xCE\xB2",
+ "\xF0\x9D\x9D\x98" => "\xCE\xB3",
+ "\xF0\x9D\x9D\x99" => "\xCE\xB4",
+ "\xF0\x9D\x9D\x9A" => "\xCE\xB5",
+ "\xF0\x9D\x9D\x9B" => "\xCE\xB6",
+ "\xF0\x9D\x9D\x9C" => "\xCE\xB7",
+ "\xF0\x9D\x9D\x9D" => "\xCE\xB8",
+ "\xF0\x9D\x9D\x9E" => "\xCE\xB9",
+ "\xF0\x9D\x9D\x9F" => "\xCE\xBA",
+ "\xF0\x9D\x9D\xA0" => "\xCE\xBB",
+ "\xF0\x9D\x9D\xA1" => "\xCE\xBC",
+ "\xF0\x9D\x9D\xA2" => "\xCE\xBD",
+ "\xF0\x9D\x9D\xA3" => "\xCE\xBE",
+ "\xF0\x9D\x9D\xA4" => "\xCE\xBF",
+ "\xF0\x9D\x9D\xA5" => "\xCF\x80",
+ "\xF0\x9D\x9D\xA6" => "\xCF\x81",
+ "\xF0\x9D\x9D\xA7" => "\xCE\xB8",
+ "\xF0\x9D\x9D\xA8" => "\xCF\x83",
+ "\xF0\x9D\x9D\xA9" => "\xCF\x84",
+ "\xF0\x9D\x9D\xAA" => "\xCF\x85",
+ "\xF0\x9D\x9D\xAB" => "\xCF\x86",
+ "\xF0\x9D\x9D\xAC" => "\xCF\x87",
+ "\xF0\x9D\x9D\xAD" => "\xCF\x88",
+ "\xF0\x9D\x9D\xAE" => "\xCF\x89",
+ "\xF0\x9D\x9E\x81" => "\xCF\x83",
+ "\xF0\x9D\x9E\x90" => "\xCE\xB1",
+ "\xF0\x9D\x9E\x91" => "\xCE\xB2",
+ "\xF0\x9D\x9E\x92" => "\xCE\xB3",
+ "\xF0\x9D\x9E\x93" => "\xCE\xB4",
+ "\xF0\x9D\x9E\x94" => "\xCE\xB5",
+ "\xF0\x9D\x9E\x95" => "\xCE\xB6",
+ "\xF0\x9D\x9E\x96" => "\xCE\xB7",
+ "\xF0\x9D\x9E\x97" => "\xCE\xB8",
+ "\xF0\x9D\x9E\x98" => "\xCE\xB9",
+ "\xF0\x9D\x9E\x99" => "\xCE\xBA",
+ "\xF0\x9D\x9E\x9A" => "\xCE\xBB",
+ "\xF0\x9D\x9E\x9B" => "\xCE\xBC",
+ "\xF0\x9D\x9E\x9C" => "\xCE\xBD",
+ "\xF0\x9D\x9E\x9D" => "\xCE\xBE",
+ "\xF0\x9D\x9E\x9E" => "\xCE\xBF",
+ "\xF0\x9D\x9E\x9F" => "\xCF\x80",
+ "\xF0\x9D\x9E\xA0" => "\xCF\x81",
+ "\xF0\x9D\x9E\xA1" => "\xCE\xB8",
+ "\xF0\x9D\x9E\xA2" => "\xCF\x83",
+ "\xF0\x9D\x9E\xA3" => "\xCF\x84",
+ "\xF0\x9D\x9E\xA4" => "\xCF\x85",
+ "\xF0\x9D\x9E\xA5" => "\xCF\x86",
+ "\xF0\x9D\x9E\xA6" => "\xCF\x87",
+ "\xF0\x9D\x9E\xA7" => "\xCF\x88",
+ "\xF0\x9D\x9E\xA8" => "\xCF\x89",
+ "\xF0\x9D\x9E\xBB" => "\xCF\x83",
+ "\xF0\x9D\x9F\x8A" => "\xCF\x9D",
+ );
+ global $phpbb_root_path, $phpEx;
+
+ // do the case fold
+ $text = utf8_new_case_fold($text, $option);
+
+ // convert to NFKC
+ $text = Normalizer::normalize($text, Normalizer::NFKC);
+
+ // FC_NFKC_Closure, http://www.unicode.org/Public/5.0.0/ucd/DerivedNormalizationProps.txt
+ $text = strtr($text, $fc_nfkc_closure);
+
+ return $text;
+}
+
+return array('Ā”'=>'i','ǃ'=>'!','α'=>'a','įš€'=>' ','Ā­'=>'','Ū'=>'','܏'=>'','į †'=>'','į Ž'=>'','​'=>'','ā€Œ'=>'','ā€'=>'','
'=>'','
'=>'','⁠'=>'','⁔'=>'','⁢'=>'','⁣'=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'','ļæ¹'=>'','ļæŗ'=>'','ļæ»'=>'','ļæ¼'=>'','š…³'=>'','š…“'=>'','š…µ'=>'','š…¶'=>'','š…·'=>'','š…ø'=>'','š…¹'=>'','š…ŗ'=>'','Ū¬'=>'۟','̓'=>'Ģ“','Ł'=>'Ģ“','֜'=>'́','́'=>'́','݇'=>'́','ą„”'=>'́','Ķ€'=>'Ģ€','ą„“'=>'Ģ€','̌'=>'̆','Ģ‘'=>'Ģ‚','ÖÆ'=>'̊','ஂ'=>'̊','ą¹'=>'̊','ą»'=>'̊','ံ'=>'̊','įŸ†'=>'̊','įŸ“'=>'̊','悚'=>'̊','゚'=>'̊','ͦ'=>'̊','Ķ‚'=>'̃','ׄ'=>'̇','Ö¹'=>'̇','ׂ'=>'̇','ׁ'=>'̇','݁'=>'̇','ं'=>'̇','ਂ'=>'̇','ąŖ‚'=>'̇','ąÆ'=>'̇','Ģ…'=>'Ģ„','怬'=>'̉','̱'=>'Ģ ','ą„’'=>'Ģ ','̧'=>'Ģ”','̦'=>'Ģ”','ĢØ'=>'Ģ¢','़'=>'Ģ£','়'=>'Ģ£','਼'=>'Ģ£','ąŖ¼'=>'Ģ£','଼'=>'Ģ£','͇'=>'̳','̶'=>'̵','ļ±ž'=>'ﹲّ','ﱟ'=>'﹓ّ','ļ³²'=>'ļ¹·Ł‘','ļ± '=>'ļ¹¶Ł‘','ļ³³'=>'ﹹّ','ļ±”'=>'ļ¹øŁ‘','ﳓ'=>'ﹻّ','ļ±¢'=>'ļ¹ŗŁ‘','ļ±£'=>'ﹼٰ','Ł“'=>'Ł”','Ż‚'=>'ܼ','౦'=>'o','೦'=>'o','ļ¾ž'=>'悙','怀'=>' ',' '=>' ',' '=>' ',' '=>' ','ā€ƒ'=>' ',' '=>' ',' '=>' ',' '=>' ','ā€ˆ'=>' ',' '=>' ','ā€Š'=>' ',' '=>' ','Ā '=>' ',' '=>' ',' '=>' ','`'=>'`','ļ½€'=>'`','῀'=>'˜','ļ¼¾'=>'^','ļøæ'=>'^','_'=>'_','ļ¹'=>'_','ļ¹Ž'=>'_','ļ¹'=>'_','āŒ‡'=>'ļø“','ļ¼'=>'-','‐'=>'-','‑'=>'-','‒'=>'-','–'=>'-','﹘'=>'-','∼'=>'⁓','d'=>'惻','•'=>'惻',','=>',','ā€š'=>',','٬'=>'،','、'=>'态',';'=>';','ļ¼›'=>';',':'=>':','։'=>':','ļø°'=>':','׃'=>':','ā©“'=>'::=','ļ¼Ž'=>'.','․'=>'.','܂'=>'.',' '=>'..','…'=>'...','ļ½”'=>'怂','·'=>'Ā·','‧'=>'Ā·','āˆ™'=>'Ā·','ā‹…'=>'Ā·','ᐧ'=>'Ā·','ᔯ'=>'Ā·4','ᐌ'=>'·ᐁ','įŽ'=>'·ᐃ','ᐐ'=>'·ᐄ','ᐒ'=>'·ᐅ','ᐔ'=>'·ᐆ','ᐗ'=>'·ᐊ','ᐙ'=>'·ᐋ','ᐷ'=>'·ᐳ','į‘€'=>'·ᐳ','į‘‚'=>'·ᐓ','į‘„'=>'·ᐸ','ᑆ'=>'·ᐹ','į‘—'=>'Ā·į‘Œ','į‘™'=>'Ā·į‘Ž','į‘›'=>'Ā·į‘','į‘”'=>'·ᑐ','į‘'=>'·ᑐ','į‘Ÿ'=>'Ā·į‘‘','į‘”'=>'Ā·į‘•','į‘£'=>'Ā·į‘–','į‘“'=>'Ā·į‘«','ᑸ'=>'Ā·į‘®','ᑼ'=>'Ā·į‘°','ᑾ'=>'·ᑲ','į’€'=>'·ᑳ','į’’'=>'Ā·į’‰','į’”'=>'Ā·į’‹','į’–'=>'Ā·į’Œ','į’š'=>'Ā·į’Ž','į’œ'=>'·ᒐ','į’ž'=>'Ā·į’‘','į’¬'=>'Ā·į’£','į’®'=>'Ā·į’„','į’°'=>'Ā·į’¦','į’²'=>'Ā·į’§','į’“'=>'Ā·į’Ø','į’¶'=>'Ā·L','į’ø'=>'Ā·į’«','ᓉ'=>'Ā·į“€','į“‹'=>'·ᓇ','į“'=>'Ā·į“ˆ','į“œ'=>'Ā·į““','į“ž'=>'Ā·į“•','į“ '=>'Ā·į“–','į“¢'=>'Ā·į“—','ᓤ'=>'Ā·į“˜','ᓦ'=>'Ā·į“š','ᓨ'=>'Ā·į“›','į“¶'=>'Ā·į“­','ᓸ'=>'·ᓯ','ᓺ'=>'Ā·į“°','ᓼ'=>'·ᓱ','ᓾ'=>'·ᓲ','ᔀ'=>'Ā·į““','ᔂ'=>'·ᓵ','į”—'=>'·ᔐ','į”™'=>'·ᔑ','į”›'=>'Ā·į”’','į”'=>'·ᔓ','į”Ÿ'=>'Ā·į””','į””'=>'·ᔕ','ᔣ'=>'Ā·į”–','į”±'=>'·ᔨ','ᔳ'=>'·ᔩ','ᔵ'=>'·ᔪ','į”·'=>'·ᔫ','ᔹ'=>'Ā·į”­','į”»'=>'Ā·į”®','į•Ž'=>'Ā·į•Œ','į•›'=>'Ā·į•š','ᕨ'=>'Ā·į•§','('=>'(','ā‘“'=>'(1)','ā’§'=>'(l)','⑽'=>'(10)','⑾'=>'(11)','⑿'=>'(12)','ā’€'=>'(13)','⒁'=>'(14)','ā’‚'=>'(15)','ā’ƒ'=>'(16)','ā’„'=>'(17)','ā’…'=>'(18)','ā’†'=>'(19)','⑵'=>'(2)','ā’‡'=>'(20)','ā‘¶'=>'(3)','ā‘·'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','ā‘»'=>'(8)','⑼'=>'(9)','ā’œ'=>'(a)','ā’'=>'(b)','ā’ž'=>'(c)','ā’Ÿ'=>'(d)','ā’ '=>'(e)','ā’”'=>'(f)','ā’¢'=>'(g)','ā’£'=>'(h)','ā’¤'=>'(i)','ā’„'=>'(j)','ā’¦'=>'(k)','ā’Ø'=>'(m)','ā’©'=>'(n)','ā’Ŗ'=>'(o)','ā’«'=>'(p)','ā’¬'=>'(q)','ā’­'=>'(r)','ā’®'=>'(s)','ā’Æ'=>'(t)','ā’°'=>'(u)','ā’±'=>'(v)','ā’²'=>'(w)','ā’³'=>'(x)','ā’“'=>'(y)','ā’µ'=>'(z)','戀'=>'(į„€)','戎'=>'(ź°€)','戁'=>'(į„‚)','戏'=>'(ė‚˜)','戂'=>'(į„ƒ)','成'=>'(다)','戃'=>'(į„…)','我'=>'(ė¼)','戄'=>'(ᄆ)','戒'=>'(마)','戅'=>'(ᄇ)','戓'=>'(ė°”)','戆'=>'(ᄉ)','戔'=>'(사)','戇'=>'(į„‹)','戕'=>'(ģ•„)','戝'=>'(ģ˜¤ģ „)','戞'=>'(ģ˜¤ķ›„)','戈'=>'(į„Œ)','或'=>'(ģž)','㈜'=>'(주)','戉'=>'(į„Ž)','戗'=>'(ģ°Ø)','㈊'=>'(į„)','战'=>'(칓)','戋'=>'(ᄐ)','戙'=>'(ķƒ€)','㈌'=>'(į„‘)','㈚'=>'(파)','戍'=>'(į„’)','戛'=>'(ķ•˜)','戠'=>'(äø€)','戦'=>'(七)','㈢'=>'(äø‰)','㈨'=>'(九)','戔'=>'(二)','戤'=>'(äŗ”)','㈹'=>'(代)','㈽'=>'(企)','扁'=>'(休)','戧'=>'(八)','戄'=>'(六)','㈸'=>'(劓)','戩'=>'(十)','㈿'=>'(協)','戓'=>'(名)','㈺'=>'(呼)','㈣'=>'(四)','㈯'=>'(土)','戻'=>'(å­¦)','戰'=>'(ę—„)','㈪'=>'(月)','㈲'=>'(꜉)','戭'=>'(木)','戱'=>'(ę Ŗ)','戬'=>'(ę°“)','戫'=>'(火)','戵'=>'(特)','㈼'=>'(監)','㈳'=>'(社)','户'=>'(ē„)','所'=>'(ē„­)','扂'=>'(自)','扃'=>'(至)','戶'=>'(č²”)','㈾'=>'(資)','戮'=>'(金)',')'=>')','ļ¼»'=>'[','怔'=>'[','ļ¼½'=>']','怕'=>']','ļ½›'=>'{','ļ½'=>'}','⦅'=>'⦅','ļ½ '=>'⦆','ļ½¢'=>'怌','ļ½£'=>'怍','ļ¼ '=>'@','*'=>'*','ļ¼'=>'/','⁄'=>'/','āˆ•'=>'/','ļ¼¼'=>'\\','&'=>'&','#'=>'#','ļ¼…'=>'%','‶'=>'‵‵','‷'=>'‵‵‵','༌'=>'་','Ā“'=>'ʹ','Ī„'=>'ʹ','įæ½'=>'ʹ','\''=>'ʹ','''=>'ʹ','′'=>'ʹ','׳'=>'ʹ','Ķ“'=>'ʹ','ˊ'=>'ʹ','"'=>'ʹʹ','"'=>'ʹʹ','″'=>'ʹʹ','怃'=>'ʹʹ','ד'=>'ʹʹ','Źŗ'=>'ʹʹ','–'=>'ʹʹʹ','⁗'=>'ʹʹʹʹ','ĀÆ'=>'ˉ',' ̄'=>'ˉ','‾'=>'ˉ','﹉'=>'ˉ','﹊'=>'ˉ','﹋'=>'ˉ','﹌'=>'ˉ','˚'=>'°','௵'=>'௳','ļæ©'=>'←','ļæ«'=>'→','ļæŖ'=>'↑','↓'=>'↓','↵'=>'↲','⨔'=>'↾','š››'=>'āˆ‚','šœ•'=>'āˆ‚','š'=>'āˆ‚','šž‰'=>'āˆ‚','šŸƒ'=>'āˆ‚','š›'=>'āˆ‡','š›»'=>'āˆ‡','šœµ'=>'āˆ‡','šÆ'=>'āˆ‡','šž©'=>'āˆ‡','+'=>'+','﬩'=>'+','‹'=>'<','<'=>'<','ļ¼'=>'=','⩵'=>'==','ā©¶'=>'===','›'=>'>','ļ¼ž'=>'>','¬'=>'¬','¦'=>'¦','怜'=>'~','ļ½ž'=>'~','﹨'=>'āˆ–','ā‹€'=>'∧','⋁'=>'∨','ā‹‚'=>'∩','ā‹ƒ'=>'∪','∯'=>'∮∮','∰'=>'∮∮∮','≣'=>'≔','♁'=>'āŠ•','ā˜‰'=>'āŠ™','āŸ‚'=>'⊄','ā–·'=>'⊲','āØ'=>'ā‹ˆ','⨽'=>'āŒ™','☸'=>'āŽˆ','āŽ®'=>'āŽ„','│'=>'│','▐'=>'ā–Œ','ļæ­'=>'ā– ','☐'=>'ā–”','ļæ®'=>'ā—‹','⦾'=>'ā—Ž','怛'=>'⟧','〈'=>'⟨','怈'=>'⟨','〉'=>'⟩','怉'=>'⟩','ā§™'=>'⦚','怶'=>'怒','ļ½°'=>'ー','ļæ '=>'Ā¢','$'=>'$','ļæ”'=>'Ā£','ļæ„'=>'Y̵','₩'=>'W̵','0'=>'0','šŸŽ'=>'0','šŸ˜'=>'0','šŸ¢'=>'0','šŸ¬'=>'0','šŸ¶'=>'0','০'=>'0','ą­¦'=>'0','௦'=>'0','᠐'=>'0','怇'=>'0','šŽ'=>'0','š‘‚'=>'0','š‘¶'=>'0','š’Ŗ'=>'0','š“ž'=>'0','š”’'=>'0','š•†'=>'0','š•ŗ'=>'0','š–®'=>'0','š—¢'=>'0','š˜–'=>'0','š™Š'=>'0','š™¾'=>'0','šš¶'=>'0','š›°'=>'0','šœŖ'=>'0','š¤'=>'0','šžž'=>'0','āµ”'=>'0','ą“ '=>'0','āŠ–'=>'0̵','ššÆ'=>'0̵','šš¹'=>'0̵','š›©'=>'0̵','š›³'=>'0̵','šœ£'=>'0̵','šœ­'=>'0̵','š'=>'0̵','š§'=>'0̵','šž—'=>'0̵','šž”'=>'0̵','⓱'=>'0̵','įŽ¾'=>'0̵','Ū°'=>'Ł ','᭜'=>'᭐','捘'=>'0点','1'=>'1','šŸ'=>'1','šŸ™'=>'1','šŸ£'=>'1','šŸ­'=>'1','šŸ·'=>'1','ℐ'=>'1','ā„‘'=>'1','šˆ'=>'1','š¼'=>'1','š‘°'=>'1','š“˜'=>'1','š•€'=>'1','š•“'=>'1','š–Ø'=>'1','š—œ'=>'1','š˜'=>'1','š™„'=>'1','š™ø'=>'1','l'=>'l','l'=>'l','ā…¼'=>'1','ā„“'=>'l','š„'=>'l','š‘™'=>'l','š’'=>'l','š“'=>'l','š“µ'=>'l','š”©'=>'l','š•'=>'l','š–‘'=>'l','š—…'=>'l','š—¹'=>'l','š˜­'=>'l','š™”'=>'l','šš•'=>'l','šš°'=>'l','š›Ŗ'=>'l','šœ¤'=>'l','šž'=>'l','šž˜'=>'l','ā‘ '=>'āž€','É­'=>'lĢ¢','É«'=>'lĢ“','ƚ'=>'l̵','ł'=>'lĢ·','Ū±'=>'Ł”','ā’ˆ'=>'1.','ŀ'=>'lĀ·','į’·'=>'1Ā·','ā‘©'=>'āž‰','ā’‘'=>'10.','ć©'=>'10ę—„','拉'=>'10月','ć¢'=>'10点','ā’’'=>'11.','ćŖ'=>'11ę—„','拊'=>'11月','ć£'=>'11点','ā’“'=>'12.','ć«'=>'12ę—„','拋'=>'12月','捤'=>'12点','ā’”'=>'13.','ć¬'=>'13ę—„','ć„'=>'13点','ā’•'=>'14.','揭'=>'14ę—„','ć¦'=>'14点','ā’–'=>'15.','ć®'=>'15ę—„','捧'=>'15点','ā’—'=>'16.','ćÆ'=>'16ę—„','ćØ'=>'16点','ā’˜'=>'17.','揰'=>'17ę—„','ć©'=>'17点','ā’™'=>'18.','ć±'=>'18ę—„','ćŖ'=>'18点','ā’š'=>'19.','ć²'=>'19ę—„','ć«'=>'19点','lj'=>'lj','揠'=>'1ę—„','拀'=>'1月','捙'=>'1点','ļ¼’'=>'2','šŸ'=>'2','šŸš'=>'2','šŸ¤'=>'2','šŸ®'=>'2','šŸø'=>'2','į’æ'=>'2','ā‘”'=>'āž','Ū²'=>'Ł¢','ā’‰'=>'2.','ā’›'=>'20.','ć³'=>'20ę—„','ć¬'=>'20点','ć“'=>'21ę—„','捭'=>'21点','ćµ'=>'22ę—„','ć®'=>'22点','ć¶'=>'23ę—„','ćÆ'=>'23点','ć·'=>'24ę—„','捰'=>'24点','ćø'=>'25ę—„','ć¹'=>'26ę—„','ćŗ'=>'27ę—„','ć»'=>'28ę—„','ć¼'=>'29ę—„','ć”'=>'2ę—„','拁'=>'2月','捚'=>'2点','3'=>'3','šŸ‘'=>'3','šŸ›'=>'3','šŸ„'=>'3','šŸÆ'=>'3','šŸ¹'=>'3','ā‘¢'=>'āž‚','Ū³'=>'Ł£','ā’Š'=>'3.','ć½'=>'30ę—„','ć¾'=>'31ę—„','ć¢'=>'3ę—„','拂'=>'3月','捛'=>'3点','ļ¼”'=>'4','šŸ’'=>'4','šŸœ'=>'4','šŸ¦'=>'4','šŸ°'=>'4','šŸŗ'=>'4','įŽ'=>'4','ā‘£'=>'āžƒ','ā’‹'=>'4.','į”°'=>'4Ā·','ć£'=>'4ę—„','拃'=>'4月','捜'=>'4点','5'=>'5','šŸ“'=>'5','šŸ'=>'5','šŸ§'=>'5','šŸ±'=>'5','šŸ»'=>'5','⑤'=>'āž„','ā’Œ'=>'5.','揤'=>'5ę—„','拄'=>'5月','捝'=>'5点','ļ¼–'=>'6','šŸ”'=>'6','šŸž'=>'6','šŸØ'=>'6','šŸ²'=>'6','šŸ¼'=>'6','б'=>'6','ā‘„'=>'āž…','ā’'=>'6.','ć„'=>'6ę—„','担'=>'6月','捞'=>'6点','ļ¼—'=>'7','šŸ•'=>'7','šŸŸ'=>'7','šŸ©'=>'7','šŸ³'=>'7','šŸ½'=>'7','⑦'=>'āž†','Ū·'=>'٧','ā’Ž'=>'7.','ć¦'=>'7ę—„','拆'=>'7月','损'=>'7点','ଃ'=>'8','ą§Ŗ'=>'8','੪'=>'8','8'=>'8','šŸ–'=>'8','šŸ '=>'8','šŸŖ'=>'8','šŸ“'=>'8','šŸ¾'=>'8','Č£'=>'8','ā‘§'=>'āž‡','Ūø'=>'ŁØ','ā’'=>'8.','揧'=>'8ę—„','拇'=>'8月','捠'=>'8点','ą©§'=>'9','ą­Ø'=>'9','ą§­'=>'9','ļ¼™'=>'9','šŸ—'=>'9','šŸ”'=>'9','šŸ«'=>'9','šŸµ'=>'9','šŸæ'=>'9','⑨'=>'āžˆ','Ū¹'=>'Ł©','⒐'=>'9.','ćØ'=>'9ę—„','拈'=>'9月','ć”'=>'9点','a'=>'a','šš'=>'a','š‘Ž'=>'a','š’‚'=>'a','š’¶'=>'a','š“Ŗ'=>'a','š”ž'=>'a','š•’'=>'a','š–†'=>'a','š–ŗ'=>'a','š—®'=>'a','š˜¢'=>'a','š™–'=>'a','ššŠ'=>'a','ā„€'=>'a/c','℁'=>'a/s','Ʀ'=>'ae','b'=>'b','š›'=>'b','š‘'=>'b','š’ƒ'=>'b','š’·'=>'b','š“«'=>'b','š”Ÿ'=>'b','š•“'=>'b','š–‡'=>'b','š–»'=>'b','š—Æ'=>'b','š˜£'=>'b','š™—'=>'b','šš‹'=>'b','ɓ'=>'bĢ”','ʃ'=>'bĢ„','ʀ'=>'b̵','c'=>'c','ā…½'=>'c','šœ'=>'c','š‘'=>'c','š’„'=>'c','š’ø'=>'c','š“¬'=>'c','š” '=>'c','š•”'=>'c','š–ˆ'=>'c','š–¼'=>'c','š—°'=>'c','š˜¤'=>'c','š™˜'=>'c','ššŒ'=>'c','š›“'=>'c','šœ'=>'c','š‡'=>'c','šž'=>'c','šž»'=>'c','ā„…'=>'c/o','℆'=>'c/u','d'=>'d','ā…¾'=>'d','ā…†'=>'d','š'=>'d','š‘‘'=>'d','š’…'=>'d','š’¹'=>'d','š“­'=>'d','š””'=>'d','š••'=>'d','š–‰'=>'d','š–½'=>'d','š—±'=>'d','š˜„'=>'d','š™™'=>'d','šš'=>'d','ɗ'=>'dĢ”','ƌ'=>'dĢ„','ɖ'=>'dĢ¢','đ'=>'d̵','dz'=>'dz','dž'=>'dž','ļ½…'=>'e','ℯ'=>'e','ā…‡'=>'e','šž'=>'e','š‘’'=>'e','š’†'=>'e','š“®'=>'e','š”¢'=>'e','š•–'=>'e','š–Š'=>'e','š–¾'=>'e','š—²'=>'e','š˜¦'=>'e','š™š'=>'e','ššŽ'=>'e','⓹'=>'E','ə'=>'Ē','ɚ'=>'ĒĖž','ā‹“'=>'ɛ','š›†'=>'ɛ','š›œ'=>'ɛ','šœ€'=>'ɛ','šœ–'=>'ɛ','šœŗ'=>'ɛ','š'=>'ɛ','š“'=>'ɛ','šžŠ'=>'ɛ','šž®'=>'ɛ','šŸ„'=>'ɛ','f'=>'f','šŸ'=>'f','š‘“'=>'f','š’‡'=>'f','š’»'=>'f','š“Æ'=>'f','š”£'=>'f','š•—'=>'f','š–‹'=>'f','š–æ'=>'f','š—³'=>'f','š˜§'=>'f','š™›'=>'f','šš'=>'f','ʒ'=>'fĢ”','g'=>'g','ā„Š'=>'g','š '=>'g','š‘”'=>'g','š’ˆ'=>'g','š“°'=>'g','š”¤'=>'g','š•˜'=>'g','š–Œ'=>'g','š—€'=>'g','š—“'=>'g','š˜Ø'=>'g','š™œ'=>'g','šš'=>'g','É”'=>'g','É '=>'gĢ”','Ē„'=>'g̵','h'=>'h','ā„Ž'=>'h','š”'=>'h','š’‰'=>'h','š’½'=>'h','š“±'=>'h','š”„'=>'h','š•™'=>'h','š–'=>'h','š—'=>'h','š—µ'=>'h','š˜©'=>'h','š™'=>'h','šš‘'=>'h','ɦ'=>'hĢ”','ħ'=>'h̵','ā„'=>'h̵','įæ¾'=>'Ź»','ā€˜'=>'Ź»','‛'=>'Ź»','ʽ'=>'Ź»','ā³'=>'i','i'=>'i','ā…°'=>'i','ℹ'=>'i','ā…ˆ'=>'i','š¢'=>'i','š‘–'=>'i','š’Š'=>'i','š’¾'=>'i','š“²'=>'i','š”¦'=>'i','š•š'=>'i','š–Ž'=>'i','š—‚'=>'i','š—¶'=>'i','š˜Ŗ'=>'i','š™ž'=>'i','šš’'=>'i','ı'=>'i','šš¤'=>'i','ÉŖ'=>'i','É©'=>'i','š›Š'=>'i','šœ„'=>'i','šœ¾'=>'i','šø'=>'i','šž²'=>'i','ÉØ'=>'i̵','ā…±'=>'ii','ā…²'=>'iii','ij'=>'ij','ā…³'=>'iv','ā…ø'=>'ix','j'=>'j','ā…‰'=>'j','š£'=>'j','š‘—'=>'j','š’‹'=>'j','š’æ'=>'j','š“³'=>'j','š”§'=>'j','š•›'=>'j','š–'=>'j','š—ƒ'=>'j','š—·'=>'j','š˜«'=>'j','š™Ÿ'=>'j','šš“'=>'j','ϳ'=>'j','šš„'=>'Č·','k'=>'k','š¤'=>'k','š‘˜'=>'k','š’Œ'=>'k','š“€'=>'k','š““'=>'k','š”Ø'=>'k','š•œ'=>'k','š–'=>'k','š—„'=>'k','š—ø'=>'k','š˜¬'=>'k','š™ '=>'k','šš”'=>'k','ʙ'=>'kĢ”','ļ½'=>'m','ā…æ'=>'m','š¦'=>'m','š‘š'=>'m','š’Ž'=>'m','š“‚'=>'m','š“¶'=>'m','š”Ŗ'=>'m','š•ž'=>'m','š–’'=>'m','š—†'=>'m','š—ŗ'=>'m','š˜®'=>'m','š™¢'=>'m','šš–'=>'m','ɱ'=>'mĢ”','ļ½Ž'=>'n','š§'=>'n','š‘›'=>'n','š’'=>'n','š“ƒ'=>'n','š“·'=>'n','š”«'=>'n','š•Ÿ'=>'n','š–“'=>'n','š—‡'=>'n','š—»'=>'n','š˜Æ'=>'n','š™£'=>'n','šš—'=>'n','š'=>'N','š‘'=>'N','š‘µ'=>'N','š’©'=>'N','š“'=>'N','š”‘'=>'N','š•¹'=>'N','š–­'=>'N','š—”'=>'N','š˜•'=>'N','š™‰'=>'N','š™½'=>'N','šš“'=>'N','š›®'=>'N','šœØ'=>'N','š¢'=>'N','šžœ'=>'N','ɲ'=>'ņ','ɳ'=>'nĢ¢','ʞ'=>'nĢ©','š›ˆ'=>'nĢ©','šœ‚'=>'nĢ©','šœ¼'=>'nĢ©','š¶'=>'nĢ©','šž°'=>'nĢ©','nj'=>'nj','ļ½'=>'o','ā„“'=>'o','šØ'=>'o','š‘œ'=>'o','š’'=>'o','š“ø'=>'o','š”¬'=>'o','š• '=>'o','š–”'=>'o','š—ˆ'=>'o','š—¼'=>'o','š˜°'=>'o','š™¤'=>'o','šš˜'=>'o','į“'=>'o','š›'=>'o','šœŠ'=>'o','š„'=>'o','š¾'=>'o','šžø'=>'o','ɵ'=>'o̵','Ēæ'=>'ó̵','Ćø'=>'oĢ·','œ'=>'oe','Ę”'=>'oʼ','ā“'=>'p','p'=>'p','š©'=>'p','š‘'=>'p','š’‘'=>'p','š“…'=>'p','š“¹'=>'p','š”­'=>'p','š•”'=>'p','š–•'=>'p','š—‰'=>'p','š—½'=>'p','š˜±'=>'p','š™„'=>'p','šš™'=>'p','š›’'=>'p','š› '=>'p','šœŒ'=>'p','šœš'=>'p','š†'=>'p','š”'=>'p','šž€'=>'p','šžŽ'=>'p','šžŗ'=>'p','šŸˆ'=>'p','Ę„'=>'pĢ”','q'=>'q','šŖ'=>'q','š‘ž'=>'q','š’’'=>'q','š“†'=>'q','š“ŗ'=>'q','š”®'=>'q','š•¢'=>'q','š––'=>'q','š—Š'=>'q','š—¾'=>'q','š˜²'=>'q','š™¦'=>'q','ššš'=>'q','š'=>'Q','š‘„'=>'Q','š‘ø'=>'Q','š’¬'=>'Q','š“ '=>'Q','š””'=>'Q','š•¼'=>'Q','š–°'=>'Q','š—¤'=>'Q','š˜˜'=>'Q','š™Œ'=>'Q','šš€'=>'Q','Ź '=>'qĢ”','š›‹'=>'Äø','š›ž'=>'Äø','šœ…'=>'Äø','šœ˜'=>'Äø','šœæ'=>'Äø','š’'=>'Äø','š¹'=>'Äø','šžŒ'=>'Äø','šž³'=>'Äø','šŸ†'=>'Äø','ļ½’'=>'r','š«'=>'r','š‘Ÿ'=>'r','š’“'=>'r','š“‡'=>'r','š“»'=>'r','š”Æ'=>'r','š•£'=>'r','š–—'=>'r','š—‹'=>'r','š—æ'=>'r','š˜³'=>'r','š™§'=>'r','šš›'=>'r','ɽ'=>'rĢ¢','ɼ'=>'rĢ©','s'=>'s','š¬'=>'s','š‘ '=>'s','š’”'=>'s','š“ˆ'=>'s','š“¼'=>'s','š”°'=>'s','š•¤'=>'s','š–˜'=>'s','š—Œ'=>'s','š˜€'=>'s','š˜“'=>'s','š™Ø'=>'s','ššœ'=>'s','ƽ'=>'s','Ź‚'=>'sĢ¢','∫'=>'ʃ','∬'=>'ʃʃ','∭'=>'ʃʃʃ','⨌'=>'ʃʃʃʃ','ļ½”'=>'t','š­'=>'t','š‘”'=>'t','š’•'=>'t','š“‰'=>'t','š“½'=>'t','š”±'=>'t','š•„'=>'t','š–™'=>'t','š—'=>'t','š˜'=>'t','š˜µ'=>'t','š™©'=>'t','šš'=>'t','š‘‡'=>'T','š‘»'=>'T','š’Æ'=>'T','š“£'=>'T','š”—'=>'T','š•‹'=>'T','š•æ'=>'T','š–³'=>'T','š—§'=>'T','š˜›'=>'T','š™'=>'T','ššƒ'=>'T','šš»'=>'T','š›µ'=>'T','šœÆ'=>'T','š©'=>'T','šž£'=>'T','Ę­'=>'tĢ”','ț'=>'Å£','Ę«'=>'Å£','ŧ'=>'t̵','u'=>'u','š®'=>'u','š‘¢'=>'u','š’–'=>'u','š“Š'=>'u','š“¾'=>'u','š”²'=>'u','š•¦'=>'u','š–š'=>'u','š—Ž'=>'u','š˜‚'=>'u','š˜¶'=>'u','š™Ŗ'=>'u','ššž'=>'u','ʊ'=>'u','Ź‹'=>'u','š›–'=>'u','šœ'=>'u','šŠ'=>'u','šž„'=>'u','šž¾'=>'u','š‘ˆ'=>'U','š‘¼'=>'U','š’°'=>'U','š“¤'=>'U','š”˜'=>'U','š•Œ'=>'U','š–€'=>'U','š–“'=>'U','š—Ø'=>'U','š˜œ'=>'U','š™'=>'U','šš„'=>'U','ļ½–'=>'v','ā…“'=>'v','šÆ'=>'v','š‘£'=>'v','š’—'=>'v','š“‹'=>'v','š“æ'=>'v','š”³'=>'v','š•§'=>'v','š–›'=>'v','š—'=>'v','š˜ƒ'=>'v','š˜·'=>'v','š™«'=>'v','ššŸ'=>'v','š›Ž'=>'v','šœˆ'=>'v','š‚'=>'v','š¼'=>'v','šž¶'=>'v','ā…µ'=>'vi','ā…¶'=>'vii','ā…·'=>'viii','ÉÆ'=>'w','ļ½—'=>'w','š°'=>'w','š‘¤'=>'w','š’˜'=>'w','š“Œ'=>'w','š”€'=>'w','š”“'=>'w','š•Ø'=>'w','š–œ'=>'w','š—'=>'w','š˜„'=>'w','š˜ø'=>'w','š™¬'=>'w','šš '=>'w','š‘Š'=>'W','š‘¾'=>'W','š’²'=>'W','š“¦'=>'W','š”š'=>'W','š•Ž'=>'W','š–‚'=>'W','š–¶'=>'W','š—Ŗ'=>'W','š˜ž'=>'W','š™’'=>'W','šš†'=>'W','Ɨ'=>'x','x'=>'x','ā…¹'=>'x','š±'=>'x','š‘„'=>'x','š’™'=>'x','š“'=>'x','š”'=>'x','š”µ'=>'x','š•©'=>'x','š–'=>'x','š—‘'=>'x','š˜…'=>'x','š˜¹'=>'x','š™­'=>'x','šš”'=>'x','į™­'=>'X','š‘‹'=>'X','š‘æ'=>'X','š’³'=>'X','š“§'=>'X','š”›'=>'X','š•'=>'X','š–ƒ'=>'X','š–·'=>'X','š—«'=>'X','š˜Ÿ'=>'X','š™“'=>'X','šš‡'=>'X','šš¾'=>'X','š›ø'=>'X','šœ²'=>'X','š¬'=>'X','šž¦'=>'X','ā…ŗ'=>'xi','ā…»'=>'xii','ļ½™'=>'y','š²'=>'y','š‘¦'=>'y','š’š'=>'y','š“Ž'=>'y','š”‚'=>'y','š”¶'=>'y','š•Ŗ'=>'y','š–ž'=>'y','š—’'=>'y','š˜†'=>'y','š˜ŗ'=>'y','š™®'=>'y','šš¢'=>'y','Ę“'=>'yĢ”','z'=>'z','š³'=>'z','š‘§'=>'z','š’›'=>'z','š“'=>'z','š”ƒ'=>'z','š”·'=>'z','š•«'=>'z','š–Ÿ'=>'z','š—“'=>'z','š˜‡'=>'z','š˜»'=>'z','š™Æ'=>'z','šš£'=>'z','Č„'=>'zĢ”','ʐ'=>'zĢ¢','ʶ'=>'z̵','ȝ'=>'Ź’','?'=>'Ź”','?'=>'Ź”','⁇'=>'ʔʔ','⁈'=>'Ź”Ēƒ','į¾½'=>'ʼ','᾿'=>'ʼ','’'=>'ʼ','ʾ'=>'ʼ','!'=>'ǃ','!'=>'ǃ','⁉'=>'ĒƒŹ”','‼'=>'ǃǃ','āŗ'=>'α','š›‚'=>'α','š›¼'=>'α','šœ¶'=>'α','š°'=>'α','šžŖ'=>'α','š›ƒ'=>'β','š›½'=>'β','šœ·'=>'β','š±'=>'β','šž«'=>'β','ℽ'=>'γ','š›„'=>'γ','š›¾'=>'γ','šœø'=>'γ','š²'=>'γ','šž¬'=>'γ','š›…'=>'Ī“','š›æ'=>'Ī“','šœ¹'=>'Ī“','š³'=>'Ī“','šž­'=>'Ī“','šŸ‹'=>'Ļ','š›‡'=>'ζ','šœ'=>'ζ','šœ»'=>'ζ','šµ'=>'ζ','šžÆ'=>'ζ','ā¬'=>'Īø','š›‰'=>'Īø','š›'=>'Īø','šœƒ'=>'Īø','šœ—'=>'Īø','šœ½'=>'Īø','š‘'=>'Īø','š·'=>'Īø','šž‹'=>'Īø','šž±'=>'Īø','šŸ…'=>'Īø','š›Œ'=>'Ī»','šœ†'=>'Ī»','š€'=>'Ī»','šŗ'=>'Ī»','šž“'=>'Ī»','š›¬'=>'Ī›','šœ¦'=>'Ī›','š '=>'Ī›','šžš'=>'Ī›','š›'=>'μ','šœ‡'=>'μ','š'=>'μ','š»'=>'μ','šžµ'=>'μ','š›'=>'ξ','šœ‰'=>'ξ','šƒ'=>'ξ','š½'=>'ξ','šž·'=>'ξ','š›Æ'=>'Īž','šœ©'=>'Īž','š£'=>'Īž','šž'=>'Īž','ℼ'=>'Ļ€','š›‘'=>'Ļ€','š›”'=>'Ļ€','šœ‹'=>'Ļ€','šœ›'=>'Ļ€','š…'=>'Ļ€','š•'=>'Ļ€','šæ'=>'Ļ€','šž'=>'Ļ€','šž¹'=>'Ļ€','šŸ‰'=>'Ļ€','ᓨ'=>'Ļ€','āˆ'=>'Ī ','šš·'=>'Ī ','š›±'=>'Ī ','šœ«'=>'Ī ','š„'=>'Ī ','šžŸ'=>'Ī ','š›”'=>'σ','šœŽ'=>'σ','šˆ'=>'σ','šž‚'=>'σ','šž¼'=>'σ','š›•'=>'Ļ„','šœ'=>'Ļ„','š‰'=>'Ļ„','šžƒ'=>'Ļ„','šž½'=>'Ļ„','š˜'=>'Y','š‘Œ'=>'Y','š’€'=>'Y','š’“'=>'Y','š“Ø'=>'Y','š”œ'=>'Y','š•'=>'Y','š–„'=>'Y','š–ø'=>'Y','š—¬'=>'Y','š˜ '=>'Y','š™”'=>'Y','ššˆ'=>'Y','šš¼'=>'Y','š›¶'=>'Y','šœ°'=>'Y','šŖ'=>'Y','šž¤'=>'Y','š›—'=>'φ','š›Ÿ'=>'φ','šœ‘'=>'φ','šœ™'=>'φ','š‹'=>'φ','š“'=>'φ','šž…'=>'φ','šž'=>'φ','šžæ'=>'φ','šŸ‡'=>'φ','š›·'=>'Φ','šœ±'=>'Φ','š«'=>'Φ','šž„'=>'Φ','š›˜'=>'χ','šœ’'=>'χ','šŒ'=>'χ','šž†'=>'χ','šŸ€'=>'χ','š›™'=>'ψ','šœ“'=>'ψ','š'=>'ψ','šž‡'=>'ψ','šŸ'=>'ψ','š›¹'=>'ĪØ','šœ³'=>'ĪØ','š­'=>'ĪØ','šž§'=>'ĪØ','āµ'=>'ω','š›š'=>'ω','šœ”'=>'ω','šŽ'=>'ω','šžˆ'=>'ω','šŸ‚'=>'ω','ӕ'=>'ae','Ņ“'=>'r̵','Ņ‘'=>'rį‘Š','Ņ—'=>'ж̩','Ņ™'=>'Š·Ģ”','ӏ'=>'i','Ņ‹'=>'й̔','Ņ›'=>'ÄøĢ©','ҟ'=>'ĸ̵','į“«'=>'Š»','ӆ'=>'л̔','ӎ'=>'м̔','ӊ'=>'н̔','ӈ'=>'н̔','Ņ£'=>'н̩','Ó©'=>'o̵','ѳ'=>'o̵','Ņ«'=>'cĢ”','Ņ­'=>'т̩','ŅÆ'=>'y','ұ'=>'y̵','ћ'=>'h̵','ѽ'=>'є҃','ӌ'=>'Ņ·','Ņæ'=>'ҽ̢','Ņ'=>'Ь̵','Õ¦'=>'q','Õ¼'=>'n','ℵ'=>'א','ﬔ'=>'א','אָ'=>'אַ','אּ'=>'אַ','ļ­'=>'אל','ā„¶'=>'ב','ā„·'=>'ג','ℸ'=>'ד','ﬢ'=>'ד','ﬣ'=>'ה','ﬤ'=>'כ','ffl'=>'ל','ﬦ'=>'ם','ﬠ'=>'×¢','ﬧ'=>'ר','ﬨ'=>'×Ŗ','ļŗ€'=>'Ų”','ļŗ‚'=>'Ų¢','ﺁ'=>'Ų¢','ļŗ„'=>'Ų£','ﺃ'=>'Ų£','ٵ'=>'Ų§Ł”','ļ­‘'=>'ٱ','ﭐ'=>'ٱ','ļŗ†'=>'Ų¤','ļŗ…'=>'Ų¤','ٶ'=>'ŁˆŁ”','ﺈ'=>'Ų„','ļŗ‡'=>'Ų„','ļŗ‹'=>'Ų¦','ﺌ'=>'Ų¦','ﺊ'=>'Ų¦','ļŗ‰'=>'Ų¦','ﯫ'=>'Ų¦Ų§','ﯪ'=>'Ų¦Ų§','ﯸ'=>'ئٻ','ﯷ'=>'ئٻ','ﯶ'=>'ئٻ','ļ²—'=>'Ų¦Ų¬','ļ°€'=>'Ų¦Ų¬','ﲘ'=>'Ų¦Ų­','ﰁ'=>'Ų¦Ų­','ļ²™'=>'Ų¦Ų®','ﱤ'=>'Ų¦Ų±','ﱄ'=>'Ų¦Ų²','ﲚ'=>'ئم','ﳟ'=>'ئم','ﱦ'=>'ئم','ļ°‚'=>'ئم','ļ±§'=>'ئن','ļ²›'=>'ئه','ļ³ '=>'ئه','ﯭ'=>'ئه','ﯬ'=>'ئه','ﯯ'=>'ئو','ﯮ'=>'ئو','ﯳ'=>'Ų¦Ū†','ﯲ'=>'Ų¦Ū†','ﯱ'=>'Ų¦Ū‡','ﯰ'=>'Ų¦Ū‡','ﯵ'=>'ئۈ','ﯓ'=>'ئۈ','ﯻ'=>'ئى','ﯺ'=>'ئى','ﱨ'=>'ئى','ﯹ'=>'ئى','ﰃ'=>'ئى','ﱩ'=>'ئى','ļ°„'=>'ئى','ļŗŽ'=>'Ų§','ļŗ'=>'Ų§',''=>'Ų§Ł‹',''=>'Ų§Ł‹','ļ·³'=>'اكبر','ļ·²'=>'الله','ļŗ‘'=>'ŲØ','ļŗ’'=>'ŲØ','ﺐ'=>'ŲØ','ļŗ'=>'ŲØ','ﲜ'=>'ŲØŲ¬','ļ°…'=>'ŲØŲ¬','ļ²'=>'ŲØŲ­','ļ°†'=>'ŲØŲ­','ļ·‚'=>'بحى','ļ²ž'=>'ŲØŲ®','ļ°‡'=>'ŲØŲ®','ļ¶ž'=>'بخى','ļ±Ŗ'=>'ŲØŲ±','ﱫ'=>'ŲØŲ²','ﲟ'=>'ŲØŁ…','ļ³”'=>'ŲØŁ…','ﱬ'=>'ŲØŁ…','ﰈ'=>'ŲØŁ…','ļ±­'=>'بن','ļ² '=>'به','ļ³¢'=>'به','ļ±®'=>'بى','ļ°‰'=>'بى','ﱯ'=>'بى','ﰊ'=>'بى','ļ­”'=>'Ł»','ļ­•'=>'Ł»','ļ­“'=>'Ł»','ļ­’'=>'Ł»','ې'=>'Ł»','ﯦ'=>'Ł»','ﯧ'=>'Ł»','﯄'=>'Ł»','ﯤ'=>'Ł»','ﭘ'=>'پ','ļ­™'=>'پ','ļ­—'=>'پ','ļ­–'=>'پ','ﭜ'=>'Ś€','ļ­'=>'Ś€','ļ­›'=>'Ś€','ﭚ'=>'Ś€','ļŗ”'=>'Ų©','ļŗ“'=>'Ų©','ļŗ—'=>'ŲŖ','ﺘ'=>'ŲŖ','ļŗ–'=>'ŲŖ','ļŗ•'=>'ŲŖ','ļ²”'=>'ŲŖŲ¬','ļ°‹'=>'ŲŖŲ¬','ﵐ'=>'تجم','ļ¶ '=>'تجى','ﶟ'=>'تجى','ļ²¢'=>'ŲŖŲ­','ﰌ'=>'ŲŖŲ­','ļµ’'=>'ŲŖŲ­Ų¬','ﵑ'=>'ŲŖŲ­Ų¬','ﵓ'=>'ŲŖŲ­Ł…','ļ²£'=>'ŲŖŲ®','ļ°'=>'ŲŖŲ®','ļµ”'=>'تخم','ļ¶¢'=>'تخى','ļ¶”'=>'تخى','ļ±°'=>'ŲŖŲ±','ļ±±'=>'ŲŖŲ²','ﲤ'=>'ŲŖŁ…','ļ³£'=>'ŲŖŁ…','ļ±²'=>'ŲŖŁ…','ļ°Ž'=>'ŲŖŁ…','ﵕ'=>'ŲŖŁ…Ų¬','ļµ–'=>'ŲŖŁ…Ų­','ļµ—'=>'ŲŖŁ…Ų®','ﶤ'=>'تمى','ļ¶£'=>'تمى','ļ±³'=>'تن','ﲄ'=>'ته','ﳤ'=>'ته','ﱓ'=>'تى','ļ°'=>'تى','ļ±µ'=>'تى','ﰐ'=>'تى','ļŗ›'=>'Ų«','ﺜ'=>'Ų«','ﺚ'=>'Ų«','ļŗ™'=>'Ų«','ļ°‘'=>'Ų«Ų¬','ļ±¶'=>'Ų«Ų±','ļ±·'=>'Ų«Ų²','ﲦ'=>'Ų«Ł…','ﳄ'=>'Ų«Ł…','ļ±ø'=>'Ų«Ł…','ļ°’'=>'Ų«Ł…','ļ±¹'=>'ثن','ﳦ'=>'ثه','ļ±ŗ'=>'ثى','ļ°“'=>'ثى','ļ±»'=>'ثى','ļ°”'=>'ثى','ļ­Ø'=>'ٹ','ļ­©'=>'ٹ','ļ­§'=>'ٹ','ļ­¦'=>'ٹ','Ś»'=>'ٹ','ﮢ'=>'ٹ','ﮣ'=>'ٹ','ļ®”'=>'ٹ','ļ® '=>'ٹ','ļ­ '=>'Łŗ','ļ­”'=>'Łŗ','ﭟ'=>'Łŗ','ļ­ž'=>'Łŗ','ļ­¤'=>'Łæ','ļ­„'=>'Łæ','ļ­£'=>'Łæ','ļ­¢'=>'Łæ','ﺟ'=>'Ų¬','ļŗ '=>'Ų¬','ļŗž'=>'Ų¬','ļŗ'=>'Ų¬','ļ²§'=>'Ų¬Ų­','ļ°•'=>'Ų¬Ų­','ﶦ'=>'جحى','ļ¶¾'=>'جحى','ļ·»'=>'جل جلاله','ﲨ'=>'جم','ļ°–'=>'جم','ļµ™'=>'جمح','ﵘ'=>'جمح','ļ¶§'=>'جمى','ļ¶„'=>'جمى','ļ“'=>'جى',''=>'جى','ļ“ž'=>'جى','ļ“‚'=>'جى','ļ­ø'=>'ڃ','ļ­¹'=>'ڃ','ļ­·'=>'ڃ','ļ­¶'=>'ڃ','ļ­“'=>'Ś„','ļ­µ'=>'Ś„','ļ­³'=>'Ś„','ļ­²'=>'Ś„','ļ­¼'=>'چ','ļ­½'=>'چ','ļ­»'=>'چ','ļ­ŗ'=>'چ','ﮀ'=>'ڇ','ﮁ'=>'ڇ','ļ­æ'=>'ڇ','ļ­¾'=>'ڇ','ļŗ£'=>'Ų­','ļŗ¤'=>'Ų­','ļŗ¢'=>'Ų­','ļŗ”'=>'Ų­','ﲩ'=>'Ų­Ų¬','ļ°—'=>'Ų­Ų¬','ļ¶æ'=>'حجى','ļ²Ŗ'=>'Ų­Ł…','ﰘ'=>'Ų­Ł…','ļµ›'=>'حمى','ﵚ'=>'حمى','ļ“›'=>'حى','ﳿ'=>'حى',''=>'حى','ļ“€'=>'حى','ļŗ§'=>'Ų®','ļŗØ'=>'Ų®','ļŗ¦'=>'Ų®','ļŗ„'=>'Ų®','ﲫ'=>'Ų®Ų¬','ļ°™'=>'Ų®Ų¬','ﰚ'=>'Ų®Ų­','ﲬ'=>'خم','ļ°›'=>'خم',''=>'خى',''=>'خى','ļ“ '=>'خى','ļ“„'=>'خى','ļŗŖ'=>'ŲÆ','ļŗ©'=>'ŲÆ','ļŗ¬'=>'Ų°','ļŗ«'=>'Ų°','ļ±›'=>'ذٰ','ﮉ'=>'ڈ','ﮈ'=>'ڈ','ļ®…'=>'ڌ','ﮄ'=>'ڌ','ﮃ'=>'Ś','ﮂ'=>'Ś','ﮇ'=>'ŚŽ','ﮆ'=>'ŚŽ','ļŗ®'=>'Ų±','ļŗ­'=>'Ų±','ﱜ'=>'رٰ','ļ·¶'=>'Ų±Ų³ŁˆŁ„','ļ·¼'=>'رىال','ļŗ°'=>'Ų²','ļŗÆ'=>'Ų²','ļ®'=>'Ś‘','ﮌ'=>'Ś‘','ﮋ'=>'ژ','ﮊ'=>'ژ','ļŗ³'=>'Ų³','ļŗ“'=>'Ų³','ļŗ²'=>'Ų³','ļŗ±'=>'Ų³','ļ²­'=>'Ų³Ų¬','ļ““'=>'Ų³Ų¬','ﰜ'=>'Ų³Ų¬','ļµ'=>'Ų³Ų¬Ų­','ļµž'=>'سجى','ļ²®'=>'Ų³Ų­',''=>'Ų³Ų­','ļ°'=>'Ų³Ų­','ﵜ'=>'Ų³Ų­Ų¬','ﲯ'=>'Ų³Ų®','ļ“¶'=>'Ų³Ų®','ļ°ž'=>'Ų³Ų®','ļ¶Ø'=>'سخى','ļ·†'=>'سخى',''=>'Ų³Ų±','ļ“Ž'=>'Ų³Ų±','ļ²°'=>'سم','ļ³§'=>'سم','ﰟ'=>'سم','ļµ”'=>'سمج','ļµ '=>'سمح','ﵟ'=>'سمح','ļµ£'=>'سمم','ļµ¢'=>'سمم',''=>'سه','ﳨ'=>'سه','ļ“—'=>'سى','ļ³»'=>'سى',''=>'سى','ļ³¼'=>'سى','ļŗ·'=>'Ų“','ļŗø'=>'Ų“','ļŗ¶'=>'Ų“','ļŗµ'=>'Ų“','ļ“­'=>'Ų“Ų¬','ļ“·'=>'Ų“Ų¬','ļ“„'=>'Ų“Ų¬',''=>'Ų“Ų¬','ﵩ'=>'ؓجى','ļ“®'=>'Ų“Ų­',''=>'Ų“Ų­',''=>'Ų“Ų­',''=>'Ų“Ų­','ﵨ'=>'Ų“Ų­Ł…','ļµ§'=>'Ų“Ų­Ł…','ļ¶Ŗ'=>'ؓحى',''=>'Ų“Ų®',''=>'Ų“Ų®','ļ“§'=>'Ų“Ų®','ļ“‹'=>'Ų“Ų®','ļ“©'=>'Ų“Ų±','ļ“'=>'Ų“Ų±','ļ“°'=>'Ų“Ł…','ﳩ'=>'Ų“Ł…',''=>'Ų“Ł…',''=>'Ų“Ł…','ﵫ'=>'Ų“Ł…Ų®','ļµŖ'=>'Ų“Ł…Ų®','ļµ­'=>'Ų“Ł…Ł…','ﵬ'=>'Ų“Ł…Ł…',''=>'ؓه','ļ³Ŗ'=>'ؓه','ļ“™'=>'ؓى','ļ³½'=>'ؓى',''=>'ؓى','ļ³¾'=>'ؓى','ļŗ»'=>'Ųµ','ļŗ¼'=>'Ųµ','ļŗŗ'=>'Ųµ','ļŗ¹'=>'Ųµ','ļ²±'=>'ŲµŲ­','ļ° '=>'ŲµŲ­','﵄'=>'ŲµŲ­Ų­','ﵤ'=>'ŲµŲ­Ų­','ļ¶©'=>'صحى','ļ²²'=>'ŲµŲ®','ļ“«'=>'ŲµŲ±','ļ“'=>'ŲµŲ±','ļ·µ'=>'صلعم','ļ·¹'=>'صلى','ļ·ŗ'=>'صلى الله علىه ŁˆŲ³Ł„Ł…','ļ·°'=>'صلے','ļ²³'=>'صم','ļ°”'=>'صم','ļ·…'=>'صمم','ﵦ'=>'صمم','ļ“”'=>'صى','ļ“…'=>'صى','ļ“¢'=>'صى',''=>'صى','ļŗæ'=>'Ų¶','ﻀ'=>'Ų¶','ļŗ¾'=>'Ų¶','ļŗ½'=>'Ų¶','ﲓ'=>'Ų¶Ų¬','ļ°¢'=>'Ų¶Ų¬','ļ²µ'=>'Ų¶Ų­','ļ°£'=>'Ų¶Ų­','ļµ®'=>'ضحى','ļ¶«'=>'ضحى','ļ²¶'=>'Ų¶Ų®','ļ°¤'=>'Ų¶Ų®','ļµ°'=>'ضخم','ﵯ'=>'ضخم',''=>'Ų¶Ų±',''=>'Ų¶Ų±','ļ²·'=>'Ų¶Ł…','ļ°„'=>'Ų¶Ł…','ļ“£'=>'ضى',''=>'ضى',''=>'ضى',''=>'ضى','ﻃ'=>'Ų·','ﻄ'=>'Ų·','ﻂ'=>'Ų·','ﻁ'=>'Ų·','ļ²ø'=>'Ų·Ų­','ļ°¦'=>'Ų·Ų­',''=>'Ų·Ł…',''=>'Ų·Ł…','ļ°§'=>'Ų·Ł…','ļµ²'=>'Ų·Ł…Ų­','ļµ±'=>'Ų·Ł…Ų­','ļµ³'=>'Ų·Ł…Ł…','ﵓ'=>'طمى','ļ“‘'=>'طى','ļ³µ'=>'طى','ļ“’'=>'طى','ļ³¶'=>'طى','ﻇ'=>'Ųø','ﻈ'=>'Ųø','ﻆ'=>'Ųø','ļ»…'=>'Ųø','ļ²¹'=>'ŲøŁ…','ļ“»'=>'ŲøŁ…','ļ°Ø'=>'ŲøŁ…','ﻋ'=>'Ų¹','ﻌ'=>'Ų¹','ﻊ'=>'Ų¹','ﻉ'=>'Ų¹','ļ²ŗ'=>'Ų¹Ų¬','ļ°©'=>'Ų¹Ų¬','ļ·„'=>'عجم','ļµµ'=>'عجم','ļ··'=>'علىه','ļ²»'=>'عم','ļ°Ŗ'=>'عم','ļµ·'=>'عمم','ļµ¶'=>'عمم','ļµø'=>'عمى','ļ¶¶'=>'عمى','ļ““'=>'عى','ļ³·'=>'عى','ļ“”'=>'عى','ļ³ø'=>'عى','ļ»'=>'Ųŗ','ﻐ'=>'Ųŗ','ļ»Ž'=>'Ųŗ','ļ»'=>'Ųŗ','ļ²¼'=>'ŲŗŲ¬','ļ°«'=>'ŲŗŲ¬','ļ²½'=>'ŲŗŁ…','ļ°¬'=>'ŲŗŁ…','ļµ¹'=>'ŲŗŁ…Ł…','ļµ»'=>'غمى','ļµŗ'=>'غمى','ļ“•'=>'غى','ļ³¹'=>'غى','ļ“–'=>'غى','ļ³ŗ'=>'غى','ﻓ'=>'ف','ļ»”'=>'ف','ļ»’'=>'ف','ﻑ'=>'ف','ļ²¾'=>'فج','ļ°­'=>'فج','ﲿ'=>'فح','ļ°®'=>'فح','ļ³€'=>'فخ','ļ°Æ'=>'فخ','ļµ½'=>'فخم','ļµ¼'=>'فخم','ﳁ'=>'فم','ļ°°'=>'فم','ﷁ'=>'فمى','ļ±¼'=>'فى','ļ°±'=>'فى','ļ±½'=>'فى','ļ°²'=>'فى','ļ­¬'=>'ڤ','ļ­­'=>'ڤ','ļ­«'=>'ڤ','ļ­Ŗ'=>'ڤ','ļ­°'=>'ڦ','ļ­±'=>'ڦ','ļ­Æ'=>'ڦ','ļ­®'=>'ڦ','ļ»—'=>'Ł‚','ﻘ'=>'Ł‚','ļ»–'=>'Ł‚','ﻕ'=>'Ł‚','ﳂ'=>'قح','ļ°³'=>'قح','ļ·±'=>'قلے','ﳃ'=>'قم','ļ°“'=>'قم','ļ¶“'=>'قمح','ļµ¾'=>'قمح','ﵿ'=>'قمم','ļ¶²'=>'قمى','ļ±¾'=>'قى','ļ°µ'=>'قى','ﱿ'=>'قى','ļ°¶'=>'قى','ļ»›'=>'ك','ﻜ'=>'ك','ﻚ'=>'ك','ļ»™'=>'ك','Ś©'=>'ك','ﮐ'=>'ك','ﮑ'=>'ك','ļ®'=>'ك','ļ®Ž'=>'ك','ļ²€'=>'كا','ļ°·'=>'كا','ﳄ'=>'كج','ļ°ø'=>'كج','ļ³…'=>'كح','ļ°¹'=>'كح','ﳆ'=>'كخ','ļ°ŗ'=>'كخ','ﳇ'=>'ŁƒŁ„','ﳫ'=>'ŁƒŁ„','ﲁ'=>'ŁƒŁ„','ļ°»'=>'ŁƒŁ„','ﳈ'=>'ŁƒŁ…','ﳬ'=>'ŁƒŁ…','ﲂ'=>'ŁƒŁ…','ļ°¼'=>'ŁƒŁ…','ﷃ'=>'ŁƒŁ…Ł…','ļ¶»'=>'ŁƒŁ…Ł…','ļ¶·'=>'ŁƒŁ…Ł‰','ﲃ'=>'ŁƒŁ‰','ļ°½'=>'ŁƒŁ‰','ﲄ'=>'ŁƒŁ‰','ļ°¾'=>'ŁƒŁ‰','ﯕ'=>'Ś­','ﯖ'=>'Ś­','ﯔ'=>'Ś­','ﯓ'=>'Ś­','ļ®”'=>'ŚÆ','ﮕ'=>'ŚÆ','ﮓ'=>'ŚÆ','ļ®’'=>'ŚÆ','ﮜ'=>'ڱ','ļ®'=>'ڱ','ļ®›'=>'ڱ','ﮚ'=>'ڱ','ﮘ'=>'ڳ','ļ®™'=>'ڳ','ļ®—'=>'ڳ','ļ®–'=>'ڳ','ﻟ'=>'Ł„','ļ» '=>'Ł„','ļ»ž'=>'Ł„','ļ»'=>'Ł„','ļ»¶'=>'لآ','ﻵ'=>'لآ','ﻸ'=>'لأ','ļ»·'=>'لأ','ﻺ'=>'ل؄','ﻹ'=>'ل؄','ﻼ'=>'لا','ļ»»'=>'لا','ﳉ'=>'لج','ļ°æ'=>'لج','ﶃ'=>'لجج','ļ¶„'=>'لجج','ļ¶ŗ'=>'لجم','ļ¶¼'=>'لجم','ﶬ'=>'لجى','ﳊ'=>'لح','ļ±€'=>'لح','ļ¶µ'=>'لحم','ļ¶€'=>'لحم','ļ¶‚'=>'لحى','ﶁ'=>'لحى','ﳋ'=>'لخ','ﱁ'=>'لخ','ﶆ'=>'لخم','ļ¶…'=>'لخم','ﳌ'=>'لم','ļ³­'=>'لم','ļ²…'=>'لم','ﱂ'=>'لم','ﶈ'=>'لمح','ﶇ'=>'لمح','ļ¶­'=>'لمى','ļ³'=>'له','ﲆ'=>'لى','ﱃ'=>'لى','ﲇ'=>'لى','ﱄ'=>'لى','ﻣ'=>'Ł…','ﻤ'=>'Ł…','ﻢ'=>'Ł…','ļ»”'=>'Ł…','ﲈ'=>'Ł…Ų§','ļ³Ž'=>'Ł…Ų¬','ļ±…'=>'Ł…Ų¬','ﶌ'=>'Ł…Ų¬Ų­','ļ¶’'=>'Ł…Ų¬Ų®','ļ¶'=>'مجم','ļ·€'=>'مجى','ļ³'=>'Ł…Ų­','ﱆ'=>'Ł…Ų­','ﶉ'=>'Ł…Ų­Ų¬','ﶊ'=>'Ł…Ų­Ł…','ļ·“'=>'Ł…Ų­Ł…ŲÆ','ļ¶‹'=>'محى','ﳐ'=>'Ł…Ų®','ﱇ'=>'Ł…Ų®','ļ¶Ž'=>'Ł…Ų®Ų¬','ļ¶'=>'مخم','ļ¶¹'=>'مخى','ﳑ'=>'Ł…Ł…','ﲉ'=>'Ł…Ł…','ﱈ'=>'Ł…Ł…','ļ¶±'=>'ممى','ﱉ'=>'مى','ﱊ'=>'مى','ļ»§'=>'ن','ﻨ'=>'ن','ﻦ'=>'ن','ﻄ'=>'ن','ļ³’'=>'نج','ﱋ'=>'نج','ļ¶ø'=>'نجح','ļ¶½'=>'نجح','ﶘ'=>'نجم','ļ¶—'=>'نجم','ļ¶™'=>'نجى','ļ·‡'=>'نجى','ﳓ'=>'نح','ﱌ'=>'نح','ļ¶•'=>'نحم','ļ¶–'=>'نحى','ļ¶³'=>'نحى','ļ³”'=>'نخ','ļ±'=>'نخ','ﲊ'=>'نر','ﲋ'=>'نز','ﳕ'=>'نم','ļ³®'=>'نم','ﲌ'=>'نم','ļ±Ž'=>'نم','ļ¶›'=>'نمى','ﶚ'=>'نمى','ļ²'=>'نن','ļ³–'=>'نه','ﳯ'=>'نه','ļ²Ž'=>'نى','ļ±'=>'نى','ļ²'=>'نى','ﱐ'=>'نى','ﮟ'=>'Śŗ','ļ®ž'=>'Śŗ','ﻫ'=>'ه','ﻬ'=>'ه','ﻪ'=>'ه','ﻩ'=>'ه','ھ'=>'ه','ﮬ'=>'ه','ļ®­'=>'ه','ﮫ'=>'ه','ﮪ'=>'ه','ہ'=>'ه','ﮨ'=>'ه','ﮩ'=>'ه','ļ®§'=>'ه','ﮦ'=>'ه','Ū•'=>'ه','ļ³™'=>'هٰ','ļ³—'=>'هج','ﱑ'=>'هج','ﳘ'=>'هم','ļ±’'=>'هم','ļ¶“'=>'همج','ļ¶”'=>'همم','ﱓ'=>'هى','ļ±”'=>'هى','ﮄ'=>'Ū€','ﮤ'=>'Ū€','ļ»®'=>'و','ļ»­'=>'و','ļ·ø'=>'ŁˆŲ³Ł„Ł…','ﯔ'=>'Ū…','ﯠ'=>'Ū…','ﯚ'=>'Ū†','ﯙ'=>'Ū†','ﯘ'=>'Ū‡','ﯗ'=>'Ū‡','Ł·'=>'ۇٔ','ļÆ'=>'ۇٔ','ﯜ'=>'ۈ','ﯛ'=>'ۈ','ﯣ'=>'Ū‰','ﯢ'=>'Ū‰','ﯟ'=>'Ū‹','ļÆž'=>'Ū‹','ﯨ'=>'ى','ﯩ'=>'ى','ļ»°'=>'ى','ﻯ'=>'ى','ي'=>'ى','ﻳ'=>'ى','ﻓ'=>'ى','ﻲ'=>'ى','ļ»±'=>'ى','ی'=>'ى','ﯾ'=>'ى','ﯿ'=>'ى','ﯽ'=>'ى','ﯼ'=>'ى','Łø'=>'ىٔ','ﲐ'=>'ىٰ','ļ±'=>'ىٰ','ﳚ'=>'ىج','ﱕ'=>'ىج','ļ¶Æ'=>'ىجى','ļ³›'=>'ىح','ļ±–'=>'ىح','ļ¶®'=>'ىحى','ﳜ'=>'ىخ','ļ±—'=>'ىخ','ﲑ'=>'ىر','ļ²’'=>'ىز','ļ³'=>'ىم','ļ³°'=>'ىم','ﲓ'=>'ىم','ﱘ'=>'ىم','ļ¶'=>'ىمم','ﶜ'=>'ىمم','ļ¶°'=>'ىمى','ļ²”'=>'ىن','ļ³ž'=>'ىه','ļ³±'=>'ىه','ﲕ'=>'ىى','ļ±™'=>'ىى','ļ²–'=>'ىى','ﱚ'=>'ىى','Ū§'=>'Ū¦','ﮯ'=>'Ū’','ļ®®'=>'Ū’','ļ®±'=>'Ū“','ļ®°'=>'Ū“','∃'=>'⓺','आ'=>'अा','ऒ'=>'ą¤…ą¤¾ą„†','ओ'=>'ą¤…ą¤¾ą„‡','औ'=>'ą¤…ą¤¾ą„ˆ','ऄ'=>'ą¤…ą„†','ऑ'=>'ą¤…ą„‰','ą¤'=>'ą¤ą„…','ą¤Ž'=>'ą¤ą„†','ऐ'=>'ą¤ą„‡','ई'=>'ą¤°ą„ą¤‡','আ'=>'অা','ą§ '=>'ą¦‹ą§ƒ','ą§”'=>'ঌৢ','ਉ'=>'ੳੁ','ਊ'=>'ੳੂ','ਆ'=>'ਅਾ','ਐ'=>'ąØ…ą©ˆ','ਔ'=>'ąØ…ą©Œ','ਇ'=>'ੲਿ','ਈ'=>'ੲੀ','ąØ'=>'ੲੇ','ąŖ†'=>'ąŖ…ąŖ¾','ąŖ‘'=>'અાૅ','ąŖ“'=>'અાે','ąŖ”'=>'ąŖ…ąŖ¾ą«ˆ','ąŖ'=>'ąŖ…ą«…','ąŖ'=>'અે','ઐ'=>'ąŖ…ą«ˆ','ଆ'=>'ଅା','௮'=>'ą®…','ą®°'=>'ஈ','ா'=>'ஈ','௫'=>'ஈு','௨'=>'உ','ஊ'=>'உள','௭'=>'ą®Ž','௷'=>'ą®Žą®µ','ஜ'=>'ஐ','௧'=>'க','௪'=>'ச','௬'=>'சு','௲'=>'ą®šąÆ‚','௺'=>'நீ','ை'=>'ன','௓'=>'மீ','௰'=>'ய','ௗ'=>'ள','௸'=>'ą®·','ொ'=>'ąÆ†ą®ˆ','ௌ'=>'ெள','ோ'=>'ąÆ‡ą®ˆ','ą± '=>'ą°‹ą°¾','ą±”'=>'ఌా','ą°”'=>'ą°’ą±Œ','ą°“'=>'ఒౕ','ą°¢'=>'ఔ̣','ą°­'=>'బ̣','ą°·'=>'వ̣','ą°¹'=>'వా','ą°®'=>'వు','ూ'=>'ుా','ౄ'=>'ృా','ą³”'=>'ಌಾ','ą²”'=>'ą°’ą±Œ','ą“ˆ'=>'ą“‡ąµ—','ą“Š'=>'உൗ','ą“'=>'ą“Žąµ†','ą““'=>'ą“’ą“¾','ą“”'=>'ą“’ąµ—','ąµ”'=>'ą“ž','൫'=>'ą“¦ąµą“°','ą“Œ'=>'ą“ØąÆ‚','ą“™'=>'ą“ØąÆ‚','൯'=>'ą“Øąµ','ą“±'=>'ą“°','ąµŖ'=>'ą“°ąµ','ąµ®'=>'ą“µąµ','ąµ€'=>'ி','ൂ'=>'ூ','ൃ'=>'ூ','ൈ'=>'െെ','ฃ'=>'ąø‚','ąø”'=>'ąø„','ąø•'=>'ąø„','ąø”'=>'ąø†','ąø‹'=>'ช','ąø'=>'ąøŽ','ąø—'=>'ąø‘','ą¹…'=>'ąø²','ąø³'=>'̊า','แ'=>'เเ','ໜ'=>'ąŗ«ąŗ™','ą»'=>'ąŗ«ąŗ”','ąŗ³'=>'̊າ','ą½·'=>'ྲཱྀ','ą½¹'=>'ླཱྀ','၀'=>'o','įž£'=>'įž¢','᧐'=>'į¦ž','į­’'=>'į¬','į­“'=>'ᬑ','᭘'=>'ᬨ','ᢖ'=>'ᔜ','ᔕ'=>'į µ','į’'=>'įŽ”','įŽ½'=>'y','š€'=>'A','š“'=>'A','š‘Ø'=>'A','š’œ'=>'A','š“'=>'A','š”„'=>'A','š”ø'=>'A','š•¬'=>'A','š– '=>'A','š—”'=>'A','š˜ˆ'=>'A','š˜¼'=>'A','š™°'=>'A','ššØ'=>'A','š›¢'=>'A','šœœ'=>'A','š–'=>'A','šž'=>'A','š‰'=>'J','š½'=>'J','š‘±'=>'J','š’„'=>'J','š“™'=>'J','š”'=>'J','š•'=>'J','š•µ'=>'J','š–©'=>'J','š—'=>'J','š˜‘'=>'J','š™…'=>'J','š™¹'=>'J','į§'=>'J','⋿'=>'E','ā„°'=>'E','š„'=>'E','šø'=>'E','š‘¬'=>'E','š“”'=>'E','š”ˆ'=>'E','š”¼'=>'E','š•°'=>'E','š–¤'=>'E','š—˜'=>'E','š˜Œ'=>'E','š™€'=>'E','š™“'=>'E','šš¬'=>'E','š›¦'=>'E','šœ '=>'E','šš'=>'E','šž”'=>'E','ℾ'=>'įŽ±','ššŖ'=>'įŽ±','š›¤'=>'įŽ±','šœž'=>'įŽ±','š˜'=>'įŽ±','šž’'=>'įŽ±','į”'=>'w','ℳ'=>'M','šŒ'=>'M','š‘€'=>'M','š‘“'=>'M','š“œ'=>'M','š”'=>'M','š•„'=>'M','š•ø'=>'M','š–¬'=>'M','š— '=>'M','š˜”'=>'M','š™ˆ'=>'M','š™¼'=>'M','šš³'=>'M','š›­'=>'M','šœ§'=>'M','š”'=>'M','šž›'=>'M','ā„‹'=>'H','ā„Œ'=>'H','ā„'=>'H','š‡'=>'H','š»'=>'H','š‘Æ'=>'H','š“—'=>'H','š•³'=>'H','š–§'=>'H','š—›'=>'H','š˜'=>'H','š™ƒ'=>'H','š™·'=>'H','šš®'=>'H','š›Ø'=>'H','šœ¢'=>'H','šœ'=>'H','šž–'=>'H','š†'=>'G','šŗ'=>'G','š‘®'=>'G','š’¢'=>'G','š“–'=>'G','š”Š'=>'G','š”¾'=>'G','š•²'=>'G','š–¦'=>'G','š—š'=>'G','š˜Ž'=>'G','š™‚'=>'G','š™¶'=>'G','į³'=>'G','ℤ'=>'Z','ℨ'=>'Z','š™'=>'Z','š‘'=>'Z','š’'=>'Z','š’µ'=>'Z','š“©'=>'Z','š–…'=>'Z','š–¹'=>'Z','š—­'=>'Z','š˜”'=>'Z','š™•'=>'Z','šš‰'=>'Z','šš­'=>'Z','š›§'=>'Z','šœ”'=>'Z','š›'=>'Z','šž•'=>'Z','š’'=>'S','š‘†'=>'S','š‘ŗ'=>'S','š’®'=>'S','š“¢'=>'S','š”–'=>'S','š•Š'=>'S','š•¾'=>'S','š–²'=>'S','š—¦'=>'S','š˜š'=>'S','š™Ž'=>'S','šš‚'=>'S','įš'=>'S','š•'=>'V','š‘‰'=>'V','š‘½'=>'V','š’±'=>'V','š“„'=>'V','š”™'=>'V','š•'=>'V','š–'=>'V','š–µ'=>'V','š—©'=>'V','š˜'=>'V','š™‘'=>'V','šš…'=>'V','ā„’'=>'L','š‹'=>'L','šæ'=>'L','š‘³'=>'L','š“›'=>'L','š”'=>'L','š•ƒ'=>'L','š•·'=>'L','š–«'=>'L','š—Ÿ'=>'L','š˜“'=>'L','š™‡'=>'L','š™»'=>'L','āˆ‘'=>'C','ā…€'=>'C','ā„‚'=>'C','ā„­'=>'C','š‚'=>'C','š¶'=>'C','š‘Ŗ'=>'C','š’ž'=>'C','š“’'=>'C','š•®'=>'C','š–¢'=>'C','š—–'=>'C','š˜Š'=>'C','š˜¾'=>'C','š™²'=>'C','ššŗ'=>'C','š›“'=>'C','šœ®'=>'C','šØ'=>'C','šž¢'=>'C','ā„™'=>'P','š'=>'P','š‘ƒ'=>'P','š‘·'=>'P','š’«'=>'P','š“Ÿ'=>'P','š”“'=>'P','š•»'=>'P','š–Æ'=>'P','š—£'=>'P','š˜—'=>'P','š™‹'=>'P','š™æ'=>'P','ššø'=>'P','š›²'=>'P','šœ¬'=>'P','š¦'=>'P','šž '=>'P','šŠ'=>'K','š¾'=>'K','š‘²'=>'K','š’¦'=>'K','š“š'=>'K','š”Ž'=>'K','š•‚'=>'K','š•¶'=>'K','š–Ŗ'=>'K','š—ž'=>'K','š˜’'=>'K','š™†'=>'K','š™ŗ'=>'K','šš±'=>'K','š›«'=>'K','šœ„'=>'K','šŸ'=>'K','šž™'=>'K','ℬ'=>'B','š'=>'B','šµ'=>'B','š‘©'=>'B','š“‘'=>'B','š”…'=>'B','š”¹'=>'B','š•­'=>'B','š–”'=>'B','š—•'=>'B','š˜‰'=>'B','š˜½'=>'B','š™±'=>'B','šš©'=>'B','š›£'=>'B','šœ'=>'B','š—'=>'B','šž‘'=>'B','į'=>'ᐁ·','āˆ†'=>'ᐃ','šš«'=>'ᐃ','š›„'=>'ᐃ','šœŸ'=>'ᐃ','š™'=>'ᐃ','šž“'=>'ᐃ','į'=>'ᐃ·','ᐑ'=>'ᐄ·','ᐓ'=>'ᐅ·','ᐕ'=>'ᐆ·','ᐘ'=>'ᐊ·','ᐚ'=>'ᐋ·','į“‘'=>'ᐔ','į‘¶'=>'Ā·P','ᑺ'=>'Ā·d','į’˜'=>'Ā·J','ᑁ'=>'ᐳ·','į‘ƒ'=>'ᐓ·','į‘…'=>'ᐸ·','ᑇ'=>'ᐹ·','ˈ'=>'į‘Š','į‘˜'=>'į‘ŒĀ·','į‘§'=>'į‘Œį‘Š','į‘š'=>'į‘ŽĀ·','ᑨ'=>'į‘Žį‘Š','į‘œ'=>'į‘Ā·','į‘ž'=>'ᑐ·','į‘©'=>'į‘į‘Š','į‘ '=>'į‘‘Ā·','į‘¢'=>'į‘•Ā·','ᑪ'=>'į‘•į‘Š','ᑤ'=>'į‘–Ā·','ᑵ'=>'į‘«Ā·','į’…'=>'į‘«į‘Š','į‘·'=>'PĀ·','į’†'=>'Pį‘Š','ᑹ'=>'ᑮ·','į‘»'=>'dĀ·','į’‡'=>'dį‘Š','ᑽ'=>'į‘°Ā·','ᑿ'=>'ᑲ·','į’ˆ'=>'į‘²į‘Š','ᒁ'=>'ᑳ·','ᘃ'=>'į’‰','į’“'=>'ᒉ·','į’•'=>'į’‹Ā·','į’—'=>'į’ŒĀ·','į’™'=>'JĀ·','į’›'=>'į’ŽĀ·','į˜‚'=>'ᒐ','į’'=>'ᒐ·','į’Ÿ'=>'į’‘Ā·','į’­'=>'ᒣ·','į’Æ'=>'į’„Ā·','į’±'=>'ᒦ·','į’³'=>'į’§Ā·','į’µ'=>'į’ØĀ·','į’¹'=>'į’«Ā·','į“Š'=>'ᓀ·','į“Œ'=>'ᓇ·','į“Ž'=>'į“ˆį’«','į˜„'=>'į““','į“'=>'į““Ā·','į“Ÿ'=>'į“•Ā·','į“”'=>'į“–Ā·','į“£'=>'į“—Ā·','į“„'=>'į“˜Ā·','į˜‡'=>'į“š','į“§'=>'į“šĀ·','į“©'=>'ᓛ·','į“·'=>'į“­Ā·','ᓹ'=>'ᓯ·','į“»'=>'į“°Ā·','ᓽ'=>'ᓱ·','ᓿ'=>'ᓲ·','ᔁ'=>'į““Ā·','į”ƒ'=>'ᓵ·','į”Œ'=>'ᔋᐸ','į”'=>'ᔋᑕ','į”Ž'=>'ᔋᑲ','į”'=>'ᔋᒐ','į”˜'=>'ᔐ·','į”š'=>'ᔑ·','į”œ'=>'į”’Ā·','į”ž'=>'ᔓ·','į” '=>'ᔔ·','ᔢ'=>'ᔕ·','ᔤ'=>'į”–Ā·','ᔲ'=>'ᔨ·','ᔓ'=>'ᔩ·','į”¶'=>'ᔪ·','ᔸ'=>'ᔫ·','ᔺ'=>'į”­Ā·','ᔼ'=>'ᔮ·','į™®'=>'x','ᕽ'=>'x','ᘢ'=>'į•ƒ','ᘣ'=>'ᕆ','ᘤ'=>'į•Š','į•'=>'į•ŒĀ·','ᙯ'=>'ᕐᑫ','ᕾ'=>'ᕐᑬ','ᕿ'=>'ᕐP','į–€'=>'ᕐᑮ','ᖁ'=>'ᕐd','į–‚'=>'ᕐᑰ','į–ƒ'=>'ᕐᑲ','į–„'=>'ᕐᑳ','į–…'=>'į•į’ƒ','į•œ'=>'į•šĀ·','į•©'=>'į•§Ā·','ā„›'=>'R','ā„œ'=>'R','ā„'=>'R','š‘'=>'R','š‘…'=>'R','š‘¹'=>'R','š“”'=>'R','š•½'=>'R','š–±'=>'R','š—„'=>'R','š˜™'=>'R','š™'=>'R','šš'=>'R','į™°'=>'į–•į’‰','į–Ž'=>'į–•į’Š','į–'=>'į–•į’‹','ᖐ'=>'į–•į’Œ','į–‘'=>'į–•J','į–’'=>'į–•į’Ž','į–“'=>'ᖕᒐ','į–”'=>'į–•į’‘','į™±'=>'į––į’‹','ᙲ'=>'į––į’Œ','ᙳ'=>'į––J','ᙓ'=>'į––į’Ž','ᙵ'=>'ᖖᒐ','į™¶'=>'į––į’‘','ℱ'=>'F','š…'=>'F','š¹'=>'F','š‘­'=>'F','š“•'=>'F','š”‰'=>'F','š”½'=>'F','š•±'=>'F','š–„'=>'F','š—™'=>'F','š˜'=>'F','š™'=>'F','š™µ'=>'F','šŸŠ'=>'F','ā……'=>'D','šƒ'=>'D','š·'=>'D','š‘«'=>'D','š’Ÿ'=>'D','š““'=>'D','š”‡'=>'D','š”»'=>'D','š•Æ'=>'D','š–£'=>'D','š——'=>'D','š˜‹'=>'D','š˜æ'=>'D','š™³'=>'D','į—Ŗ'=>'D','ā„§'=>'ᘮ','ᘓ'=>'ᘮ','š›€'=>'ᘯ','š›ŗ'=>'ᘯ','šœ“'=>'ᘯ','š®'=>'ᘯ','šžØ'=>'ᘯ','ᘵ'=>'ᘯ','愱'=>'į„€','ļ¾”'=>'į„€','ᆨ'=>'į„€','ㄲ'=>'ᄁ','ļ¾¢'=>'ᄁ','ᆩ'=>'ᄁ','ć„“'=>'į„‚','ᄂ'=>'į„‚','ᆫ'=>'į„‚','ć„·'=>'į„ƒ','ļ¾§'=>'į„ƒ','ᆮ'=>'į„ƒ','ㄸ'=>'į„„','ᄄ'=>'į„„','ㄹ'=>'į„…','ᄅ'=>'į„…','ᆯ'=>'į„…','慁'=>'ᄆ','ļ¾±'=>'ᄆ','ᆷ'=>'ᄆ','慂'=>'ᄇ','ļ¾²'=>'ᄇ','ᆸ'=>'ᄇ','慃'=>'į„ˆ','ļ¾³'=>'į„ˆ','慅'=>'ᄉ','ļ¾µ'=>'ᄉ','ᆺ'=>'ᄉ','慆'=>'į„Š','ļ¾¶'=>'į„Š','ᆻ'=>'į„Š','慇'=>'į„‹','ļ¾·'=>'į„‹','ᆼ'=>'į„‹','慈'=>'į„Œ','ļ¾ø'=>'į„Œ','ᆽ'=>'į„Œ','慉'=>'į„','ļ¾¹'=>'į„','慊'=>'į„Ž','ļ¾ŗ'=>'į„Ž','ᆾ'=>'į„Ž','態'=>'į„','ļ¾»'=>'į„','ᆿ'=>'į„','慌'=>'ᄐ','ļ¾¼'=>'ᄐ','ᇀ'=>'ᄐ','慍'=>'į„‘','ļ¾½'=>'į„‘','ᇁ'=>'į„‘','慎'=>'į„’','ļ¾¾'=>'į„’','ᇂ'=>'į„’','ᇅ'=>'į„“','ć…„'=>'į„”','ć…¦'=>'į„•','ᇆ'=>'į„•','į‡Š'=>'į„—','į‡'=>'į„˜','ᇐ'=>'į„™','慀'=>'į„š','ļ¾°'=>'į„š','į„»'=>'į„š','ᆶ'=>'į„š','ć…®'=>'į„œ','į‡œ'=>'į„œ','ć…±'=>'į„','ᇢ'=>'į„','ć…²'=>'į„ž','ć…³'=>'į„ ','慄'=>'į„”','モ'=>'į„”','ᆹ'=>'į„”','ć…“'=>'į„¢','ć…µ'=>'į„£','ć…¶'=>'į„§','ć…·'=>'į„©','ć…ø'=>'į„«','ᇦ'=>'į„«','ć…¹'=>'ᄬ','ć…ŗ'=>'į„­','ᇧ'=>'į„­','ć…»'=>'į„®','ć…¼'=>'ᄯ','ᇨ'=>'ᄯ','ᇩ'=>'į„°','ć…½'=>'ᄲ','ᇪ'=>'ᄲ','ć…¾'=>'į„¶','ć…æ'=>'į…€','ᇫ'=>'į…€','ᇬ'=>'ᅁ','ᇱ'=>'į……','憂'=>'į……','ᇲ'=>'į…†','憃'=>'į…†','憀'=>'į…‡','ᇮ'=>'į…‡','憁'=>'į…Œ','ᇰ'=>'į…Œ','ᇳ'=>'į…–','憄'=>'į…—','ᇓ'=>'į…—','憅'=>'į…˜','憆'=>'į…™','ᇹ'=>'į…™','慤'=>'į… ','ļ¾ '=>'į… ','慏'=>'į…”','ļæ‚'=>'į…”','慐'=>'į…¢','ᅢ'=>'į…¢','慑'=>'į…£','ļæ„'=>'į…£','慒'=>'į…¤','ļæ…'=>'į…¤','慓'=>'į…„','ᅥ'=>'į…„','慔'=>'į…¦','ᅦ'=>'į…¦','慕'=>'į…§','ᅧ'=>'į…§','慖'=>'į…Ø','ļæ‹'=>'į…Ø','慗'=>'į…©','ᅩ'=>'į…©','慘'=>'į…Ŗ','ļæ'=>'į…Ŗ','慙'=>'į…«','ļæŽ'=>'į…«','慚'=>'į…¬','ļæ'=>'į…¬','慛'=>'į…­','ļæ’'=>'į…­','慜'=>'į…®','ļæ“'=>'į…®','慝'=>'į…Æ','ļæ”'=>'į…Æ','慞'=>'į…°','ļæ•'=>'į…°','慟'=>'į…±','ļæ–'=>'į…±','慠'=>'į…²','ļæ—'=>'į…²','ć…”'=>'äø€','ᅳ'=>'äø€','ć…¢'=>'į…“','ļæ›'=>'į…“','ć…£'=>'äøØ','ᅵ'=>'äøØ','憇'=>'ᆄ','ᆆ'=>'ᆄ','憈'=>'ᆅ','憉'=>'į†ˆ','憊'=>'ᆑ','憋'=>'ᆒ','憌'=>'ᆔ','憍'=>'į†ž','憎'=>'ᆔ','ㄳ'=>'ᆪ','ļ¾£'=>'ᆪ','愵'=>'ᆬ','ト'=>'ᆬ','ć„¶'=>'ᆭ','ᆭ'=>'ᆭ','ㄺ'=>'ᆰ','ļ¾Ŗ'=>'ᆰ','ć„»'=>'ᆱ','ᆱ'=>'ᆱ','ㄼ'=>'ᆲ','ᆲ'=>'ᆲ','ㄽ'=>'ᆳ','ļ¾­'=>'ᆳ','ㄾ'=>'ᆓ','ļ¾®'=>'ᆓ','ㄿ'=>'ᆵ','ᆵ'=>'ᆵ','慧'=>'ᇇ','ć…Ø'=>'į‡ˆ','ć…©'=>'į‡Œ','ć…Ŗ'=>'į‡Ž','ć…«'=>'ᇓ','ć…¬'=>'ᇗ','慭'=>'ᇙ','ć…Æ'=>'į‡','慰'=>'į‡Ÿ','ļ½§'=>'ć‚”','ļ½±'=>'ć‚¢','ィ'=>'ć‚£','ļ½²'=>'悤','ゥ'=>'ć‚„','ļ½³'=>'悦','ļ½Ŗ'=>'悧','s'=>'エ','ォ'=>'ć‚©','ļ½µ'=>'オ','ļ½¶'=>'ć‚«','ļ½·'=>'悭','ļ½ø'=>'ク','ļ½¹'=>'悱','ļ½ŗ'=>'コ','ļ½»'=>'悵','ļ½¼'=>'ć‚·','ļ½½'=>'ス','ļ½¾'=>'ć‚»','ソ'=>'ソ','ļ¾€'=>'タ','チ'=>'惁','ッ'=>'惃','ツ'=>'惄','テ'=>'惆','ト'=>'惈','ļ¾…'=>'ナ','ニ'=>'惋','ヌ'=>'ヌ','ネ'=>'惍','ノ'=>'惎','ハ'=>'惏','ヒ'=>'惒','フ'=>'惕','ļ¾'=>'へ','ļ¾Ž'=>'惛','ļ¾'=>'惞','ā§„'=>'〼','ミ'=>'ミ','ム'=>'惠','ļ¾’'=>'惔','モ'=>'モ','ャ'=>'ャ','ļ¾”'=>'惤','ļ½­'=>'惄','ユ'=>'惦','ļ½®'=>'惧','ļ¾–'=>'ヨ','ļ¾—'=>'惩','リ'=>'リ','ļ¾™'=>'惫','レ'=>'惬','ļ¾›'=>'惭','ワ'=>'ワ','ヲ'=>'ヲ','ļ¾'=>'ン','ź’ž'=>'ꁊ','ź’¬'=>'ꁐ','ź’œ'=>'źƒ€','ź’æ'=>'ꉙ','ź’¾'=>'ꊱ','ź“€'=>'źŽ«','ź“‚'=>'źŽµ','ź’ŗ'=>'źŽæ','ź’°'=>'ź‚','𐒠'=>'𐒆','—'=>'äø€','―'=>'äø€','āˆ’'=>'äø€','─'=>'äø€','ā¼€'=>'äø€','ļ„§'=>'äø','ļ©°'=>'äø¦','|'=>'äøØ','|'=>'äøØ','∣'=>'äøØ','⼁'=>'äøØ','‖'=>'äøØäøØ','∄'=>'äøØäøØ','串'=>'äø²','⼂'=>'äø¶','丸'=>'äøø','ļ„ž'=>'äø¹','丽'=>'äø½','⼃'=>'äøæ','乁'=>'乁','⼄'=>'乙','亂'=>'äŗ‚','ā¼…'=>'äŗ…','了'=>'äŗ†','⼆'=>'二','⼇'=>'äŗ ','ļ„·'=>'äŗ®','⼈'=>'äŗŗ','ļ§½'=>'什','仌'=>'仌','令'=>'令','你'=>'ä½ ','倂'=>'ä½µ','倂'=>'ä½µ','侀'=>'侀','來'=>'來','例'=>'例','侮'=>'ä¾®','侮'=>'ä¾®','侻'=>'ä¾»','ļ„„'=>'便','值'=>'値','ļ§”'=>'倫','偺'=>'偺','備'=>'備','像'=>'像','僚'=>'僚','僧'=>'僧','僧'=>'僧','⼉'=>'儿','兀'=>'兀','ļ©“'=>'充','免'=>'免','šÆ Ž'=>'免','šÆ '=>'兔','兤'=>'兤','⼊'=>'å…„','內'=>'內','全'=>'å…Ø',''=>'兩','⼋'=>'八','ļ§‘'=>'六','具'=>'具','冀'=>'冀','⼌'=>'冂','再'=>'再','冒'=>'冒','冕'=>'冕','ā¼'=>'冖','冗'=>'冗','冤'=>'冤','ā¼Ž'=>'冫','冬'=>'冬','况'=>'况','况'=>'况','冷'=>'冷',''=>'凉','ļ„•'=>'凌','ļ„”'=>'凜','凞'=>'凞','ā¼'=>'几','šÆ '=>'凵','⼐'=>'凵','⼑'=>'刀','šÆ ž'=>'刃','切'=>'切','𯔐'=>'切','列'=>'列','ļ§'=>'利','ļ§æ'=>'刺','刻'=>'刻','內'=>'剆','割'=>'割','剷'=>'剷','劉'=>'劉','力'=>'力','ā¼’'=>'力','ļ¦'=>'劣','劳'=>'劳','ļ©¶'=>'勇','你'=>'勇','勉'=>'勉','勉'=>'勉','ļ„’'=>'勒','勞'=>'勞','﨓'=>'勤','勤'=>'勤',''=>'勵','⼓'=>'勹','ļ©·'=>'勺','勺'=>'勺','包'=>'包','匆'=>'匆','ā¼”'=>'匕','ļ„£'=>'北','北'=>'北','⼕'=>'匚','ā¼–'=>'匸','ļ§«'=>'匿','ā¼—'=>'十','〸'=>'十','〹'=>'卄','〺'=>'卅','卉'=>'卉','卑'=>'卑','卑'=>'卑','博'=>'博','⼘'=>'卜','ā¼™'=>'卩','即'=>'即','卵'=>'卵','卽'=>'卽','卿'=>'åæ','卿'=>'åæ','卿'=>'åæ','⼚'=>'厂','ā¼›'=>'厶','ļ„«'=>'參','⼜'=>'又','及'=>'及','叟'=>'叟','ā¼'=>'口','句'=>'叄','叫'=>'叫','叱'=>'叱','吆'=>'吆','ļ§ž'=>'吏','ļ§­'=>'吝','吸'=>'吸','呂'=>'呂','呈'=>'呈','周'=>'周','咞'=>'咞','𯔀'=>'咢','ļ¦ž'=>'咽','𯔁'=>'哶','𯔂'=>'唐','𯔃'=>'啓','啟'=>'啓','啕'=>'啕','𯔄'=>'啣','𯔅'=>'善','𯔆'=>'善','喇'=>'喇','喙'=>'喙','𯔇'=>'喙','喝'=>'喝','喝'=>'喝','𯔈'=>'喫','𯔉'=>'喳','ļØ'=>'嗀','𯔊'=>'嗂','ļ©»'=>'嗢','嘆'=>'嘆','𯔌'=>'嘆','šÆ”Ž'=>'噑','器'=>'器','šÆ”'=>'噓','ā¼ž'=>'囗','囹'=>'囹','𯔋'=>'圖','šÆ”'=>'圗','⼟'=>'土','𯔕'=>'型','𯔒'=>'城','𯔓'=>'埓','𯔔'=>'堍','𯔗'=>'å ±','𯔖'=>'å ²','塀'=>'唀','塚'=>'唚','塚'=>'唚',''=>'唞','唫'=>'å””','墨'=>'墨','壿'=>'墫','𯔘'=>'墬','墳'=>'墳',''=>'壘','ļ„‚'=>'壟','ā¼ '=>'士','𯔑'=>'壮','𯔚'=>'売','𯔛'=>'壷','ā¼”'=>'夂','𯔜'=>'夆','ā¼¢'=>'夊','ā¼£'=>'夕','šÆ”'=>'多','šÆ”ž'=>'夢','⼤'=>'大','奄'=>'å„„','奈'=>'儈','契'=>'å„‘','奔'=>'å„”','𯔟'=>'å„¢','女'=>'儳','⼄'=>'儳','𯔄'=>'姘','𯔢'=>'姬','𯔣'=>'娛','𯔤'=>'娧','ļŖ€'=>'å©¢','𯔦'=>'婦','嬀'=>'åŖÆ','媵'=>'åŖµ','𯔩'=>'嬈','嬨'=>'嬨','𯔪'=>'嬾','𯔫'=>'嬾','⼦'=>'子','ā¼§'=>'宀','宅'=>'宅','𯔭'=>'寃','𯔮'=>'寘',''=>'寧','寧'=>'寧','𯔯'=>'寧','寮'=>'寮','𯔰'=>'寳','⼨'=>'寸','𯔲'=>'寿','𯔳'=>'将','⼩'=>'小','𯔵'=>'å°¢','ā¼Ŗ'=>'å°¢','⼫'=>'å°ø','尿'=>'å°æ','𯔷'=>'å± ','ļ„‹'=>'å±¢','層'=>'層','履'=>'屄','屮'=>'å±®','𯔸'=>'å±®','⼬'=>'å±®','ā¼­'=>'å±±','𯔺'=>'岍','𯔹'=>'峀','ļ§•'=>'å“™','𯔼'=>'嵃','樂'=>'嵐','𯔿'=>'嵫','𯔾'=>'åµ®','嵼'=>'åµ¼','𧲨'=>'å¶²','嶺'=>'å¶ŗ','ā¼®'=>'巛','巡'=>'å·”','巢'=>'å·¢','⼯'=>'å·„','ā¼°'=>'å·±','巽'=>'å·½','ā¼±'=>'å·¾','åø²'=>'åø”','帨'=>'åøØ','帽'=>'åø½','幩'=>'幩','ā¼²'=>'å¹²','ļ¦Ž'=>'幓','ā¼³'=>'å¹ŗ','⼓'=>'广','度'=>'åŗ¦','庰'=>'åŗ°','庳'=>'åŗ³','šÆ¢'=>'åŗ¶','廉'=>'廉','廊'=>'廊','šÆ¢Ž'=>'廊','ļŖ‚'=>'廒','廓'=>'廓','廙'=>'廙','廬'=>'廬','ā¼µ'=>'廓','廾'=>'廾','ā¼¶'=>'廾',''=>'弄','ā¼·'=>'弋','ā¼ø'=>'弓','弢'=>'å¼¢','弢'=>'å¼¢','ā¼¹'=>'彐','𯔓'=>'当','ā¼ŗ'=>'å½”','形'=>'å½¢','ļŖ„'=>'彩','彫'=>'彫','ā¼»'=>'å½³','律'=>'律','徚'=>'徚',''=>'復','ļŖ…'=>'å¾­','ā¼¼'=>'心','šÆ¢'=>'åæ','šÆ¢ž'=>'åæ—','念'=>'åæµ','忹'=>'åæ¹','ļ„ '=>'ꀒ','怜'=>'ꀜ','悁'=>'ꂁ','悔'=>'ꂔ','悔'=>'ꂔ','巽'=>'ꃇ','ļŖ†'=>'ꃘ','惡'=>'ꃔ','愈'=>'ꄈ','ļ§™'=>'ꅄ','慈'=>'ꅈ','慌'=>'ꅌ','慌'=>'ꅌ','ļŖ‡'=>'ꅎ','慎'=>'ꅎ','慠'=>'ꅠ','慨'=>'ę…Ø','慺'=>'ę…ŗ','憎'=>'ꆎ','ļŖ‰'=>'ꆎ','憎'=>'ꆎ','ļ¦'=>'ꆐ','憤'=>'ꆤ','憯'=>'憯','憲'=>'憲','懞'=>'ꇞ','ļ©€'=>'懲','ļŖ‹'=>'懲','懲'=>'懲','ļ¤'=>'ꇶ','懶'=>'ꇶ','戀'=>'ꈀ','ā¼½'=>'ꈈ','成'=>'ꈐ','戛'=>'ꈛ','ļ§’'=>'ꈮ','戴'=>'ꈓ','ā¼¾'=>'ꈶ','⼿'=>'ꉋ','舁'=>'ꉝ','抱'=>'抱','滑'=>'ꋉ','ļ„›'=>'ꋏ','拓'=>'ꋓ','拔'=>'ꋔ','拼'=>'拼',''=>'拾','挽'=>'挽','捐'=>'ꍐ','捨'=>'ęØ','捻'=>'ę»','掃'=>'ꎃ',''=>'ꎠ','掩'=>'ꎩ','ļŖ'=>'ꏄ','揅'=>'ꏅ','揤'=>'ꏤ','橁'=>'ꐉ','ļŖŽ'=>'搜','搢'=>'搢','ļŖ'=>'ꑒ','摩'=>'ę‘©','摷'=>'ę‘·','摾'=>'摾','撚'=>'꒚','撝'=>'꒝','擄'=>'꓄','ā½€'=>'支','⽁'=>'ꔓ','敏'=>'ꕏ','敏'=>'ꕏ','敖'=>'ꕖ','敬'=>'ꕬ','ļ„©'=>'數','⽂'=>'ꖇ','⽃'=>'ꖗ','料'=>'ꖙ','⽄'=>'ꖤ','ā½…'=>'ę–¹','旅'=>'ꗅ','⽆'=>'ꗠ','ļ©‚'=>'ę—¢','旣'=>'ę—£','⽇'=>'ę—„','ļ§ '=>'ꘓ','šÆ£'=>'ꙉ','ꙩ'=>'Ꙛ','䀿'=>'晣','晴'=>'ꙓ','ļŖ‘'=>'ꙓ','ļ§…'=>'暈','暑'=>'ꚑ','šÆ£'=>'ꚑ','暜'=>'暜','暴'=>'暓','曆'=>'ꛆ','⽈'=>'꛰','更'=>'ꛓ','㫚'=>'ę›¶','書'=>'書','最'=>'꜀','⽉'=>'月','肦'=>'朌','胐'=>'꜏','胊'=>'朐','脁'=>'꜓','朗'=>'ꜗ','ļŖ’'=>'ꜗ','朗'=>'ꜗ','脧'=>'朘','ļŖ“'=>'ꜛ','望'=>'ꜛ','朡'=>'朔','膧'=>'朣','⽊'=>'木','ļ§”'=>'Ꝏ','杓'=>'ꝓ','ļŖ”'=>'Ꝗ','杞'=>'Ꝟ','柿'=>'ę®','杻'=>'ę»','枅'=>'ꞅ','ļ§“'=>'ꞗ','柳'=>'柳','柺'=>'柺','栗'=>'ꠗ','摾'=>'栟','最'=>'ę”’',''=>'梁','ļ©„'=>'梅','梅'=>'梅','梎'=>'ę¢Ž','ļ§¢'=>'梨','椔'=>'ꤔ','楂'=>'ę„‚','樧'=>'ę¦','榣'=>'榣','槪'=>'ę§Ŗ','樂'=>'樂',''=>'樂','樂'=>'樂',''=>'樓','檨'=>'ęŖØ','櫓'=>'ę«“','櫛'=>'ę«›','ļ¤'=>'ꬄ','⽋'=>'ꬠ','次'=>'ꬔ','歔'=>'ꭔ','⽌'=>'ę­¢','歲'=>'ę­²','歷'=>'ę­·','ļŖ•'=>'ę­¹','ā½'=>'ę­¹','冕'=>'殟','濾'=>'ę®®','ā½Ž'=>'殳','ļ„°'=>'殺','ļŖ–'=>'殺','殺'=>'殺','殻'=>'ę®»','ā½'=>'毋','⺟'=>'ęÆ','⽐'=>'比','⽑'=>'毛','ā½’'=>'갏','⽓'=>'갔','ā½”'=>'ę°“','汎'=>'걎','汧'=>'ę±§',''=>'沈','沿'=>'沿',''=>'泌','泍'=>'ę³','ļ§£'=>'泄','洖'=>'ę“–','洛'=>'ę“›','洞'=>'ꓞ','洴'=>'ę““','派'=>'擾','流'=>'굁','ļŖ—'=>'굁','流'=>'굁','浩'=>'굩','浪'=>'ęµŖ','ļ©…'=>'ęµ·','海'=>'ęµ·','浸'=>'ęµø','涅'=>'ę¶…','ļ§µ'=>'ę·‹','ļ„'=>'淚','ļ§–'=>'ę·Ŗ','šÆ¤Ž'=>'ę·¹','渚'=>'渚','港'=>'ęøÆ','湮'=>'ę¹®','ę½™'=>'溈','ļ§‹'=>'溜','溺'=>'ęŗŗ','滇'=>'껇','ļŖ™'=>'껋','滋'=>'껋','滑'=>'껑','滛'=>'ę»›','ļ„Ž'=>'ę¼','漢'=>'ę¼¢','漢'=>'ę¼¢','漣'=>'ę¼£','šÆ¤'=>'ę½®','濆'=>'濆','濫'=>'ęæ«','濾'=>'ęæ¾','瀛'=>'瀛','ļŖ›'=>'ē€ž','瀞'=>'ē€ž','瀹'=>'瀹','灊'=>'灊','⽕'=>'火','灰'=>'灰','灷'=>'灷','災'=>'災','ļ§»'=>'ē‚™','炭'=>'ē‚­','烈'=>'烈','烙'=>'ēƒ™','煅'=>'ē……','煉'=>'ē…‰','煮'=>'ē…®','煮'=>'ē…®','šÆ¤ž'=>'ē†œ','ļ§€'=>'ē‡Ž','ļ§®'=>'燐','爐'=>'爐','ļ¤ž'=>'ēˆ›','爨'=>'爨','ā½–'=>'爪','爫'=>'爫','āŗ¤'=>'爫','ļŖž'=>'爵','瀞'=>'爵','ā½—'=>'父','⽘'=>'爻','ā½™'=>'爿','⽚'=>'片','牐'=>'牐','ā½›'=>'牙','⽜'=>'牛',''=>'牢','犀'=>'ēŠ€','浸'=>'ēŠ•','ā½'=>'犬','犯'=>'犯','ļ§ŗ'=>'ē‹€','狼'=>'狼','猪'=>'猪','ļŖ '=>'猪','獵'=>'ēµ','獺'=>'ēŗ','ā½ž'=>'ēŽ„','ļ„”'=>'ēŽ‡','ļ§›'=>'ēŽ‡','⽟'=>'ēŽ‰','王'=>'ēŽ‹','玥'=>'ēŽ„','玲'=>'ēŽ²','珞'=>'ēž','理'=>'理','琉'=>'琉','琢'=>'琢','瑇'=>'瑇','瑜'=>'ē‘œ','瑩'=>'ē‘©','ļŖ”'=>'瑱','瑱'=>'瑱','璅'=>'ē’…','璉'=>'ē’‰','ļ§Æ'=>'ē’˜','瓊'=>'ē“Š','ā½ '=>'ē“œ','ā½”'=>'瓦','ļŖ¢'=>'甆','ā½¢'=>'ē”˜','ā½£'=>'ē”Ÿ','瀹'=>'甤','⽤'=>'用','⽄'=>'ē”°','ļŖ£'=>'ē”»','甾'=>'甾','ļ§'=>'ē•™','ļ„¶'=>'ē•„','ļ„¢'=>'ē•°','異'=>'ē•°','⽦'=>'ē–‹','ā½§'=>'ē–’','ļ§„'=>'ē—¢','瘐'=>'瘐','ļŖ¤'=>'ē˜','ļŖ„'=>'瘟','療'=>'療','ļ¤Ž'=>'癩','⽨'=>'ē™¶','⽩'=>'白','ā½Ŗ'=>'皮','⽫'=>'皿','益'=>'ē›Š','ļŖ¦'=>'ē›Š','ļŖ§'=>'ē››','盧'=>'ē›§','⽬'=>'ē›®','ļŖØ'=>'盓','𯄀'=>'盓','ļ„­'=>'省','𯄅'=>'ēœž','𯄆'=>'真','𯄇'=>'真','ļŖŖ'=>'ē€','ļŖ©'=>'ēŠ','𯄈'=>'ēŠ','𯄊'=>'ēž‹','ļŖ'=>'ēž§','ā½­'=>'ēŸ›','ā½®'=>'矢','⽯'=>'石','ē”'=>'ē ”','šÆ„Ž'=>'ē”Ž','ļ§Ž'=>'甫','碌'=>'碌','šÆ„'=>'碌','ļ©‹'=>'碑',''=>'磊','ļŖ«'=>'磌','𯄐'=>'磌',''=>'磻','礪'=>'礪','ā½°'=>'示','礼'=>'礼','社'=>'社','ļ©Ž'=>'焈','ļ©'=>'焉','ļ©'=>'焐','祖'=>'ē„–','𯄓'=>'ē„–','ļ©‘'=>'ē„','神'=>'ē„ž','祥'=>'ē„„','祿'=>'焿','ļ©’'=>'ē¦','ļ©“'=>'ē¦Ž','福'=>'ē¦','𯄖'=>'ē¦','禮'=>'禮','ā½±'=>'禸','ā½²'=>'禾','秊'=>'秊','𯄗'=>'ē§«','ļ„–'=>'稜','ļ©”'=>'ē©€','𯄙'=>'ē©€','𯄚'=>'穊','𯄛'=>'ē©','ā½³'=>'ē©“','ļ©•'=>'突','ļŖ¬'=>'ēŖ±','ļ§·'=>'ē«‹','⽓'=>'ē«‹','𯄟'=>'ē«®','ā½µ'=>'竹','ļ§ø'=>'笠','ļ©–'=>'節','ļŖ­'=>'節','𯄢'=>'篆','𯄣'=>'築','簾'=>'ē°¾','ļ„„'=>'ē± ','ā½¶'=>'ē±³','ļŖ®'=>'ē±»','ļ§¹'=>'ē²’','ļØ'=>'ē²¾','𯄦'=>'ē³’','糖'=>'ē³–','𯄩'=>'ē³£','ļ„»'=>'ē³§','𯄨'=>'糨','ā½·'=>'ē³ø','𯄪'=>'ē“€','ļ§'=>'瓐',''=>'ē“¢','ļ„'=>'瓯','ēµ¶'=>'絕','ļŖÆ'=>'ēµ›','𯄬'=>'ēµ£','綠'=>'ē¶ ','ļ„—'=>'ē¶¾','𯄮'=>'ē·‡','練'=>'ē·“','ļ©—'=>'ē·“','ļŖ°'=>'ē·“','𯄯'=>'ēø‚','縉'=>'ēø‰',''=>'ēø·','ļ©™'=>'繁','𯄰'=>'ē¹…','ā½ø'=>'ē¼¶','ļŖ±'=>'ē¼¾','ā½¹'=>'网','āŗ«'=>'ē½’','署'=>'ē½²','罹'=>'ē½¹','𯄶'=>'ē½ŗ','ļ¤'=>'ē¾…','ā½ŗ'=>'羊','𯄸'=>'羕','羚'=>'羚','ļØž'=>'ē¾½','ā½»'=>'ē¾½','𯄹'=>'ēæŗ','邏'=>'老','ā½¼'=>'老','ļ©›'=>'者','ļŖ²'=>'者','𯄺'=>'者','ā½½'=>'而','ā½¾'=>'耒','⽿'=>'耳','聆'=>'聆','𯄽'=>'聠','聯'=>'聯','𯄿'=>'聰','ļ„…'=>'聾','ā¾€'=>'聿','⾁'=>'肉','ļ„“'=>'肋','肭'=>'肭','育'=>'育','欵'=>'胶','腁'=>'胼','脃'=>'脃','脾'=>'脾','臘'=>'臘','⾂'=>'臣','ļ§¶'=>'臨','⾃'=>'自','臭'=>'臭','⾄'=>'至','ā¾…'=>'臼','舁'=>'舁','舁'=>'舁','舄'=>'舄','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮',''=>'良','⾊'=>'色','⾋'=>'艸','ļ©'=>'艹','ļ©ž'=>'艹','芋'=>'芋','šÆ¦'=>'芑','芝'=>'芝','花'=>'花','芳'=>'芳','芽'=>'芽','ļ„“'=>'č‹„','若'=>'č‹„','苦'=>'苦','茝'=>'茝','茣'=>'茣','ļ§¾'=>'茶','ļŖ³'=>'荒','荓'=>'荓','荣'=>'č£','莭'=>'莭','šÆ¦'=>'čŽ½','菉'=>'菉','芳'=>'菊','菌'=>'菌','菜'=>'菜','šÆ¦ž'=>'菧','ļŖ“'=>'čÆ',''=>'č±','落'=>'落','ļ„®'=>'葉','著'=>'著','著'=>'著','蔿'=>'蒍','蓮'=>'č“®','蓱'=>'蓱','蓳'=>'蓳','ļ§‚'=>'蓼','蔖'=>'蔖','蕤'=>'蕤','藍'=>'藍','ļ§°'=>'č—ŗ','蘆'=>'蘆','蘒'=>'蘒','蘭'=>'蘭','虁'=>'蘷','蘿'=>'蘿','⾌'=>'虍','虐'=>'虐','虜'=>'虜','花'=>'虜','虧'=>'虧','虩'=>'虩','ā¾'=>'虫','蚈'=>'蚈','蚩'=>'蚩','蛢'=>'蛢','蜎'=>'蜎','蜨'=>'蜨','蝫'=>'č«','ļŖµ'=>'č¹','蝹'=>'č¹','螆'=>'螆','螺'=>'čžŗ','蟡'=>'蟔','蠁'=>'蠁','蠟'=>'蠟','ā¾Ž'=>'蔀','行'=>'蔌','ā¾'=>'蔌','衠'=>'č” ','衣'=>'蔣','⾐'=>'蔣','裂'=>'裂','ļ§§'=>'č£','裗'=>'裗','裞'=>'č£ž','ļ§Ø'=>'裔','裸'=>'裸','裺'=>'裺','ļ© '=>'褐','ļŖ¶'=>'脁','襤'=>'脤','⾑'=>'脾','ļŖ·'=>'覆','見'=>'見','ā¾’'=>'見','ļ©”'=>'視','ļŖø'=>'視','⾓'=>'角','ā¾”'=>'言','䚶'=>'čØž','詽'=>'訮','šÆ§'=>'čŖ ',''=>'čŖŖ','璉'=>'čŖŖ','ļŖ¹'=>'čŖæ','ļŖ»'=>'č«‹',''=>'č«’',''=>'č«–','ļŖ¾'=>'č«­','諭'=>'č«­','諸'=>'諸','ļŖŗ'=>'諸','ļ„'=>'諾','ļŖ½'=>'諾','ļ©¢'=>'謁','ļŖ¼'=>'謁','ļ©£'=>'謹','ļŖæ'=>'謹','ļ§¼'=>'識',''=>'讀','č®'=>'讆','ļ«€'=>'變','變'=>'變','⾕'=>'č°·','ā¾–'=>'豆','豈'=>'豈','豕'=>'豕','ā¾—'=>'豕','⾘'=>'č±ø','ā¾™'=>'č²','貫'=>'貫','賁'=>'賁',''=>'賂','賈'=>'賈','賓'=>'賓','ļ©„'=>'蓈','贈'=>'蓈','贛'=>'č“›','⾚'=>'赤','ā¾›'=>'čµ°','起'=>'čµ·','趆'=>'赿','⾜'=>'č¶³','趼'=>'č¶¼','跋'=>'č·‹','č·ŗ'=>'č·„','路'=>'č·Æ','跰'=>'č·°','čŗ›'=>'čŗ—','ā¾'=>'čŗ«','車'=>'車','ā¾ž'=>'車','šÆ§ž'=>'č»”','č¼§'=>'軿','輦'=>'輦','ļ§—'=>'č¼Ŗ','ļ«‚'=>'č¼ø','輸'=>'č¼ø','輻'=>'č¼»','ļ¦'=>'č½¢','⾟'=>'č¾›','šÆ¦'=>'č¾ž',''=>'č¾°','ā¾ '=>'č¾°','ā¾”'=>'č¾µ','辶'=>'č¾¶','⻌'=>'č¾¶','連'=>'連','宅'=>'逸','ļ©§'=>'逸','遲'=>'遲','遼'=>'遼','邏'=>'邏','ā¾¢'=>'邑','邔'=>'邔','郎'=>'郎','郱'=>'郱','都'=>'都','鄑'=>'鄑','鄛'=>'鄛','ā¾£'=>'酉','酪'=>'é…Ŗ','ļ«„'=>'醙','醴'=>'醓','⾤'=>'釆','ļ§©'=>'里','⾄'=>'里',''=>'量','金'=>'金','⾦'=>'金','鈴'=>'鈓','鈸'=>'鈸','ļ«…'=>'鉶','鉼'=>'鉼','鋗'=>'鋗','鋘'=>'鋘','錄'=>'錄','鍊'=>'鍊','鎮'=>'鎭','鏹'=>'鏹','鐕'=>'鐕','ā¾§'=>'長','⾨'=>'門','開'=>'開','閭'=>'閭','閷'=>'閷','⾩'=>'阜','阮'=>'阮','ļ„‘'=>'陋','降'=>'降','ļ„™'=>'陵','ļ§“'=>'陸','陼'=>'陼','隆'=>'隆','ļ§±'=>'隣','ā¾Ŗ'=>'隶','隸'=>'隸','⾫'=>'隹','雃'=>'雃','ļ§Ŗ'=>'離','難'=>'難','難'=>'難','⾬'=>'雨','零'=>'零',''=>'雷','霣'=>'霣','露'=>'露','靈'=>'靈','ā¾­'=>'靑','靖'=>'靖','靖'=>'靖','ā¾®'=>'非','⾯'=>'面','ā¾°'=>'革','ā¾±'=>'韋','韛'=>'韛','韠'=>'韠','ā¾²'=>'韭','ā¾³'=>'音','ļ©©'=>'響','響'=>'響','⾓'=>'頁','ļ«‹'=>'頋','頋'=>'頋','頋'=>'頋','煉'=>'領','頩'=>'é ©','頻'=>'é »','頻'=>'é »','類'=>'锞','ā¾µ'=>'風','ā¾¶'=>'飛','ā»'=>'食','ā¾·'=>'食','飢'=>'飢','飯'=>'飯','飼'=>'飼','館'=>'館','餩'=>'餩','ā¾ø'=>'首','ā¾¹'=>'香','馧'=>'馧','ā¾ŗ'=>'馬','駂'=>'駂','駱'=>'é§±','駾'=>'é§¾','驪'=>'驪','ā¾»'=>'éŖØ','ā¾¼'=>'高','ā¾½'=>'髟','ļ«'=>'鬒','鬒'=>'鬒','ā¾¾'=>'鬄','⾿'=>'鬯','⿀'=>'鬲','⿁'=>'鬼','āæ‚'=>'魚','魯'=>'é­Æ','鱀'=>'鱀','ļ§²'=>'鱗','⿃'=>'鳄','鳽'=>'é³½','šÆØ'=>'éµ§','鶴'=>'é¶“','鷺'=>'é·ŗ','鸞'=>'éøž','鹃'=>'鹂','āæ„'=>'é¹µ','ļ„€'=>'鹿','āæ…'=>'鹿','麗'=>'éŗ—','ļ§³'=>'麟','⿆'=>'éŗ„','麻'=>'éŗ»','⿇'=>'éŗ»','⿈'=>'黃','⿉'=>'黍','黎'=>'黎','⿊'=>'黑','黹'=>'黹','āæ‹'=>'黹','⿌'=>'黽','黾'=>'黾','鼅'=>'鼅','āæ'=>'鼎','鼏'=>'鼏','āæŽ'=>'鼓','鼖'=>'鼖','āæ'=>'é¼ ','鼻'=>'é¼»','⿐'=>'é¼»','齃'=>'齃','āæ‘'=>'齊','āæ’'=>'齒','ļ§„'=>'龍','āæ“'=>'龍','ļ«™'=>'龎','龜'=>'龜','龜'=>'龜','ļ«Ž'=>'龜','āæ”'=>'龜','⻳'=>'龟','āæ•'=>'é¾ ','㒞'=>'撞','㒹'=>'ć’¹','㒻'=>'ć’»','㓟'=>'擟','㔕'=>'攕','䎛'=>'斈','𯔧'=>'ć›®','𯔨'=>'㛼','𯔶'=>'极','㠯'=>'ć Æ','㡢'=>'㔢','㡼'=>'㔼','㣇'=>'㣇','㣣'=>'㣣','㤜'=>'㤜','弢'=>'㤺','㨮'=>'㨮','㩬'=>'橬','㫤'=>'櫤','㬈'=>'欈','šÆ£Ž'=>'欙','䐠'=>'欻','šÆ£ž'=>'歉','ļ«’'=>'ć®','㮝'=>'ć®','㰘'=>'氘','㱎'=>'汎','㴳'=>'㓳','㶖'=>'ć¶–','㺬'=>'ćŗ¬','㺸'=>'ćŗø','㺸'=>'ćŗø','㼛'=>'ć¼›','㿼'=>'ćæ¼','䀈'=>'䀈','ļ«“'=>'䀘','ļ«”'=>'䀹','𯄉'=>'䀹','𯄋'=>'䁆','𯄌'=>'䂖','𯄑'=>'䃣','𯄘'=>'䄯','𯄠'=>'䈂','𯄤'=>'䈧','𯄧'=>'䊠','𯄭'=>'䌁','𯄱'=>'䌓','𯄓'=>'䍙','䏕'=>'䏕','䏙'=>'䏙','䐋'=>'䐋','šÆ¦Ž'=>'䑫','䔫'=>'䔫','䕝'=>'䕝','䕡'=>'ä•”','䕫'=>'䕫','䗗'=>'䗗','䗹'=>'䗹','䘵'=>'䘵','šÆ§'=>'䚾','šÆ§Ž'=>'䛇','䦕'=>'䦕','䧦'=>'䧦','䩮'=>'ä©®','䩶'=>'ä©¶','䪲'=>'äŖ²','䬳'=>'䬳','䯎'=>'äÆŽ','šÆØ'=>'䳎','šÆØŽ'=>'ä³­','䳸'=>'ä³ø','䵖'=>'䵖','𠄢'=>'š „¢','𠔜'=>'š ”œ','𠔥'=>'š ”„','𠕋'=>'š •‹','šÆ '=>'𠘺','𠠄'=>'š  „','šÆ§'=>'š £ž','㒹'=>'𠨬','𠭣'=>'š ­£','𯔙'=>'𔓤','𯔠'=>'𔚨','𯔔'=>'š”›Ŗ','𯔬'=>'𔧈','𯔱'=>'𔬘','𡴋'=>'𔓋','𯔻'=>'š”·¤','𯔽'=>'š”·¦','𢆃'=>'š¢†ƒ','𢆟'=>'š¢†Ÿ','𢌱'=>'𢌱','𢌱'=>'𢌱','𢛔'=>'𢛔','𢡄'=>'𢔄','ļ«'=>'𢔊','𢬌'=>'𢬌','𢯱'=>'𢯱','𣀊'=>'š£€Š','𣊸'=>'𣊸','𣍟'=>'š£Ÿ','𣎓'=>'š£Ž“','𣎜'=>'š£Žœ','šÆ£'=>'š£ƒ','ļ«‘'=>'š£•','𣑭'=>'𣑭','𣚣'=>'𣚣','𣢧'=>'𣢧','𣪍'=>'š£Ŗ','𣫺'=>'𣫺','𣲼'=>'𣲼','𣴞'=>'š£“ž','šÆ¤'=>'𣻑','𣽞'=>'š£½ž','𣾎'=>'š£¾Ž','šÆ¤'=>'𤉣','𤎫'=>'š¤Ž«','𤘈'=>'𤘈','𤜵'=>'𤜵','𤠔'=>'𤠔','𤰶'=>'𤰶','𤲒'=>'𤲒','𤾡'=>'𤾔','𤾸'=>'𤾸','𥁄'=>'š„„','𯄂'=>'š„ƒ²','𯄁'=>'š„ƒ³','𯄃'=>'š„„™','𯄄'=>'š„„³','ļ«•'=>'š„‰‰','šÆ„'=>'š„','𯄒'=>'š„˜¦','𯄔'=>'š„šš','𯄕'=>'š„›…','𯄜'=>'š„„¼','šÆ„'=>'š„Ŗ§','šÆ„ž'=>'š„Ŗ§','𯄔'=>'š„®«','𯄄'=>'š„²€','ļ«–'=>'š„³','𯄫'=>'š„¾†','𦇚'=>'š¦‡š','𯄲'=>'𦈨','𯄳'=>'𦉇','𯄵'=>'𦋙','𯄷'=>'𦌾','𯄻'=>'š¦“š','𯄼'=>'𦔣','𯄾'=>'𦖨','𦞧'=>'š¦ž§','𦞵'=>'š¦žµ','𦬼'=>'𦬼','𦰶'=>'𦰶','𦳕'=>'𦳕','䐋'=>'𦵫','𦼬'=>'𦼬','𦾱'=>'𦾱','𧃒'=>'š§ƒ’','𧏊'=>'š§Š','𧙧'=>'š§™§','𧢮'=>'š§¢®','𧥦'=>'𧄦','𧲨'=>'𧲨','ļ«—'=>'𧻓','𧼯'=>'𧼯','𨗒'=>'𨗒','貫'=>'𨗭','衣'=>'𨜮','𨯺'=>'𨯺','𨵷'=>'𨵷','𩅅'=>'š©……','𩇟'=>'š©‡Ÿ','𩈚'=>'𩈚','𩐊'=>'𩐊','𩒖'=>'š©’–','𩖶'=>'š©–¶','𩬰'=>'𩬰','𪃎'=>'šŖƒŽ','𪄅'=>'šŖ„…','𪈎'=>'šŖˆŽ','𪊑'=>'šŖŠ‘','šÆ¢'=>'šŖŽ’','šÆØ'=>'šŖ˜€','ā„ƒ'=>'°C','℉'=>'°F','ℇ'=>'ʐ','ā„»'=>'FAX','ā„•'=>'N','ā„–'=>'No','ā„š'=>'Q','₨'=>'Rs','š“'=>'T','ā„”'=>'TEL','š”'=>'U','š–'=>'W','ā‚©'=>'W̵','š—'=>'X','Ā„'=>'Y̵','šš²'=>'Ī›','ššµ'=>'Īž','ℿ'=>'Ī ','ϲ'=>'c','Ļ’'=>'Y','šš½'=>'Φ','ššæ'=>'ĪØ','Ń£'=>'Ь̵','ਃ'=>'ঃ','ಃ'=>'ః','່'=>'่','įŸ‹'=>'่','້'=>'้','໊'=>'๊','໋'=>'๋','įŸ•'=>'๚','៚'=>'ą¹›','ъ'=>'ˉb','įŸ™'=>'ą¹','ą³§'=>'ą±§','૨'=>'ą„Ø','೨'=>'౨','ą«©'=>'ą„©','૪'=>'ą„Ŗ','ą«®'=>'ą„®','೯'=>'౯','а'=>'a','į'=>'b','į–Æ'=>'b','с'=>'c','ԁ'=>'d','ᑯ'=>'d','е'=>'e','ә'=>'Ē','ε'=>'ɛ','є'=>'ɛ','ք'=>'f','ց'=>'g','Ņ»'=>'h','Õ°'=>'h','į‚'=>'h','į²'=>'hĢ”','ι'=>'i','і'=>'i','įŽ„'=>'i','ј'=>'j','Õµ'=>'j','į—°'=>'m','Õø'=>'n','Ī·'=>'nĢ©','ą°‚'=>'o','ಂ'=>'o','ą“‚'=>'o','ą„¦'=>'o','੦'=>'o','૦'=>'o','๐'=>'o','໐'=>'o','Īæ'=>'o','о'=>'o','օ'=>'o','į€'=>'o','ρ'=>'p','р'=>'p','į“©'=>'ᓘ','Õ£'=>'q','Īŗ'=>'Äø','Šŗ'=>'Äø','ᓦ'=>'r','г'=>'r','ѕ'=>'s','Ļ…'=>'u','Õ½'=>'u','ν'=>'v','ѵ'=>'v','įŽ³'=>'w','į—Æ'=>'w','х'=>'x','ᕁ'=>'x','у'=>'y','įŽ©'=>'y','Ó”'=>'Ź’','ჳ'=>'Ź’','Ļ©'=>'ĘØ','ь'=>'ʅ','ы'=>'ʅi','ɑ'=>'α','Õ®'=>'Ī“','į•·'=>'Ī“','Šæ'=>'Ļ€','Éø'=>'φ','ф'=>'φ','Ź™'=>'в','ɜ'=>'Š·','į“'=>'м','ʜ'=>'н','É¢'=>'Ō','į“›'=>'т','į“™'=>'я','ąŖ½'=>'ऽ','ુ'=>'ą„','ą«‚'=>'ą„‚','ą©‹'=>'ą„†','ą©'=>'ą„','ą«'=>'ą„','ą“‰'=>'உ','ą“œ'=>'ஐ','ą“£'=>'ண','ą““'=>'ஓ','ą“æ'=>'ி','ു'=>'ூ','ą²…'=>'ą°…','ಆ'=>'ą°†','ಇ'=>'ą°‡','ą²’'=>'ą°’','ಓ'=>'ఒౕ','ಜ'=>'జ','ą²ž'=>'ą°ž','ą²£'=>'ą°£','ą°„'=>'ą°§Ö¼','ಯ'=>'ą°Æ','ą° '=>'ą°°Ö¼','ą²±'=>'ą°±','ą²²'=>'ą°²','ඌ'=>'ą“Øąµą“Ø','ą®¶'=>'ą“¶','ຈ'=>'จ','ບ'=>'บ','ąŗ›'=>'ąø›','ąŗ'=>'ąø','ąŗž'=>'ąøž','ຟ'=>'ฟ','ąŗ'=>'ąø¢','įŸ”'=>'ąøÆ','įž·'=>'ąø“','įžø'=>'ąøµ','įž¹'=>'ąø¶','įžŗ'=>'ąø·','ąŗø'=>'ąøø','ąŗ¹'=>'ąø¹','į—…'=>'A','į’'=>'J','ᕼ'=>'H','ᐯ'=>'V','į‘­'=>'P','į—·'=>'B','惘'=>'へ','š‘'=>'šŽ‚','š“'=>'šŽ“','š’€ø'=>'šŽš','į…³'=>'äø€','Ē€'=>'äøØ','į…µ'=>'äøØ','įŽŖ'=>'A','į“'=>'B','įŸ'=>'C','į—ž'=>'D','įŽ¬'=>'E','į–“'=>'F','į€'=>'G','įŽ»'=>'H','įŽ«'=>'J','į¦'=>'K','įž'=>'L','įŽ·'=>'M','į¢'=>'P','į–‡'=>'R','į•'=>'S','į™'=>'V','įƒ'=>'Z');
diff --git a/phpBB/install_old/database_update.php b/phpBB/install_old/database_update.php
new file mode 100644
index 0000000000..853848d637
--- /dev/null
+++ b/phpBB/install_old/database_update.php
@@ -0,0 +1,267 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+$update_start_time = time();
+
+/**
+* @ignore
+*/
+define('IN_PHPBB', true);
+define('IN_INSTALL', true);
+$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
+$phpEx = substr(strrchr(__FILE__, '.'), 1);
+
+function phpbb_end_update($cache, $config)
+{
+ $cache->purge();
+
+ $config->increment('assets_version', 1);
+
+?>
+ </p>
+ </div>
+ </div>
+ <span class="corners-bottom"><span></span></span>
+ </div>
+ </div>
+ </div>
+
+ <div id="page-footer">
+ <div class="copyright">
+ Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
+ </div>
+ </div>
+ </div>
+</body>
+</html>
+
+<?php
+
+ garbage_collection();
+ exit_handler();
+}
+
+require($phpbb_root_path . 'includes/startup.' . $phpEx);
+require($phpbb_root_path . 'phpbb/class_loader.' . $phpEx);
+
+$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
+$phpbb_class_loader->register();
+
+$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
+extract($phpbb_config_php_file->get_all());
+
+if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type))
+{
+ die("Please read: <a href='../docs/INSTALL.html'>INSTALL.html</a> before attempting to update.");
+}
+
+// In case $phpbb_adm_relative_path is not set (in case of an update), use the default.
+$phpbb_adm_relative_path = (isset($phpbb_adm_relative_path)) ? $phpbb_adm_relative_path : 'adm/';
+$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : $phpbb_root_path . $phpbb_adm_relative_path;
+
+// Include files
+require($phpbb_root_path . 'includes/functions.' . $phpEx);
+require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
+
+require($phpbb_root_path . 'includes/constants.' . $phpEx);
+require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
+
+// Set PHP error handler to ours
+set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
+
+// Set up container (must be done here because extensions table may not exist)
+$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+$phpbb_container = $phpbb_container_builder
+ ->with_config($phpbb_config_php_file)
+ ->without_extensions()
+ ->without_cache()
+ ->get_container()
+;
+
+// set up caching
+/* @var $cache \phpbb\cache\service */
+$cache = $phpbb_container->get('cache');
+
+// Instantiate some basic classes
+/* @var $phpbb_dispatcher \phpbb\event\dispatcher */
+$phpbb_dispatcher = $phpbb_container->get('dispatcher');
+
+/* @var $request \phpbb\request\request_interface */
+$request = $phpbb_container->get('request');
+
+/* @var $user \phpbb\user */
+$user = $phpbb_container->get('user');
+
+/* @var $auth \phpbb\auth\auth */
+$auth = $phpbb_container->get('auth');
+
+/* @var $db \phpbb\db\driver\driver_interface */
+$db = $phpbb_container->get('dbal.conn');
+
+/* @var $phpbb_log \phpbb\log\log_interface */
+$phpbb_log = $phpbb_container->get('log');
+
+// Grab global variables, re-cache if necessary
+/* @var $config \phpbb\config\config */
+$config = $phpbb_container->get('config');
+
+if (!isset($config['version_update_from']))
+{
+ $config->set('version_update_from', $config['version']);
+}
+
+$orig_version = $config['version_update_from'];
+
+$user->add_lang(array('common', 'acp/common', 'install', 'migrator'));
+
+// Add own hook handler, if present. :o
+if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
+{
+ require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
+ $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
+
+ /* @var $phpbb_hook_finder \phpbb\hook\finder */
+ $phpbb_hook_finder = $phpbb_container->get('hook_finder');
+ foreach ($phpbb_hook_finder->find() as $hook)
+ {
+ @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
+ }
+}
+else
+{
+ $phpbb_hook = false;
+}
+
+header('Content-type: text/html; charset=UTF-8');
+?>
+<!DOCTYPE html>
+<html dir="<?php echo $user->lang['DIRECTION']; ?>" lang="<?php echo $user->lang['USER_LANG']; ?>">
+<head>
+<meta charset="utf-8">
+
+<title><?php echo $user->lang['UPDATING_TO_LATEST_STABLE']; ?></title>
+
+<link href="<?php echo htmlspecialchars($phpbb_admin_path); ?>style/admin.css" rel="stylesheet" type="text/css" media="screen" />
+
+</head>
+
+<body>
+ <div id="wrap">
+ <div id="page-header">&nbsp;</div>
+
+ <div id="page-body">
+ <div id="acp">
+ <div class="panel">
+ <span class="corners-top"><span></span></span>
+ <div id="content">
+ <div id="main" class="install-body">
+
+ <h1><?php echo $user->lang['UPDATING_TO_LATEST_STABLE']; ?></h1>
+
+ <br />
+
+ <p><?php echo $user->lang['DATABASE_TYPE']; ?> :: <strong><?php echo $db->get_sql_layer(); ?></strong><br />
+ <?php echo $user->lang['PREVIOUS_VERSION']; ?> :: <strong><?php echo $config['version']; ?></strong><br />
+
+<?php
+
+define('IN_DB_UPDATE', true);
+
+/**
+* @todo mysql update?
+*/
+
+// End startup code
+
+/* @var $migrator \phpbb\db\migrator */
+$migrator = $phpbb_container->get('migrator');
+
+/** @var \phpbb\filesystem\filesystem_interface $phpbb_filesystem */
+$phpbb_filesystem = $phpbb_container->get('filesystem');
+$migrator->set_output_handler(new \phpbb\db\log_wrapper_migrator_output_handler($user, new \phpbb\db\html_migrator_output_handler($user), $phpbb_root_path . 'store/migrations_' . time() . '.log', $phpbb_filesystem));
+
+$migrator->create_migrations_table();
+
+/* @var $phpbb_extension_manager \phpbb\extension\manager */
+$phpbb_extension_manager = $phpbb_container->get('ext.manager');
+
+$migrations = $phpbb_extension_manager
+ ->get_finder()
+ ->core_path('phpbb/db/migration/data/')
+ ->extension_directory('/migrations')
+ ->get_classes();
+
+$migrator->set_migrations($migrations);
+
+// What is a safe limit of execution time? Half the max execution time should be safe.
+// No more than 15 seconds so the user isn't sitting and waiting for a very long time
+$phpbb_ini = new \phpbb\php\ini();
+$safe_time_limit = min(15, ($phpbb_ini->get_int('max_execution_time') / 2));
+
+// While we're going to try limit this to half the max execution time,
+// we want to try and take additional measures to prevent hitting the
+// max execution time (if, say, one migration step takes much longer
+// than the max execution time)
+@set_time_limit(0);
+
+while (!$migrator->finished())
+{
+ try
+ {
+ $migrator->update();
+ }
+ catch (\phpbb\db\migration\exception $e)
+ {
+ echo $e->getLocalisedMessage($user);
+
+ phpbb_end_update($cache, $config);
+ }
+
+ $state = array_merge(array(
+ 'migration_schema_done' => false,
+ 'migration_data_done' => false,
+ ),
+ $migrator->last_run_migration['state']
+ );
+
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $update_start_time) >= $safe_time_limit)
+ {
+ echo '<br />' . $user->lang['DATABASE_UPDATE_NOT_COMPLETED'] . '<br /><br />';
+ echo '<a href="' . append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=' . $request->variable('type', 0) . '&amp;language=' . $request->variable('language', 'en')) . '" class="button1">' . $user->lang['DATABASE_UPDATE_CONTINUE'] . '</a>';
+
+ phpbb_end_update($cache, $config);
+ }
+}
+
+if ($orig_version != $config['version'])
+{
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UPDATE_DATABASE', false, array($orig_version, $config['version']));
+}
+
+echo $user->lang['DATABASE_UPDATE_COMPLETE'] . '<br />';
+
+if ($request->variable('type', 0))
+{
+ echo $user->lang['INLINE_UPDATE_SUCCESSFUL'] . '<br /><br />';
+ echo '<a href="' . append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update&amp;sub=update_db&amp;language=' . $request->variable('language', 'en')) . '" class="button1">' . $user->lang['CONTINUE_UPDATE_NOW'] . '</a>';
+}
+else
+{
+ echo '<div class="errorbox">' . $user->lang['UPDATE_FILES_NOTICE'] . '</div>';
+ echo $user->lang['COMPLETE_LOGIN_TO_BOARD'];
+}
+
+$config->delete('version_update_from');
+
+phpbb_end_update($cache, $config);
diff --git a/phpBB/install_old/index.php b/phpBB/install_old/index.php
new file mode 100644
index 0000000000..3559a10971
--- /dev/null
+++ b/phpBB/install_old/index.php
@@ -0,0 +1,867 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**#@+
+* @ignore
+*/
+define('IN_PHPBB', true);
+define('IN_INSTALL', true);
+define('PHPBB_ENVIRONMENT', 'production');
+/**#@-*/
+
+$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
+$phpEx = substr(strrchr(__FILE__, '.'), 1);
+
+if (version_compare(PHP_VERSION, '5.3.9') < 0)
+{
+ die('You are running an unsupported PHP version. Please upgrade to PHP 5.3.9 or higher before trying to install phpBB 3.1');
+}
+
+function phpbb_require_updated($path, $optional = false)
+{
+ global $phpbb_root_path, $table_prefix;
+
+ $new_path = $phpbb_root_path . 'install/update/new/' . $path;
+ $old_path = $phpbb_root_path . $path;
+
+ if (file_exists($new_path))
+ {
+ require($new_path);
+ }
+ else if (!$optional || file_exists($old_path))
+ {
+ require($old_path);
+ }
+}
+
+function phpbb_include_updated($path, $optional = false)
+{
+ global $phpbb_root_path;
+
+ $new_path = $phpbb_root_path . 'install/update/new/' . $path;
+ $old_path = $phpbb_root_path . $path;
+
+ if (file_exists($new_path))
+ {
+ include($new_path);
+ }
+ else if (!$optional || file_exists($old_path))
+ {
+ include($old_path);
+ }
+}
+
+phpbb_require_updated('includes/startup.' . $phpEx);
+
+// Try to override some limits - maybe it helps some...
+@set_time_limit(0);
+$mem_limit = @ini_get('memory_limit');
+if (!empty($mem_limit))
+{
+ $unit = strtolower(substr($mem_limit, -1, 1));
+ $mem_limit = (int) $mem_limit;
+
+ if ($unit == 'k')
+ {
+ $mem_limit = floor($mem_limit / 1024);
+ }
+ else if ($unit == 'g')
+ {
+ $mem_limit *= 1024;
+ }
+ else if (is_numeric($unit))
+ {
+ $mem_limit = floor((int) ($mem_limit . $unit) / 1048576);
+ }
+ $mem_limit = max(128, $mem_limit) . 'M';
+}
+else
+{
+ $mem_limit = '128M';
+}
+@ini_set('memory_limit', $mem_limit);
+
+// In case $phpbb_adm_relative_path is not set (in case of an update), use the default.
+$phpbb_adm_relative_path = (isset($phpbb_adm_relative_path)) ? $phpbb_adm_relative_path : 'adm/';
+$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : $phpbb_root_path . $phpbb_adm_relative_path;
+
+// Include essential scripts
+phpbb_require_updated('phpbb/class_loader.' . $phpEx);
+
+phpbb_require_updated('includes/functions.' . $phpEx);
+
+phpbb_require_updated('includes/functions_content.' . $phpEx, true);
+
+phpbb_include_updated('includes/functions_admin.' . $phpEx);
+phpbb_include_updated('includes/utf/utf_tools.' . $phpEx);
+phpbb_require_updated('includes/functions_install.' . $phpEx);
+
+// Setup class loader first
+$phpbb_class_loader_new = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}install/update/new/phpbb/", $phpEx);
+$phpbb_class_loader_new->register();
+$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
+$phpbb_class_loader->register();
+$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
+$phpbb_class_loader_ext->register();
+
+// Set up container
+$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
+$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+$phpbb_container_builder
+ ->without_extensions()
+ ->without_cache()
+ ->without_compiled_container()
+;
+
+$other_config_path = $phpbb_root_path . 'install/update/new/config/';
+$config_path = file_exists($other_config_path . 'services.yml') ? $other_config_path : $phpbb_root_path . 'config/';
+$phpbb_container_builder->with_config_path($config_path);
+
+$phpbb_container_builder->with_custom_parameters(array(
+ 'core.root_path' => $phpbb_root_path,
+ 'core.adm_relative_path' => $phpbb_adm_relative_path,
+ 'core.php_ext' => $phpEx,
+ 'core.table_prefix' => '',
+ 'cache.driver.class' => 'phpbb\cache\driver\file',
+));
+
+$phpbb_container = $phpbb_container_builder->get_container();
+$phpbb_container->register('dbal.conn.driver')->setSynthetic(true);
+$phpbb_container->register('template.twig.environment')->setSynthetic(true);
+$phpbb_container->register('language.loader')->setSynthetic(true);
+$phpbb_container->compile();
+
+$phpbb_class_loader->set_cache($phpbb_container->get('cache.driver'));
+$phpbb_class_loader_ext->set_cache($phpbb_container->get('cache.driver'));
+
+/* @var $phpbb_dispatcher \phpbb\event\dispatcher */
+$phpbb_dispatcher = $phpbb_container->get('dispatcher');
+
+/* @var $request \phpbb\request\request_interface */
+$request = $phpbb_container->get('request');
+
+// Try and load an appropriate language if required
+$language = basename($request->variable('language', ''));
+
+if ($request->header('Accept-Language') && !$language)
+{
+ $accept_lang_ary = explode(',', strtolower($request->header('Accept-Language')));
+ foreach ($accept_lang_ary as $accept_lang)
+ {
+ // Set correct format ... guess full xx_yy form
+ $accept_lang = substr($accept_lang, 0, 2) . '_' . substr($accept_lang, 3, 2);
+
+ if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang))
+ {
+ $language = $accept_lang;
+ break;
+ }
+ else
+ {
+ // No match on xx_yy so try xx
+ $accept_lang = substr($accept_lang, 0, 2);
+ if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang))
+ {
+ $language = $accept_lang;
+ break;
+ }
+ }
+ }
+}
+
+// No appropriate language found ... so let's use the first one in the language
+// dir, this may or may not be English
+if (!$language)
+{
+ $dir = @opendir($phpbb_root_path . 'language');
+
+ if (!$dir)
+ {
+ die('Unable to access the language directory');
+ exit;
+ }
+
+ while (($file = readdir($dir)) !== false)
+ {
+ $path = $phpbb_root_path . 'language/' . $file;
+
+ if (!is_file($path) && !is_link($path) && file_exists($path . '/iso.txt'))
+ {
+ $language = $file;
+ break;
+ }
+ }
+ closedir($dir);
+}
+
+if (!file_exists($phpbb_root_path . 'language/' . $language) || !is_dir($phpbb_root_path . 'language/' . $language))
+{
+ die('No language found!');
+}
+
+// And finally, load the relevant language files
+$load_lang_files = array('common', 'acp/common', 'acp/board', 'install', 'posting');
+$new_path = $phpbb_root_path . 'install/update/new/language/' . $language . '/';
+$old_path = $phpbb_root_path . 'language/' . $language . '/';
+
+// NOTE: we can not use "phpbb_include_updated" as the files uses vars which would be required
+// to be global while loading.
+foreach ($load_lang_files as $lang_file)
+{
+ if (file_exists($new_path . $lang_file . '.' . $phpEx))
+ {
+ include($new_path . $lang_file . '.' . $phpEx);
+ }
+ else
+ {
+ include($old_path . $lang_file . '.' . $phpEx);
+ }
+}
+
+// usually we would need every single constant here - and it would be consistent. For 3.0.x, use a dirty hack... :(
+
+// Define needed constants
+define('CHMOD_ALL', 7);
+define('CHMOD_READ', 4);
+define('CHMOD_WRITE', 2);
+define('CHMOD_EXECUTE', 1);
+
+$mode = $request->variable('mode', 'overview');
+$sub = $request->variable('sub', '');
+
+// Set PHP error handler to ours
+set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
+
+$lang_service = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+$user = new \phpbb\user($lang_service, '\phpbb\datetime');
+$auth = new \phpbb\auth\auth();
+
+// Add own hook handler, if present. :o
+if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
+{
+ require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
+ $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
+
+ /* @var $phpbb_hook_finder \phpbb\hook\finder */
+ $phpbb_hook_finder = $phpbb_container->get('hook_finder');
+ foreach ($phpbb_hook_finder->find() as $hook)
+ {
+ @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
+ }
+}
+else
+{
+ $phpbb_hook = false;
+}
+
+// Set some standard variables we want to force
+$config = new \phpbb\config\config(array(
+ 'load_tplcompile' => '1'
+));
+
+/* @var $symfony_request \phpbb\symfony_request */
+$symfony_request = $phpbb_container->get('symfony_request');
+
+/* @var $phpbb_filesystem \phpbb\filesystem\filesystem_interface */
+$phpbb_filesystem = $phpbb_container->get('filesystem');
+
+/* @var $phpbb_path_helper \phpbb\path_helper */
+$phpbb_path_helper = $phpbb_container->get('path_helper');
+$cache_path = $phpbb_root_path . 'cache/';
+
+$twig_environment = new \phpbb\template\twig\environment(
+ $config,
+ $phpbb_filesystem,
+ $phpbb_path_helper,
+ $phpbb_container,
+ $cache_path,
+ null,
+ $phpbb_container->get('template.twig.loader')
+);
+
+$language_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+$phpbb_container->set('template.twig.environment', $twig_environment);
+$phpbb_container->set('language.loader', $language_loader);
+$twig_context = new \phpbb\template\context();
+$template = new \phpbb\template\twig\twig(
+ $phpbb_path_helper,
+ $config,
+ $twig_context,
+ $twig_environment,
+ $cache_path,
+ $user,
+ array($phpbb_container->get('template.twig.extensions.phpbb'))
+);
+
+$paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
+$paths = array_filter($paths, 'is_dir');
+$template->set_custom_style(array(
+ array(
+ 'name' => 'adm',
+ 'ext_path' => 'adm/style/',
+ ),
+), $paths);
+
+$path = array_shift($paths);
+
+$template->assign_var('T_ASSETS_PATH', $path . '/../../assets');
+$template->assign_var('T_TEMPLATE_PATH', $path);
+
+$install = new module();
+
+$install->create('install', "index.$phpEx", $mode, $sub);
+$install->load();
+
+// Generate the page
+$install->page_header();
+$install->generate_navigation();
+
+$template->set_filenames(array(
+ 'body' => $install->get_tpl_name())
+);
+
+$install->page_footer();
+
+class module
+{
+ var $id = 0;
+ var $type = 'install';
+ var $module_ary = array();
+ var $filename;
+ var $module_url = '';
+ var $tpl_name = '';
+ var $mode;
+ var $sub;
+
+ /**
+ * Private methods, should not be overwritten
+ */
+ function create($module_type, $module_url, $selected_mod = false, $selected_submod = false)
+ {
+ global $db, $config, $phpEx, $phpbb_root_path;
+
+ $module = array();
+
+ // Grab module information using Bart's "neat-o-module" system (tm)
+ $dir = @opendir('.');
+
+ if (!$dir)
+ {
+ $this->error('Unable to access the installation directory', __LINE__, __FILE__);
+ }
+
+ $setmodules = 1;
+ while (($file = readdir($dir)) !== false)
+ {
+ if (preg_match('#^install_(.*?)\.' . $phpEx . '$#', $file))
+ {
+ include($file);
+ }
+ }
+ closedir($dir);
+
+ unset($setmodules);
+
+ if (!sizeof($module))
+ {
+ $this->error('No installation modules found', __LINE__, __FILE__);
+ }
+
+ // Order to use and count further if modules get assigned to the same position or not having an order
+ $max_module_order = 1000;
+
+ foreach ($module as $row)
+ {
+ // Module order not specified or module already assigned at this position?
+ if (!isset($row['module_order']) || isset($this->module_ary[$row['module_order']]))
+ {
+ $row['module_order'] = $max_module_order;
+ $max_module_order++;
+ }
+
+ $this->module_ary[$row['module_order']]['name'] = $row['module_title'];
+ $this->module_ary[$row['module_order']]['filename'] = $row['module_filename'];
+ $this->module_ary[$row['module_order']]['subs'] = $row['module_subs'];
+ $this->module_ary[$row['module_order']]['stages'] = $row['module_stages'];
+
+ if (strtolower($selected_mod) == strtolower($row['module_title']))
+ {
+ $this->id = (int) $row['module_order'];
+ $this->filename = (string) $row['module_filename'];
+ $this->module_url = (string) $module_url;
+ $this->mode = (string) $selected_mod;
+ // Check that the sub-mode specified is valid or set a default if not
+ if (is_array($row['module_subs']))
+ {
+ $this->sub = strtolower((in_array(strtoupper($selected_submod), $row['module_subs'])) ? $selected_submod : $row['module_subs'][0]);
+ }
+ else if (is_array($row['module_stages']))
+ {
+ $this->sub = strtolower((in_array(strtoupper($selected_submod), $row['module_stages'])) ? $selected_submod : $row['module_stages'][0]);
+ }
+ else
+ {
+ $this->sub = '';
+ }
+ }
+ } // END foreach
+ } // END create
+
+ /**
+ * Load and run the relevant module if applicable
+ */
+ function load($mode = false, $run = true)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ if ($run)
+ {
+ if (!empty($mode))
+ {
+ $this->mode = $mode;
+ }
+
+ $module = $this->filename;
+ if (!class_exists($module))
+ {
+ $this->error('Module "' . htmlspecialchars($module) . '" not accessible.', __LINE__, __FILE__);
+ }
+ $this->module = new $module($this);
+
+ if (method_exists($this->module, 'main'))
+ {
+ $this->module->main($this->mode, $this->sub);
+ }
+ }
+ }
+
+ /**
+ * Output the standard page header
+ */
+ function page_header()
+ {
+ if (defined('HEADER_INC'))
+ {
+ return;
+ }
+
+ define('HEADER_INC', true);
+ global $template, $lang, $stage, $phpbb_admin_path, $path;
+
+ $template->assign_vars(array(
+ 'L_CHANGE' => $lang['CHANGE'],
+ 'L_COLON' => $lang['COLON'],
+ 'L_INSTALL_PANEL' => $lang['INSTALL_PANEL'],
+ 'L_SELECT_LANG' => $lang['SELECT_LANG'],
+ 'L_SKIP' => $lang['SKIP'],
+ 'PAGE_TITLE' => $this->get_page_title(),
+ 'T_IMAGE_PATH' => htmlspecialchars($phpbb_admin_path) . 'images/',
+ 'T_JQUERY_LINK' => $path . '/../../assets/javascript/jquery.min.js',
+
+ 'S_CONTENT_DIRECTION' => $lang['DIRECTION'],
+ 'S_CONTENT_FLOW_BEGIN' => ($lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
+ 'S_CONTENT_FLOW_END' => ($lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
+ 'S_CONTENT_ENCODING' => 'UTF-8',
+
+ 'S_USER_LANG' => $lang['USER_LANG'],
+ )
+ );
+
+ header('Content-type: text/html; charset=UTF-8');
+ header('Cache-Control: private, no-cache="set-cookie"');
+ header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
+
+ return;
+ }
+
+ /**
+ * Output the standard page footer
+ */
+ function page_footer()
+ {
+ global $db, $template;
+
+ $template->display('body');
+
+ // Close our DB connection.
+ if (!empty($db) && is_object($db))
+ {
+ $db->sql_close();
+ }
+
+ if (function_exists('exit_handler'))
+ {
+ exit_handler();
+ }
+ }
+
+ /**
+ * Returns desired template name
+ */
+ function get_tpl_name()
+ {
+ return $this->module->tpl_name . '.html';
+ }
+
+ /**
+ * Returns the desired page title
+ */
+ function get_page_title()
+ {
+ global $lang;
+
+ if (!isset($this->module->page_title))
+ {
+ return '';
+ }
+
+ return (isset($lang[$this->module->page_title])) ? $lang[$this->module->page_title] : $this->module->page_title;
+ }
+
+ /**
+ * Generate an HTTP/1.1 header to redirect the user to another page
+ * This is used during the installation when we do not have a database available to call the normal redirect function
+ * @param string $page The page to redirect to relative to the installer root path
+ */
+ function redirect($page)
+ {
+ global $request;
+
+ // HTTP_HOST is having the correct browser url in most cases...
+ $server_name = strtolower(htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))));
+ $server_port = $request->server('SERVER_PORT', 0);
+ $secure = $request->is_secure() ? 1 : 0;
+
+ $script_name = htmlspecialchars_decode($request->server('PHP_SELF'));
+ if (!$script_name)
+ {
+ $script_name = htmlspecialchars_decode($request->server('REQUEST_URI'));
+ }
+
+ // Replace backslashes and doubled slashes (could happen on some proxy setups)
+ $script_name = str_replace(array('\\', '//'), '/', $script_name);
+ $script_path = trim(dirname($script_name));
+
+ $url = (($secure) ? 'https://' : 'http://') . $server_name;
+
+ if ($server_port && (($secure && $server_port <> 443) || (!$secure && $server_port <> 80)))
+ {
+ // HTTP HOST can carry a port number...
+ if (strpos($server_name, ':') === false)
+ {
+ $url .= ':' . $server_port;
+ }
+ }
+
+ $url .= $script_path . '/' . $page;
+ header('Location: ' . $url);
+ exit;
+ }
+
+ /**
+ * Generate the navigation tabs
+ */
+ function generate_navigation()
+ {
+ global $lang, $template, $phpEx, $language;
+
+ if (is_array($this->module_ary))
+ {
+ @ksort($this->module_ary);
+ foreach ($this->module_ary as $cat_ary)
+ {
+ $cat = $cat_ary['name'];
+ $l_cat = (!empty($lang['CAT_' . $cat])) ? $lang['CAT_' . $cat] : preg_replace('#_#', ' ', $cat);
+ $cat = strtolower($cat);
+ $url = $this->module_url . "?mode=$cat&amp;language=$language";
+
+ if ($this->mode == $cat)
+ {
+ $template->assign_block_vars('t_block1', array(
+ 'L_TITLE' => $l_cat,
+ 'S_SELECTED' => true,
+ 'U_TITLE' => $url,
+ ));
+
+ if (is_array($this->module_ary[$this->id]['subs']))
+ {
+ $subs = $this->module_ary[$this->id]['subs'];
+ foreach ($subs as $option)
+ {
+ $l_option = (!empty($lang['SUB_' . $option])) ? $lang['SUB_' . $option] : preg_replace('#_#', ' ', $option);
+ $option = strtolower($option);
+ $url = $this->module_url . '?mode=' . $this->mode . "&amp;sub=$option&amp;language=$language";
+
+ $template->assign_block_vars('l_block1', array(
+ 'L_TITLE' => $l_option,
+ 'S_SELECTED' => ($this->sub == $option),
+ 'U_TITLE' => $url,
+ ));
+ }
+ }
+
+ if (is_array($this->module_ary[$this->id]['stages']))
+ {
+ $subs = $this->module_ary[$this->id]['stages'];
+ $matched = false;
+ foreach ($subs as $option)
+ {
+ $l_option = (!empty($lang['STAGE_' . $option])) ? $lang['STAGE_' . $option] : preg_replace('#_#', ' ', $option);
+ $option = strtolower($option);
+ $matched = ($this->sub == $option) ? true : $matched;
+
+ $template->assign_block_vars('l_block2', array(
+ 'L_TITLE' => $l_option,
+ 'S_SELECTED' => ($this->sub == $option),
+ 'S_COMPLETE' => !$matched,
+ ));
+ }
+ }
+ }
+ else
+ {
+ $template->assign_block_vars('t_block1', array(
+ 'L_TITLE' => $l_cat,
+ 'S_SELECTED' => false,
+ 'U_TITLE' => $url,
+ ));
+ }
+ }
+ }
+ }
+
+ /**
+ * Output an error message
+ * If skip is true, return and continue execution, else exit
+ */
+ function error($error, $line, $file, $skip = false)
+ {
+ global $lang, $db, $template, $phpbb_admin_path;
+
+ if ($skip)
+ {
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $lang['INST_ERR'],
+ ));
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => basename($file) . ' [ ' . $line . ' ]',
+ 'RESULT' => '<b style="color:red">' . $error . '</b>',
+ ));
+
+ return;
+ }
+
+ echo '<!DOCTYPE html>';
+ echo '<html dir="ltr">';
+ echo '<head>';
+ echo '<meta charset="utf-8">';
+ echo '<title>' . $lang['INST_ERR_FATAL'] . '</title>';
+ echo '<link href="' . htmlspecialchars($phpbb_admin_path) . 'style/admin.css" rel="stylesheet" type="text/css" media="screen" />';
+ echo '</head>';
+ echo '<body id="errorpage">';
+ echo '<div id="wrap">';
+ echo ' <div id="page-header">';
+ echo ' </div>';
+ echo ' <div id="page-body">';
+ echo ' <div id="acp">';
+ echo ' <div class="panel">';
+ echo ' <span class="corners-top"><span></span></span>';
+ echo ' <div id="content">';
+ echo ' <h1>' . $lang['INST_ERR_FATAL'] . '</h1>';
+ echo ' <p>' . $lang['INST_ERR_FATAL'] . "</p>\n";
+ echo ' <p>' . basename($file) . ' [ ' . $line . " ]</p>\n";
+ echo ' <p><b>' . $error . "</b></p>\n";
+ echo ' </div>';
+ echo ' <span class="corners-bottom"><span></span></span>';
+ echo ' </div>';
+ echo ' </div>';
+ echo ' </div>';
+ echo ' <div id="page-footer">';
+ echo ' Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited';
+ echo ' </div>';
+ echo '</div>';
+ echo '</body>';
+ echo '</html>';
+
+ if (!empty($db) && is_object($db))
+ {
+ $db->sql_close();
+ }
+
+ exit_handler();
+ }
+
+ /**
+ * Output an error message for a database related problem
+ * If skip is true, return and continue execution, else exit
+ */
+ function db_error($error, $sql, $line, $file, $skip = false)
+ {
+ global $lang, $db, $template;
+
+ if ($skip)
+ {
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $lang['INST_ERR_FATAL'],
+ ));
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => basename($file) . ' [ ' . $line . ' ]',
+ 'RESULT' => '<b style="color:red">' . $error . '</b><br />&#187; SQL:' . $sql,
+ ));
+
+ return;
+ }
+
+ $template->set_filenames(array(
+ 'body' => 'install_error.html')
+ );
+ $this->page_header();
+ $this->generate_navigation();
+
+ $template->assign_vars(array(
+ 'MESSAGE_TITLE' => $lang['INST_ERR_FATAL_DB'],
+ 'MESSAGE_TEXT' => '<p>' . basename($file) . ' [ ' . $line . ' ]</p><p>SQL : ' . $sql . '</p><p><b>' . $error . '</b></p>',
+ ));
+
+ // Rollback if in transaction
+ if ($db->get_transaction())
+ {
+ $db->sql_transaction('rollback');
+ }
+
+ $this->page_footer();
+ }
+
+ /**
+ * Generate the relevant HTML for an input field and the associated label and explanatory text
+ */
+ function input_field($name, $type, $value = '', $options = '')
+ {
+ global $lang;
+ $tpl_type = explode(':', $type);
+ $tpl = '';
+
+ switch ($tpl_type[0])
+ {
+ case 'text':
+ case 'password':
+ // HTML5 text-like input types
+ case 'color':
+ case 'date':
+ case 'time':
+ case 'datetime':
+ case 'datetime-local':
+ case 'email':
+ case 'month':
+ case 'number':
+ case 'range':
+ case 'search':
+ case 'tel':
+ case 'url':
+ case 'week':
+
+ $size = (int) $tpl_type[1];
+ $maxlength = (int) $tpl_type[2];
+ $autocomplete = (isset($options['autocomplete']) && $options['autocomplete'] == 'off') ? ' autocomplete="off"' : '';
+
+ $tpl = '<input id="' . $name . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '"' . $autocomplete . ' value="' . $value . '" />';
+ break;
+
+ case 'textarea':
+ $rows = (int) $tpl_type[1];
+ $cols = (int) $tpl_type[2];
+
+ $tpl = '<textarea id="' . $name . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $value . '</textarea>';
+ break;
+
+ case 'radio':
+ $key_yes = ($value) ? ' checked="checked" id="' . $name . '"' : '';
+ $key_no = (!$value) ? ' checked="checked" id="' . $name . '"' : '';
+
+ $tpl_type_cond = explode('_', $tpl_type[1]);
+ $type_no = ($tpl_type_cond[0] == 'disabled' || $tpl_type_cond[0] == 'enabled') ? false : true;
+
+ $tpl_no = '<label><input type="radio" name="' . $name . '" value="0"' . $key_no . ' class="radio" /> ' . (($type_no) ? $lang['NO'] : $lang['DISABLED']) . '</label>';
+ $tpl_yes = '<label><input type="radio" name="' . $name . '" value="1"' . $key_yes . ' class="radio" /> ' . (($type_no) ? $lang['YES'] : $lang['ENABLED']) . '</label>';
+
+ $tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . '&nbsp;&nbsp;' . $tpl_no : $tpl_no . '&nbsp;&nbsp;' . $tpl_yes;
+ break;
+
+ case 'select':
+ // @codingStandardsIgnoreStart
+ eval('$s_options = ' . str_replace('{VALUE}', $value, $options) . ';');
+ // @codingStandardsIgnoreEnd
+ $tpl = '<select id="' . $name . '" name="' . $name . '">' . $s_options . '</select>';
+ break;
+
+ case 'custom':
+ // @codingStandardsIgnoreStart
+ eval('$tpl = ' . str_replace('{VALUE}', $value, $options) . ';');
+ // @codingStandardsIgnoreEnd
+ break;
+
+ default:
+ break;
+ }
+
+ return $tpl;
+ }
+
+ /**
+ * Generate the drop down of available language packs
+ */
+ function inst_language_select($default = '')
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $dir = @opendir($phpbb_root_path . 'language');
+
+ if (!$dir)
+ {
+ $this->error('Unable to access the language directory', __LINE__, __FILE__);
+ }
+
+ while ($file = readdir($dir))
+ {
+ $path = $phpbb_root_path . 'language/' . $file;
+
+ if ($file == '.' || $file == '..' || is_link($path) || is_file($path) || $file == 'CVS')
+ {
+ continue;
+ }
+
+ if (file_exists($path . '/iso.txt'))
+ {
+ list($displayname, $localname) = @file($path . '/iso.txt');
+ $lang[$localname] = $file;
+ }
+ }
+ closedir($dir);
+
+ @asort($lang);
+ @reset($lang);
+
+ $user_select = '';
+ foreach ($lang as $displayname => $filename)
+ {
+ $selected = (strtolower($default) == strtolower($filename)) ? ' selected="selected"' : '';
+ $user_select .= '<option value="' . $filename . '"' . $selected . '>' . ucwords($displayname) . '</option>';
+ }
+
+ return $user_select;
+ }
+}
diff --git a/phpBB/install_old/install_convert.php b/phpBB/install_old/install_convert.php
new file mode 100644
index 0000000000..d72ee1a633
--- /dev/null
+++ b/phpBB/install_old/install_convert.php
@@ -0,0 +1,2153 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+*/
+
+if (!defined('IN_INSTALL'))
+{
+ // Someone has tried to access the file direct. This is not a good idea, so exit
+ exit;
+}
+
+if (!empty($setmodules))
+{
+ $module[] = array(
+ 'module_type' => 'install',
+ 'module_title' => 'CONVERT',
+ 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
+ 'module_order' => 20,
+ 'module_subs' => '',
+ 'module_stages' => array('INTRO', 'SETTINGS', 'IN_PROGRESS', 'FINAL'),
+ 'module_reqs' => ''
+ );
+}
+
+/**
+* Class holding all convertor-specific details.
+*/
+class convert
+{
+ var $options = array();
+
+ var $convertor_tag = '';
+ var $src_dbms = '';
+ var $src_dbhost = '';
+ var $src_dbport = '';
+ var $src_dbuser = '';
+ var $src_dbpasswd = '';
+ var $src_dbname = '';
+ var $src_table_prefix = '';
+
+ var $convertor_data = array();
+ var $tables = array();
+ var $config_schema = array();
+ var $convertor = array();
+ var $src_truncate_statement = 'DELETE FROM ';
+ var $truncate_statement = 'DELETE FROM ';
+
+ var $fulltext_search;
+
+ // Batch size, can be adjusted by the conversion file
+ // For big boards a value of 6000 seems to be optimal
+ var $batch_size = 2000;
+ // Number of rows to be inserted at once (extended insert) if supported
+ // For installations having enough memory a value of 60 may be good.
+ var $num_wait_rows = 20;
+
+ // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
+ var $mysql_convert = false;
+
+ var $p_master;
+
+ function convert(&$p_master)
+ {
+ $this->p_master = &$p_master;
+ }
+}
+
+/**
+* Convert class for conversions
+*/
+class install_convert extends module
+{
+ /** @var array */
+ protected $lang;
+
+ /** @var string */
+ protected $language;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var string */
+ protected $phpbb_root_path;
+
+ /** @var string */
+ protected $php_ext;
+
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ /**
+ * Variables used while converting, they are accessible from the global variable $convert
+ */
+ function install_convert(&$p_master)
+ {
+ $this->p_master = &$p_master;
+ }
+
+ function main($mode, $sub)
+ {
+ global $lang, $template, $phpbb_root_path, $phpEx, $cache, $config, $language, $table_prefix;
+ global $convert, $request, $phpbb_container, $phpbb_config_php_file;
+
+ $this->tpl_name = 'install_convert';
+ $this->mode = $mode;
+ $this->lang = $lang;
+ $this->language = $language;
+ $this->template = $template;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $phpEx;
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+
+ if (!$this->check_phpbb_installed())
+ {
+ return;
+ }
+
+ $convert = new convert($this->p_master);
+
+ // Enable super globals to prevent issues with the new \phpbb\request\request object
+ $request->enable_super_globals();
+ // Create a normal container now
+ $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $phpbb_container = $phpbb_container_builder->with_config($phpbb_config_php_file)->get_container();
+
+ // Create cache
+ /* @var $cache \phpbb\cache\service */
+ $cache = $phpbb_container->get('cache');
+
+ switch ($sub)
+ {
+ case 'intro':
+ extract($phpbb_config_php_file->get_all());
+
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
+ unset($dbpasswd);
+
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy, CONFIG_TABLE);
+
+ // Detect if there is already a conversion in progress at this point and offer to resume
+ // It's quite possible that the user will get disconnected during a large conversion so they need to be able to resume it
+ $new_conversion = $request->variable('new_conv', 0);
+
+ if ($new_conversion)
+ {
+ $config['convert_progress'] = '';
+ $config['convert_db_server'] = '';
+ $config['convert_db_user'] = '';
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
+ WHERE config_name = 'convert_progress'
+ OR config_name = 'convert_db_server'
+ OR config_name = 'convert_db_user'"
+ );
+ }
+
+ // Let's see if there is a conversion in the works...
+ $options = array();
+ if (!empty($config['convert_progress']) && !empty($config['convert_db_server']) && !empty($config['convert_db_user']) && !empty($config['convert_options']))
+ {
+ $options = unserialize($config['convert_progress']);
+ $options = array_merge($options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (!empty($options) && !empty($options['tag']) &&
+ isset($options['dbms']) &&
+ isset($options['dbhost']) &&
+ isset($options['dbport']) &&
+ isset($options['dbuser']) &&
+ isset($options['dbpasswd']) &&
+ isset($options['dbname']) &&
+ isset($options['table_prefix']))
+ {
+ $this->page_title = $lang['CONTINUE_CONVERT'];
+
+ $template->assign_vars(array(
+ 'TITLE' => $lang['CONTINUE_CONVERT'],
+ 'BODY' => $lang['CONTINUE_CONVERT_BODY'],
+ 'L_NEW' => $lang['CONVERT_NEW_CONVERSION'],
+ 'L_CONTINUE' => $lang['CONTINUE_OLD_CONVERSION'],
+ 'S_CONTINUE' => true,
+
+ 'U_NEW_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=intro&amp;new_conv=1&amp;language=$language",
+ 'U_CONTINUE_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$options['tag']}{$options['step']}&amp;language=$language",
+ ));
+
+ return;
+ }
+
+ $this->list_convertors($sub);
+
+ break;
+
+ case 'settings':
+ $this->get_convert_settings($sub);
+ break;
+
+ case 'in_progress':
+ $this->convert_data($sub);
+ break;
+
+ case 'final':
+ $this->page_title = $lang['CONVERT_COMPLETE'];
+
+ $template->assign_vars(array(
+ 'TITLE' => $lang['CONVERT_COMPLETE'],
+ 'BODY' => $lang['CONVERT_COMPLETE_EXPLAIN'],
+ ));
+
+ // If we reached this step (conversion completed) we want to purge the cache and log the user out.
+ // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
+ $cache->purge();
+
+ extract($phpbb_config_php_file->get_all());
+
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
+ unset($dbpasswd);
+
+ $sql = 'SELECT config_value
+ FROM ' . CONFIG_TABLE . '
+ WHERE config_name = \'search_type\'';
+ $result = $db->sql_query($sql);
+
+ if ($db->sql_fetchfield('config_value') != 'fulltext_mysql')
+ {
+ $template->assign_vars(array(
+ 'S_ERROR_BOX' => true,
+ 'ERROR_TITLE' => $lang['SEARCH_INDEX_UNCONVERTED'],
+ 'ERROR_MSG' => $lang['SEARCH_INDEX_UNCONVERTED_EXPLAIN'],
+ ));
+ }
+
+ switch ($db->get_sql_layer())
+ {
+ case 'sqlite':
+ case 'sqlite3':
+ $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE);
+ $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
+ break;
+
+ default:
+ $db->sql_query('TRUNCATE TABLE ' . SESSIONS_KEYS_TABLE);
+ $db->sql_query('TRUNCATE TABLE ' . SESSIONS_TABLE);
+ break;
+ }
+
+ break;
+ }
+ }
+
+ /**
+ * Check whether phpBB is installed.
+ * Assigns error template vars if not installed.
+ *
+ * @return bool Returns true if phpBB is installed.
+ */
+ public function check_phpbb_installed()
+ {
+ if (phpbb_check_installation_exists($this->phpbb_root_path, $this->php_ext))
+ {
+ return true;
+ }
+
+ $this->page_title = 'BOARD_NOT_INSTALLED';
+ $install_url = append_sid($this->phpbb_root_path . 'install/index.' . $this->php_ext, 'mode=install&amp;language=' . $this->language);
+
+ $this->template->assign_vars(array(
+ 'S_NOT_INSTALLED' => true,
+ 'BODY' => sprintf($this->lang['BOARD_NOT_INSTALLED_EXPLAIN'], $install_url),
+ ));
+
+ return false;
+ }
+
+ /**
+ * Generate a list of all available conversion modules
+ */
+ function list_convertors($sub)
+ {
+ global $lang, $language, $template, $phpbb_root_path, $phpEx;
+
+ $this->page_title = $lang['SUB_INTRO'];
+
+ $template->assign_vars(array(
+ 'TITLE' => $lang['CONVERT_INTRO'],
+ 'BODY' => $lang['CONVERT_INTRO_BODY'],
+
+ 'L_AUTHOR' => $lang['AUTHOR'],
+ 'L_AVAILABLE_CONVERTORS' => $lang['AVAILABLE_CONVERTORS'],
+ 'L_CONVERT' => $lang['CONVERT'],
+ 'L_NO_CONVERTORS' => $lang['NO_CONVERTORS'],
+ 'L_OPTIONS' => $lang['CONVERT_OPTIONS'],
+ 'L_SOFTWARE' => $lang['SOFTWARE'],
+ 'L_VERSION' => $lang['VERSION'],
+
+ 'S_LIST' => true,
+ ));
+
+ $convertors = $sort = array();
+ $get_info = true;
+
+ $handle = @opendir('./convertors/');
+
+ if (!$handle)
+ {
+ $this->error('Unable to access the convertors directory', __LINE__, __FILE__);
+ }
+
+ while ($entry = readdir($handle))
+ {
+ if (preg_match('/^convert_([a-z0-9_]+).' . $phpEx . '$/i', $entry, $m))
+ {
+ include('./convertors/' . $entry);
+ if (isset($convertor_data))
+ {
+ $sort[strtolower($convertor_data['forum_name'])] = sizeof($convertors);
+
+ $convertors[] = array(
+ 'tag' => $m[1],
+ 'forum_name' => $convertor_data['forum_name'],
+ 'version' => $convertor_data['version'],
+ 'dbms' => $convertor_data['dbms'],
+ 'dbhost' => $convertor_data['dbhost'],
+ 'dbport' => $convertor_data['dbport'],
+ 'dbuser' => $convertor_data['dbuser'],
+ 'dbpasswd' => $convertor_data['dbpasswd'],
+ 'dbname' => $convertor_data['dbname'],
+ 'table_prefix' => $convertor_data['table_prefix'],
+ 'author' => $convertor_data['author']
+ );
+ }
+ unset($convertor_data);
+ }
+ }
+ closedir($handle);
+
+ @ksort($sort);
+
+ foreach ($sort as $void => $index)
+ {
+ $template->assign_block_vars('convertors', array(
+ 'AUTHOR' => $convertors[$index]['author'],
+ 'SOFTWARE' => $convertors[$index]['forum_name'],
+ 'VERSION' => $convertors[$index]['version'],
+
+ 'U_CONVERT' => $this->p_master->module_url . "?mode={$this->mode}&amp;language=$language&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
+ ));
+ }
+ }
+
+ /**
+ */
+ function get_convert_settings($sub)
+ {
+ global $lang, $language, $template, $db, $phpbb_root_path, $phpEx, $config, $cache, $phpbb_config_php_file;
+
+ extract($phpbb_config_php_file->get_all());
+
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
+ unset($dbpasswd);
+
+ $this->page_title = $lang['STAGE_SETTINGS'];
+
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy, CONFIG_TABLE);
+
+ $convertor_tag = $request->variable('tag', '');
+
+ if (empty($convertor_tag))
+ {
+ $this->p_master->error($lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
+ }
+ $get_info = true;
+
+ // check security implications of direct inclusion
+ $convertor_tag = basename($convertor_tag);
+ if (!file_exists('./convertors/convert_' . $convertor_tag . '.' . $phpEx))
+ {
+ $this->p_master->error($lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
+ }
+
+ include('./convertors/convert_' . $convertor_tag . '.' . $phpEx);
+
+ // The test_file is a file that should be present in the location of the old board.
+ if (!isset($test_file))
+ {
+ $this->p_master->error($lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
+ }
+
+ $submit = (isset($_POST['submit'])) ? true : false;
+
+ $src_dbms = $request->variable('src_dbms', $convertor_data['dbms']);
+ $src_dbhost = $request->variable('src_dbhost', $convertor_data['dbhost']);
+ $src_dbport = $request->variable('src_dbport', $convertor_data['dbport']);
+ $src_dbuser = $request->variable('src_dbuser', $convertor_data['dbuser']);
+ $src_dbpasswd = $request->variable('src_dbpasswd', $convertor_data['dbpasswd']);
+ $src_dbname = $request->variable('src_dbname', $convertor_data['dbname']);
+ $src_table_prefix = $request->variable('src_table_prefix', $convertor_data['table_prefix']);
+ $forum_path = $request->variable('forum_path', $convertor_data['forum_path']);
+ $refresh = $request->variable('refresh', 1);
+
+ // Default URL of the old board
+ // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
+ // -> We should convert old urls to the new relative urls format
+ // $src_url = $request->variable('src_url', 'Not in use at the moment');
+
+ // strip trailing slash from old forum path
+ $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
+
+ $error = array();
+ if ($submit)
+ {
+ if (!@file_exists('./../' . $forum_path . '/' . $test_file))
+ {
+ $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $forum_path);
+ }
+
+ $connect_test = false;
+ $available_dbms = get_available_dbms(false, true, true);
+
+ if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
+ {
+ $error[] = $lang['INST_ERR_NO_DB'];
+ $connect_test = false;
+ }
+ else
+ {
+ $connect_test = connect_check_db(true, $error, $available_dbms[$src_dbms], $src_table_prefix, $src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, true, ($src_dbms == $dbms) ? false : true, false);
+ }
+
+ // The forum prefix of the old and the new forum can only be the same if two different databases are used.
+ if ($src_table_prefix == $table_prefix && $src_dbms == $dbms && $src_dbhost == $dbhost && $src_dbport == $dbport && $src_dbname == $dbname)
+ {
+ $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
+ }
+
+ $src_dbms = $phpbb_config_php_file->convert_30_dbms_to_31($src_dbms);
+
+ // Check table prefix
+ if (!sizeof($error))
+ {
+ // initiate database connection to old db if old and new db differ
+ global $src_db, $same_db;
+ $src_db = $same_db = false;
+
+ if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
+ {
+ $src_db = new $src_dbms();
+ $src_db->sql_connect($src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, false, true);
+ $same_db = false;
+ }
+ else
+ {
+ $src_db = $db;
+ $same_db = true;
+ }
+
+ $src_db->sql_return_on_error(true);
+ $db->sql_return_on_error(true);
+
+ // Try to select one row from the first table to see if the prefix is OK
+ $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
+
+ if (!$result)
+ {
+ $prefixes = array();
+
+ $db_tools_factory = new \phpbb\db\tools\factory();
+ $db_tools = $db_tools_factory->get($src_db);
+ $tables_existing = $db_tools->sql_list_tables();
+ $tables_existing = array_map('strtolower', $tables_existing);
+ foreach ($tables_existing as $table_name)
+ {
+ compare_table($tables, $table_name, $prefixes);
+ }
+ unset($tables_existing);
+
+ foreach ($prefixes as $prefix => $count)
+ {
+ if ($count >= sizeof($tables))
+ {
+ $possible_prefix = $prefix;
+ break;
+ }
+ }
+
+ $msg = '';
+ if (!empty($convertor_data['table_prefix']))
+ {
+ $msg .= sprintf($lang['DEFAULT_PREFIX_IS'], $convertor_data['forum_name'], $convertor_data['table_prefix']);
+ }
+
+ if (!empty($possible_prefix))
+ {
+ $msg .= '<br />';
+ $msg .= ($possible_prefix == '*') ? $lang['BLANK_PREFIX_FOUND'] : sprintf($lang['PREFIX_FOUND'], $possible_prefix);
+ $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
+ }
+
+ $error[] = $msg;
+ }
+ $src_db->sql_freeresult($result);
+ $src_db->sql_return_on_error(false);
+ }
+
+ if (!sizeof($error))
+ {
+ // Save convertor Status
+ $config->set('convert_progress', serialize(array(
+ 'step' => '',
+ 'table_prefix' => $src_table_prefix,
+ 'tag' => $convertor_tag,
+ )), false);
+ $config->set('convert_db_server', serialize(array(
+ 'dbms' => $src_dbms,
+ 'dbhost' => $src_dbhost,
+ 'dbport' => $src_dbport,
+ 'dbname' => $src_dbname,
+ )), false);
+ $config->set('convert_db_user', serialize(array(
+ 'dbuser' => $src_dbuser,
+ 'dbpasswd' => $src_dbpasswd,
+ )), false);
+
+ // Save options
+ $config->set('convert_options', serialize(array(
+ 'forum_path' => './../' . $forum_path,
+ 'refresh' => $refresh
+ )), false);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $lang['VERIFY_OPTIONS'],
+ 'RESULT' => $lang['CONVERT_SETTINGS_VERIFIED'],
+ ));
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $lang['BEGIN_CONVERT'],
+// 'S_HIDDEN' => $s_hidden_fields,
+ 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag=$convertor_tag&amp;language=$language",
+ ));
+
+ return;
+ }
+ else
+ {
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $lang['VERIFY_OPTIONS'],
+ 'RESULT' => '<b style="color:red">' . implode('<br />', $error) . '</b>',
+ ));
+ }
+ } // end submit
+
+ foreach ($this->convert_options as $config_key => $vars)
+ {
+ if (!is_array($vars) && strpos($config_key, 'legend') === false)
+ {
+ continue;
+ }
+
+ if (strpos($config_key, 'legend') !== false)
+ {
+ $template->assign_block_vars('options', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $lang[$vars])
+ );
+
+ continue;
+ }
+
+ $options = isset($vars['options']) ? $vars['options'] : '';
+
+ $template->assign_block_vars('options', array(
+ 'KEY' => $config_key,
+ 'TITLE' => $lang[$vars['lang']],
+ 'S_EXPLAIN' => $vars['explain'],
+ 'S_LEGEND' => false,
+ 'TITLE_EXPLAIN' => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
+ 'CONTENT' => $this->p_master->input_field($config_key, $vars['type'], ${$config_key}, $options),
+ )
+ );
+ }
+
+ $template->assign_vars(array(
+ 'TITLE' => $lang['STAGE_SETTINGS'],
+ 'BODY' => $lang['CONV_OPTIONS_BODY'],
+ 'L_SUBMIT' => $lang['BEGIN_CONVERT'],
+ 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=settings&amp;tag=$convertor_tag&amp;language=$language",
+ ));
+ }
+
+ /**
+ * The function which does the actual work (or dispatches it to the relevant places)
+ */
+ function convert_data($sub)
+ {
+ global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
+ global $convert, $convert_row, $message_parser, $skip_rows, $language;
+ global $request, $phpbb_config_php_file, $phpbb_dispatcher;
+
+ extract($phpbb_config_php_file->get_all());
+
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
+ unset($dbpasswd);
+
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy, CONFIG_TABLE);
+
+ // Override a couple of config variables for the duration
+ $config['max_quote_depth'] = 0;
+
+ // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
+ $config['max_post_chars'] = $config['min_post_chars'] = 0;
+
+ // Set up a user as well. We _should_ have enough of a database here at this point to do this
+ // and it helps for any core code we call
+ $user->session_begin();
+ $user->page = $user->extract_current_page($phpbb_root_path);
+
+ // This is a little bit of a fudge, but it allows the language entries to be available to the
+ // core code without us loading them again
+ $user->lang = &$lang;
+
+ $this->page_title = $user->lang['STAGE_IN_PROGRESS'];
+
+ $convert->options = array();
+ if (isset($config['convert_progress']))
+ {
+ $convert->options = unserialize($config['convert_progress']);
+ $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (empty($convert->options) || empty($convert->options['tag']) ||
+ !isset($convert->options['dbms']) ||
+ !isset($convert->options['dbhost']) ||
+ !isset($convert->options['dbport']) ||
+ !isset($convert->options['dbuser']) ||
+ !isset($convert->options['dbpasswd']) ||
+ !isset($convert->options['dbname']) ||
+ !isset($convert->options['table_prefix']))
+ {
+ $this->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
+ }
+
+ // Make some short variables accessible, for easier referencing
+ $convert->convertor_tag = basename($convert->options['tag']);
+ $convert->src_dbms = $convert->options['dbms'];
+ $convert->src_dbhost = $convert->options['dbhost'];
+ $convert->src_dbport = $convert->options['dbport'];
+ $convert->src_dbuser = $convert->options['dbuser'];
+ $convert->src_dbpasswd = $convert->options['dbpasswd'];
+ $convert->src_dbname = $convert->options['dbname'];
+ $convert->src_table_prefix = $convert->options['table_prefix'];
+
+ // initiate database connection to old db if old and new db differ
+ global $src_db, $same_db;
+ $src_db = $same_db = null;
+ if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser)
+ {
+ $dbms = $convert->src_dbms;
+ $src_db = new $dbms();
+ $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true);
+ $same_db = false;
+ }
+ else
+ {
+ $src_db = $db;
+ $same_db = true;
+ }
+
+ $convert->mysql_convert = false;
+ switch ($src_db->sql_layer)
+ {
+ case 'sqlite':
+ case 'sqlite3':
+ $convert->src_truncate_statement = 'DELETE FROM ';
+ break;
+
+ // Thanks MySQL, for silently converting...
+ case 'mysql':
+ case 'mysql4':
+ if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>='))
+ {
+ $convert->mysql_convert = true;
+ }
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+
+ case 'mysqli':
+ $convert->mysql_convert = true;
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+
+ default:
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+ }
+
+ if ($convert->mysql_convert && !$same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ switch ($db->get_sql_layer())
+ {
+ case 'sqlite':
+ case 'sqlite3':
+ $convert->truncate_statement = 'DELETE FROM ';
+ break;
+
+ default:
+ $convert->truncate_statement = 'TRUNCATE TABLE ';
+ break;
+ }
+
+ $get_info = false;
+
+ // check security implications of direct inclusion
+ if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
+ {
+ $this->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
+ }
+
+ if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
+ {
+ include('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
+ }
+
+ $get_info = true;
+ include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
+
+ // Map some variables...
+ $convert->convertor_data = $convertor_data;
+ $convert->tables = $tables;
+ $convert->config_schema = $config_schema;
+
+ // Now include the real data
+ $get_info = false;
+ include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
+
+ $convert->convertor_data = $convertor_data;
+ $convert->tables = $tables;
+ $convert->config_schema = $config_schema;
+ $convert->convertor = $convertor;
+
+ // The test_file is a file that should be present in the location of the old board.
+ if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
+ {
+ $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
+ }
+
+ $search_type = $config['search_type'];
+
+ // For conversions we are a bit less strict and set to a search backend we know exist...
+ if (!class_exists($search_type))
+ {
+ $search_type = '\phpbb\search\fulltext_native';
+ $config->set('search_type', $search_type);
+ }
+
+ if (!class_exists($search_type))
+ {
+ trigger_error('NO_SUCH_SEARCH_MODULE');
+ }
+
+ $error = false;
+ $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
+
+ if ($error)
+ {
+ trigger_error($error);
+ }
+
+ include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ $message_parser = new parse_message();
+
+ $jump = $request->variable('jump', 0);
+ $final_jump = $request->variable('final_jump', 0);
+ $sync_batch = $request->variable('sync_batch', -1);
+ $last_statement = $request->variable('last', 0);
+
+ // We are running sync...
+ if ($sync_batch >= 0)
+ {
+ $this->sync_forums($sync_batch);
+ return;
+ }
+
+ if ($jump)
+ {
+ $this->jump($jump, $last_statement);
+ return;
+ }
+
+ if ($final_jump)
+ {
+ $this->final_jump($final_jump);
+ return;
+ }
+
+ $current_table = $request->variable('current_table', 0);
+ $old_current_table = min(-1, $current_table - 1);
+ $skip_rows = $request->variable('skip_rows', 0);
+
+ if (!$current_table && !$skip_rows)
+ {
+ if (!$request->variable('confirm', false))
+ {
+ // If avatars / ranks / smilies folders are specified make sure they are writable
+ $bad_folders = array();
+
+ $local_paths = array(
+ 'avatar_path' => path($config['avatar_path']),
+ 'avatar_gallery_path' => path($config['avatar_gallery_path']),
+ 'icons_path' => path($config['icons_path']),
+ 'ranks_path' => path($config['ranks_path']),
+ 'smilies_path' => path($config['smilies_path'])
+ );
+
+ foreach ($local_paths as $folder => $local_path)
+ {
+ if (isset($convert->convertor[$folder]))
+ {
+ if (empty($convert->convertor['test_file']))
+ {
+ // test_file is mandantory at the moment so this should never be reached, but just in case...
+ $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
+ }
+
+ if (!$local_path || !$this->filesystem->is_writable($phpbb_root_path . $local_path))
+ {
+ if (!$local_path)
+ {
+ $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
+ }
+ else
+ {
+ $bad_folders[] = $local_path;
+ }
+ }
+ }
+ }
+
+ if (sizeof($bad_folders))
+ {
+ $msg = (sizeof($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
+ sort($bad_folders);
+ $this->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['INSTALL_TEST'],
+ 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}&amp;language=$language",
+ ));
+ return;
+ }
+
+ // Grab all the tables used in convertor
+ $missing_tables = $tables_list = $aliases = array();
+
+ foreach ($convert->convertor['schema'] as $schema)
+ {
+ // Skip those not used (because of addons/plugins not detected)
+ if (!$schema['target'])
+ {
+ continue;
+ }
+
+ foreach ($schema as $key => $val)
+ {
+ // we're dealing with an array like:
+ // array('forum_status', 'forums.forum_status', 'is_item_locked')
+ if (is_int($key) && !empty($val[1]))
+ {
+ $temp_data = $val[1];
+ if (!is_array($temp_data))
+ {
+ $temp_data = array($temp_data);
+ }
+
+ foreach ($temp_data as $val)
+ {
+ if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $val, $m))
+ {
+ $table = $convert->src_table_prefix . $m[1];
+ $tables_list[$table] = $table;
+
+ if (!empty($m[3]))
+ {
+ $aliases[] = $convert->src_table_prefix . $m[3];
+ }
+ }
+ }
+ }
+ // 'left_join' => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
+ else if ($key == 'left_join')
+ {
+ // Convert the value if it wasn't an array already.
+ if (!is_array($val))
+ {
+ $val = array($val);
+ }
+
+ for ($j = 0; $j < sizeof($val); ++$j)
+ {
+ if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
+ {
+ $table = $convert->src_table_prefix . $m[1];
+ $tables_list[$table] = $table;
+
+ if (!empty($m[2]))
+ {
+ $aliases[] = $convert->src_table_prefix . $m[2];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Remove aliased tables from $tables_list
+ foreach ($aliases as $alias)
+ {
+ unset($tables_list[$alias]);
+ }
+
+ // Check if the tables that we need exist
+ $src_db->sql_return_on_error(true);
+ foreach ($tables_list as $table => $null)
+ {
+ $sql = 'SELECT 1 FROM ' . $table;
+ $_result = $src_db->sql_query_limit($sql, 1);
+
+ if (!$_result)
+ {
+ $missing_tables[] = $table;
+ }
+ $src_db->sql_freeresult($_result);
+ }
+ $src_db->sql_return_on_error(false);
+
+ // Throw an error if some tables are missing
+ // We used to do some guessing here, but since we have a suggestion of possible values earlier, I don't see it adding anything here to do it again
+
+ if (sizeof($missing_tables) == sizeof($tables_list))
+ {
+ $this->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
+ }
+ else if (sizeof($missing_tables))
+ {
+ $this->p_master->error(sprintf($user->lang['TABLES_MISSING'], implode($user->lang['COMMA_SEPARATOR'], $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
+ }
+
+ $url = $this->save_convert_progress('&amp;confirm=1');
+ $msg = $user->lang['PRE_CONVERT_COMPLETE'];
+
+ if ($convert->convertor_data['author_notes'])
+ {
+ $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
+ }
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'L_MESSAGE' => $msg,
+ 'U_ACTION' => $url,
+ ));
+
+ return;
+ } // if (!$request->variable('confirm', false)))
+
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['STARTING_CONVERT'],
+ ));
+
+ // Convert the config table and load the settings of the old board
+ if (!empty($convert->config_schema))
+ {
+ restore_config($convert->config_schema);
+
+ // Override a couple of config variables for the duration
+ $config['max_quote_depth'] = 0;
+
+ // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
+ $config['max_post_chars'] = $config['min_post_chars'] = 0;
+ }
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['CONFIG_CONVERT'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ // Now process queries and execute functions that have to be executed prior to the conversion
+ if (!empty($convert->convertor['execute_first']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_first']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ if (!empty($convert->convertor['query_first']))
+ {
+ if (!is_array($convert->convertor['query_first']))
+ {
+ $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
+ }
+ else if (!is_array($convert->convertor['query_first'][0]))
+ {
+ $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
+ }
+
+ foreach ($convert->convertor['query_first'] as $query_first)
+ {
+ if ($query_first[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $src_db->sql_query($query_first[1]);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_first[1]);
+ }
+ }
+ }
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['PREPROCESS_STEP'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+ } // if (!$current_table && !$skip_rows)
+
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['FILLING_TABLES'],
+ ));
+
+ // This loop takes one target table and processes it
+ while ($current_table < sizeof($convert->convertor['schema']))
+ {
+ $schema = $convert->convertor['schema'][$current_table];
+
+ // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
+ if (empty($schema['target']))
+ {
+ $current_table++;
+ continue;
+ }
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => sprintf($user->lang['FILLING_TABLE'], $schema['target']),
+ ));
+
+ // This is only the case when we first start working on the tables.
+ if (!$skip_rows)
+ {
+ // process execute_first and query_first for this table...
+ if (!empty($schema['execute_first']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($schema['execute_first']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ if (!empty($schema['query_first']))
+ {
+ if (!is_array($schema['query_first']))
+ {
+ $schema['query_first'] = array('target', array($schema['query_first']));
+ }
+ else if (!is_array($schema['query_first'][0]))
+ {
+ $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
+ }
+
+ foreach ($schema['query_first'] as $query_first)
+ {
+ if ($query_first[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+ $src_db->sql_query($query_first[1]);
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_first[1]);
+ }
+ }
+ }
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'postgres':
+ $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
+ break;
+
+ case 'oracle':
+ $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $largest_id = (int) $row['max_id'];
+
+ if ($largest_id)
+ {
+ $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
+ $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
+ }
+ break;
+ }
+ }
+ }
+
+ // Process execute_always for this table
+ // This is for code which needs to be executed on every pass of this table if
+ // it gets split because of time restrictions
+ if (!empty($schema['execute_always']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($schema['execute_always']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ //
+ // Set up some variables
+ //
+ // $waiting_rows holds rows for multirows insertion (MySQL only)
+ // $src_tables holds unique tables with aliases to select from
+ // $src_fields will quickly refer source fields (or aliases) corresponding to the current index
+ // $select_fields holds the names of the fields to retrieve
+ //
+
+ $sql_data = array(
+ 'source_fields' => array(),
+ 'target_fields' => array(),
+ 'source_tables' => array(),
+ 'select_fields' => array(),
+ );
+
+ // This statement is building the keys for later insertion.
+ $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
+
+ // If no source table is affected, we skip the table
+ if (empty($sql_data['source_tables']))
+ {
+ $skip_rows = 0;
+ $current_table++;
+ continue;
+ }
+
+ $distinct = (!empty($schema['distinct'])) ? 'DISTINCT ' : '';
+
+ $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
+
+ // Where
+ $sql .= (!empty($schema['where'])) ? "\nWHERE (" . $schema['where'] . ')' : '';
+
+ // Group By
+ if (!empty($schema['group_by']))
+ {
+ $schema['group_by'] = array($schema['group_by']);
+ foreach ($sql_data['select_fields'] as $select)
+ {
+ $alias = strpos(strtolower($select), ' as ');
+ $select = ($alias) ? substr($select, 0, $alias) : $select;
+ if (!in_array($select, $schema['group_by']))
+ {
+ $schema['group_by'][] = $select;
+ }
+ }
+ }
+ $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
+
+ // Having
+ $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
+
+ // Order By
+ if (empty($schema['order_by']) && !empty($schema['primary']))
+ {
+ $schema['order_by'] = $schema['primary'];
+ }
+ $sql .= (!empty($schema['order_by'])) ? "\nORDER BY " . $schema['order_by'] : '';
+
+ // Counting basically holds the amount of rows processed.
+ $counting = -1;
+ $batch_time = 0;
+
+ while ($counting === -1 || ($counting >= $convert->batch_size && still_on_time()))
+ {
+ $old_current_table = $current_table;
+
+ $rows = '';
+ $waiting_rows = array();
+
+ if (!empty($batch_time))
+ {
+ $mtime = explode(' ', microtime());
+ $mtime = $mtime[0] + $mtime[1];
+ $rows = ceil($counting/($mtime - $batch_time)) . " rows/s ($counting rows) | ";
+ }
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => "skip_rows = $skip_rows",
+ 'RESULT' => $rows . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] : ''),
+ ));
+
+ $mtime = explode(' ', microtime());
+ $batch_time = $mtime[0] + $mtime[1];
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ // Take skip rows into account and only fetch batch_size amount of rows
+ $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ // This loop processes each row
+ $counting = 0;
+
+ $convert->row = $convert_row = array();
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'mssql':
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
+ break;
+ }
+ }
+
+ // Now handle the rows until time is over or no more rows to process...
+ while ($counting === 0 || still_on_time())
+ {
+ $convert_row = $src_db->sql_fetchrow($___result);
+
+ if (!$convert_row)
+ {
+ // move to the next batch or table
+ break;
+ }
+
+ // With this we are able to always save the last state
+ $convert->row = $convert_row;
+
+ // Increment the counting variable, it stores the number of rows we have processed
+ $counting++;
+
+ $insert_values = array();
+
+ $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
+
+ if ($sql_flag === true)
+ {
+ switch ($db->get_sql_layer())
+ {
+ // If MySQL, we'll wait to have num_wait_rows rows to submit at once
+ case 'mysql':
+ case 'mysql4':
+ case 'mysqli':
+ $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
+
+ if (sizeof($waiting_rows) >= $convert->num_wait_rows)
+ {
+ $errored = false;
+
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
+ {
+ $errored = true;
+ }
+ $db->sql_return_on_error(false);
+
+ if ($errored)
+ {
+ $db->sql_return_on_error(true);
+
+ // Because it errored out we will try to insert the rows one by one... most of the time this
+ // is caused by duplicate entries - but we also do not want to miss one...
+ foreach ($waiting_rows as $waiting_sql)
+ {
+ if (!$db->sql_query($insert_query . $waiting_sql))
+ {
+ $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+ }
+
+ $db->sql_return_on_error(false);
+ }
+
+ $waiting_rows = array();
+ }
+
+ break;
+
+ default:
+ $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
+
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_sql))
+ {
+ $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+ $db->sql_return_on_error(false);
+
+ $waiting_rows = array();
+
+ break;
+ }
+ }
+
+ $skip_rows++;
+ }
+ $src_db->sql_freeresult($___result);
+
+ // We might still have some rows waiting
+ if (sizeof($waiting_rows))
+ {
+ $errored = false;
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
+ {
+ $errored = true;
+ }
+ $db->sql_return_on_error(false);
+
+ if ($errored)
+ {
+ $db->sql_return_on_error(true);
+
+ // Because it errored out we will try to insert the rows one by one... most of the time this
+ // is caused by duplicate entries - but we also do not want to miss one...
+ foreach ($waiting_rows as $waiting_sql)
+ {
+ $db->sql_query($insert_query . $waiting_sql);
+ $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+
+ $db->sql_return_on_error(false);
+ }
+
+ $waiting_rows = array();
+ }
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'mssql':
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
+ break;
+
+ case 'postgres':
+ $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
+ break;
+
+ case 'oracle':
+ $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $largest_id = (int) $row['max_id'];
+
+ if ($largest_id)
+ {
+ $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
+ $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
+ }
+ break;
+ }
+ }
+ }
+
+ // When we reach this point, either the current table has been processed or we're running out of time.
+ if (still_on_time() && $counting < $convert->batch_size/* && !defined('DEBUG')*/)
+ {
+ $skip_rows = 0;
+ $current_table++;
+ }
+ else
+ {/*
+ if (still_on_time() && $counting < $convert->batch_size)
+ {
+ $skip_rows = 0;
+ $current_table++;
+ }*/
+
+ // Looks like we ran out of time.
+ $url = $this->save_convert_progress('&amp;current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
+
+ $current_table++;
+// $percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
+
+ $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, sizeof($convert->convertor['schema']));
+
+ $template->assign_vars(array(
+ 'L_MESSAGE' => $msg,
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+
+ // Process execute_last then we'll be done
+ $url = $this->save_convert_progress('&amp;jump=1');
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * Sync function being executed at the middle, some functions need to be executed after a successful sync.
+ */
+ function sync_forums($sync_batch)
+ {
+ global $template, $user, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['SYNC_TOPICS'],
+ ));
+
+ $batch_size = $convert->batch_size;
+
+ $sql = 'SELECT MIN(topic_id) as min_value, MAX(topic_id) AS max_value
+ FROM ' . TOPICS_TABLE;
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ // Set values of minimum/maximum primary value for this table.
+ $primary_min = $row['min_value'];
+ $primary_max = $row['max_value'];
+
+ if ($sync_batch == 0)
+ {
+ $sync_batch = (int) $primary_min;
+ }
+
+ if ($sync_batch == 0)
+ {
+ $sync_batch = 1;
+ }
+
+ // Fetch a batch of rows, process and insert them.
+ while ($sync_batch <= $primary_max && still_on_time())
+ {
+ $end = ($sync_batch + $batch_size - 1);
+
+ // Sync all topics in batch mode...
+ sync('topic', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, true);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => sprintf($user->lang['SYNC_TOPIC_ID'], $sync_batch, ($sync_batch + $batch_size)) . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ' [' . ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] . ']' : ''),
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $sync_batch += $batch_size;
+ }
+
+ if ($sync_batch >= $primary_max)
+ {
+ $url = $this->save_convert_progress('&amp;final_jump=1');
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ else
+ {
+ $sync_batch--;
+ }
+
+ $url = $this->save_convert_progress('&amp;sync_batch=' . $sync_batch);
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * Save the convertor status
+ */
+ function save_convert_progress($step)
+ {
+ global $config, $convert, $language;
+
+ // Save convertor Status
+ $config->set('convert_progress', serialize(array(
+ 'step' => $step,
+ 'table_prefix' => $convert->src_table_prefix,
+ 'tag' => $convert->convertor_tag,
+ )), false);
+
+ $config->set('convert_db_server', serialize(array(
+ 'dbms' => $convert->src_dbms,
+ 'dbhost' => $convert->src_dbhost,
+ 'dbport' => $convert->src_dbport,
+ 'dbname' => $convert->src_dbname,
+ )), false);
+
+ $config->set('convert_db_user', serialize(array(
+ 'dbuser' => $convert->src_dbuser,
+ 'dbpasswd' => $convert->src_dbpasswd,
+ )), false);
+
+ return $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step&amp;language=$language";
+ }
+
+ /**
+ * Finish conversion, the last function to be called.
+ */
+ function finish_conversion()
+ {
+ global $db, $phpbb_root_path, $phpEx, $convert, $config, $language, $user, $template;
+ global $cache, $auth, $phpbb_container, $phpbb_log;
+
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
+ WHERE config_name = 'convert_progress'
+ OR config_name = 'convert_options'
+ OR config_name = 'convert_db_server'
+ OR config_name = 'convert_db_user'");
+ $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
+
+ @unlink($phpbb_root_path . 'cache/data_global.' . $phpEx);
+ phpbb_cache_moderators($db, $cache, $auth);
+
+ // And finally, add a note to the log
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INSTALL_CONVERTED', false, array($convert->convertor_data['forum_name'], $config['version']));
+
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=final&amp;language=$language";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * This function marks the steps after syncing
+ */
+ function final_jump($final_jump)
+ {
+ global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['PROCESS_LAST'],
+ ));
+
+ if ($final_jump == 1)
+ {
+ $db->sql_return_on_error(true);
+
+ update_topics_posted();
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ if ($db->get_sql_error_triggered())
+ {
+ $template->assign_vars(array(
+ 'S_ERROR_BOX' => true,
+ 'ERROR_TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
+ 'ERROR_MSG' => $user->lang['UPDATE_TOPICS_POSTED_ERR'],
+ ));
+ }
+ $db->sql_return_on_error(false);
+
+ $this->finish_conversion();
+ return;
+ }
+ }
+
+ /**
+ * This function marks the steps before syncing (jump=1)
+ */
+ function jump($jump, $last_statement)
+ {
+ global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ $template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['PROCESS_LAST'],
+ ));
+
+ if ($jump == 1)
+ {
+ // Execute 'last' statements/queries
+ if (!empty($convert->convertor['execute_last']))
+ {
+ if (!is_array($convert->convertor['execute_last']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_last']);
+ // @codingStandardsIgnoreEnd
+ }
+ else
+ {
+ while ($last_statement < sizeof($convert->convertor['execute_last']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_last'][$last_statement]);
+ // @codingStandardsIgnoreEnd
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $convert->convertor['execute_last'][$last_statement],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $last_statement++;
+ $url = $this->save_convert_progress('&amp;jump=1&amp;last=' . $last_statement);
+
+ $percentage = ($last_statement == 0) ? 0 : floor(100 / (sizeof($convert->convertor['execute_last']) / $last_statement));
+ $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $last_statement, sizeof($convert->convertor['execute_last']), $percentage);
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_LAST'],
+ 'L_MESSAGE' => $msg,
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+ }
+
+ if (!empty($convert->convertor['query_last']))
+ {
+ if (!is_array($convert->convertor['query_last']))
+ {
+ $convert->convertor['query_last'] = array('target', array($convert->convertor['query_last']));
+ }
+ else if (!is_array($convert->convertor['query_last'][0]))
+ {
+ $convert->convertor['query_last'] = array(array($convert->convertor['query_last'][0], $convert->convertor['query_last'][1]));
+ }
+
+ foreach ($convert->convertor['query_last'] as $query_last)
+ {
+ if ($query_last[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $src_db->sql_query($query_last[1]);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_last[1]);
+ }
+ }
+ }
+
+ // Sanity check
+ $db->sql_return_on_error(false);
+ $src_db->sql_return_on_error(false);
+
+ fix_empty_primary_groups();
+
+ $sql = 'SELECT MIN(user_regdate) AS board_startdate
+ FROM ' . USERS_TABLE;
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if (!isset($config['board_startdate']) || ($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0))
+ {
+ $config->set('board_startdate', $row['board_startdate']);
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_regdate = ' . $row['board_startdate'] . ' WHERE user_id = ' . ANONYMOUS);
+ }
+
+ update_dynamic_config();
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['CLEAN_VERIFY'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $url = $this->save_convert_progress('&amp;jump=2');
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ if ($jump == 2)
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_permissions = ''");
+
+ // TODO: sync() is likely going to bomb out on forums with a considerable amount of topics.
+ // TODO: the sync function is able to handle FROM-TO values, we should use them here (batch processing)
+ sync('forum', '', '', false, true);
+ $cache->destroy('sql', FORUMS_TABLE);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['SYNC_FORUMS'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ // Continue with synchronizing the forums...
+ $url = $this->save_convert_progress('&amp;sync_batch=0');
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+
+ function build_insert_query(&$schema, &$sql_data, $current_table)
+ {
+ global $db, $user;
+ global $convert;
+
+ // Can we use IGNORE with this DBMS?
+ $sql_ignore = (strpos($db->get_sql_layer(), 'mysql') === 0 && !defined('DEBUG')) ? 'IGNORE ' : '';
+ $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' (';
+
+ $aliases = array();
+
+ $sql_data = array(
+ 'source_fields' => array(),
+ 'target_fields' => array(),
+ 'source_tables' => array(),
+ 'select_fields' => array(),
+ );
+
+ foreach ($schema as $key => $val)
+ {
+ // Example: array('group_name', 'extension_groups.group_name', 'htmlspecialchars'),
+ if (is_int($key))
+ {
+ if (!empty($val[0]))
+ {
+ // Target fields
+ $sql_data['target_fields'][$val[0]] = $key;
+ $insert_query .= $val[0] . ', ';
+ }
+
+ if (!is_array($val[1]))
+ {
+ $val[1] = array($val[1]);
+ }
+
+ foreach ($val[1] as $valkey => $value_1)
+ {
+ // This should cover about any case:
+ //
+ // table.field => SELECT table.field FROM table
+ // table.field AS alias => SELECT table.field AS alias FROM table
+ // table.field AS table2.alias => SELECT table2.field AS alias FROM table table2
+ // table.field AS table2.field => SELECT table2.field FROM table table2
+ //
+ if (preg_match('/^([a-z0-9_]+)\.([a-z0-9_]+)( +AS +(([a-z0-9_]+?)\.)?([a-z0-9_]+))?$/i', $value_1, $m))
+ {
+ // There is 'AS ...' in the field names
+ if (!empty($m[3]))
+ {
+ $value_1 = ($m[2] == $m[6]) ? $m[1] . '.' . $m[2] : $m[1] . '.' . $m[2] . ' AS ' . $m[6];
+
+ // Table alias: store it then replace the source table with it
+ if (!empty($m[5]) && $m[5] != $m[1])
+ {
+ $aliases[$m[5]] = $m[1];
+ $value_1 = str_replace($m[1] . '.' . $m[2], $m[5] . '.' . $m[2], $value_1);
+ }
+ }
+ else
+ {
+ // No table alias
+ $sql_data['source_tables'][$m[1]] = (empty($convert->src_table_prefix)) ? $m[1] : $convert->src_table_prefix . $m[1] . ' ' . $m[1];
+ }
+
+ $sql_data['select_fields'][$value_1] = $value_1;
+ $sql_data['source_fields'][$key][$valkey] = (!empty($m[6])) ? $m[6] : $m[2];
+ }
+ }
+ }
+ else if ($key == 'where' || $key == 'group_by' || $key == 'order_by' || $key == 'having')
+ {
+ if (@preg_match_all('/([a-z0-9_]+)\.([a-z0-9_]+)/i', $val, $m))
+ {
+ foreach ($m[1] as $value)
+ {
+ $sql_data['source_tables'][$value] = (empty($convert->src_table_prefix)) ? $value : $convert->src_table_prefix . $value . ' ' . $value;
+ }
+ }
+ }
+ }
+
+ // Add the aliases to the list of tables
+ foreach ($aliases as $alias => $table)
+ {
+ $sql_data['source_tables'][$alias] = $convert->src_table_prefix . $table . ' ' . $alias;
+ }
+
+ // 'left_join' => 'forums LEFT JOIN forum_prune ON forums.forum_id = forum_prune.forum_id',
+ if (!empty($schema['left_join']))
+ {
+ if (!is_array($schema['left_join']))
+ {
+ $schema['left_join'] = array($schema['left_join']);
+ }
+
+ foreach ($schema['left_join'] as $left_join)
+ {
+ // This won't handle concatened LEFT JOINs
+ if (!preg_match('/([a-z0-9_]+) LEFT JOIN ([a-z0-9_]+) A?S? ?([a-z0-9_]*?) ?(ON|USING)(.*)/i', $left_join, $m))
+ {
+ $this->p_master->error(sprintf($user->lang['NOT_UNDERSTAND'], 'LEFT JOIN', $left_join, $current_table, $schema['target']), __LINE__, __FILE__);
+ }
+
+ if (!empty($aliases[$m[2]]))
+ {
+ if (!empty($m[3]))
+ {
+ $this->p_master->error(sprintf($user->lang['NAMING_CONFLICT'], $m[2], $m[3], $schema['left_join']), __LINE__, __FILE__);
+ }
+
+ $m[2] = $aliases[$m[2]];
+ $m[3] = $m[2];
+ }
+
+ $right_table = $convert->src_table_prefix . $m[2];
+ if (!empty($m[3]))
+ {
+ unset($sql_data['source_tables'][$m[3]]);
+ }
+ else if ($m[2] != $m[1])
+ {
+ unset($sql_data['source_tables'][$m[2]]);
+ }
+
+ if (strpos($sql_data['source_tables'][$m[1]], "\nLEFT JOIN") !== false)
+ {
+ $sql_data['source_tables'][$m[1]] = '(' . $sql_data['source_tables'][$m[1]] . ")\nLEFT JOIN $right_table";
+ }
+ else
+ {
+ $sql_data['source_tables'][$m[1]] .= "\nLEFT JOIN $right_table";
+ }
+
+ if (!empty($m[3]))
+ {
+ unset($sql_data['source_tables'][$m[3]]);
+ $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[3];
+ }
+ else if (!empty($convert->src_table_prefix))
+ {
+ $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[2];
+ }
+ $sql_data['source_tables'][$m[1]] .= ' ' . $m[4] . $m[5];
+ }
+ }
+
+ // Remove ", " from the end of the insert query
+ $insert_query = substr($insert_query, 0, -2) . ') VALUES ';
+
+ return $insert_query;
+ }
+
+ /**
+ * Function for processing the currently handled row
+ */
+ function process_row(&$schema, &$sql_data, &$insert_values)
+ {
+ global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
+ global $convert, $convert_row;
+
+ $sql_flag = false;
+
+ foreach ($schema as $key => $fields)
+ {
+ // We are only interested in the lines with:
+ // array('comment', 'attachments_desc.comment', 'htmlspecialchars'),
+ if (is_int($key))
+ {
+ if (!is_array($fields[1]))
+ {
+ $fields[1] = array($fields[1]);
+ }
+
+ $firstkey_set = false;
+ $firstkey = 0;
+
+ foreach ($fields[1] as $inner_key => $inner_value)
+ {
+ if (!$firstkey_set)
+ {
+ $firstkey = $inner_key;
+ $firstkey_set = true;
+ }
+
+ $src_field = isset($sql_data['source_fields'][$key][$inner_key]) ? $sql_data['source_fields'][$key][$inner_key] : '';
+
+ if (!empty($src_field))
+ {
+ $fields[1][$inner_key] = $convert->row[$src_field];
+ }
+ }
+
+ if (!empty($fields[0]))
+ {
+ // We have a target field, if we haven't set $sql_flag yet it will be set to TRUE.
+ // If a function has already set it to FALSE it won't change it.
+ if ($sql_flag === false)
+ {
+ $sql_flag = true;
+ }
+
+ // No function assigned?
+ if (empty($fields[2]))
+ {
+ $value = $fields[1][$firstkey];
+ }
+ else if (is_array($fields[2]) && !is_callable($fields[2]))
+ {
+ // Execute complex function/eval/typecast
+ $value = $fields[1];
+
+ foreach ($fields[2] as $type => $execution)
+ {
+ if (strpos($type, 'typecast') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+ $value = $value[0];
+ settype($value, $execution);
+ }
+ else if (strpos($type, 'function') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $value = call_user_func_array($execution, $value);
+ }
+ else if (strpos($type, 'execute') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $execution = str_replace('{RESULT}', '$value', $execution);
+ $execution = str_replace('{VALUE}', '$value', $execution);
+ // @codingStandardsIgnoreStart
+ eval($execution);
+ // @codingStandardsIgnoreEnd
+ }
+ }
+ }
+ else
+ {
+ $value = call_user_func_array($fields[2], $fields[1]);
+ }
+
+ if (is_null($value))
+ {
+ $value = '';
+ }
+
+ $insert_values[] = $db->_sql_validate_value($value);
+ }
+ else if (!empty($fields[2]))
+ {
+ if (is_array($fields[2]))
+ {
+ // Execute complex function/eval/typecast
+ $value = '';
+
+ foreach ($fields[2] as $type => $execution)
+ {
+ if (strpos($type, 'typecast') === 0)
+ {
+ $value = settype($value, $execution);
+ }
+ else if (strpos($type, 'function') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $value = call_user_func_array($execution, $value);
+ }
+ else if (strpos($type, 'execute') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $execution = str_replace('{RESULT}', '$value', $execution);
+ $execution = str_replace('{VALUE}', '$value', $execution);
+ // @codingStandardsIgnoreStart
+ eval($execution);
+ // @codingStandardsIgnoreEnd
+ }
+ }
+ }
+ else
+ {
+ call_user_func_array($fields[2], $fields[1]);
+ }
+ }
+ }
+ }
+
+ return $sql_flag;
+ }
+
+ /**
+ * Own meta refresh function to be able to change the global time used
+ */
+ function meta_refresh($url)
+ {
+ global $convert, $template;
+
+ if ($convert->options['refresh'])
+ {
+ // Because we should not rely on correct settings, we simply use the relative path here directly.
+ $template->assign_vars(array(
+ 'S_REFRESH' => true,
+ 'META' => '<meta http-equiv="refresh" content="5; url=' . $url . '" />')
+ );
+ }
+ }
+
+ /**
+ * The information below will be used to build the input fields presented to the user
+ */
+ var $convert_options = array(
+ 'legend1' => 'SPECIFY_OPTIONS',
+ 'src_dbms' => array('lang' => 'DBMS', 'type' => 'select', 'options' => 'dbms_select(\'{VALUE}\', true)', 'explain' => false),
+ 'src_dbhost' => array('lang' => 'DB_HOST', 'type' => 'text:25:100', 'explain' => true),
+ 'src_dbport' => array('lang' => 'DB_PORT', 'type' => 'text:25:100', 'explain' => true),
+ 'src_dbname' => array('lang' => 'DB_NAME', 'type' => 'text:25:100', 'explain' => false),
+ 'src_dbuser' => array('lang' => 'DB_USERNAME', 'type' => 'text:25:100', 'explain' => false),
+ 'src_dbpasswd' => array('lang' => 'DB_PASSWORD', 'type' => 'password:25:100', 'explain' => false),
+ 'src_table_prefix' => array('lang' => 'TABLE_PREFIX', 'type' => 'text:25:100', 'explain' => false),
+ //'src_url' => array('lang' => 'FORUM_ADDRESS', 'type' => 'text:50:100', 'explain' => true),
+ 'forum_path' => array('lang' => 'FORUM_PATH', 'type' => 'text:25:100', 'explain' => true),
+ 'refresh' => array('lang' => 'REFRESH_PAGE', 'type' => 'radio:yes_no', 'explain' => true),
+ );
+}
diff --git a/phpBB/install_old/install_update.php b/phpBB/install_old/install_update.php
new file mode 100644
index 0000000000..d9ba2e7fe9
--- /dev/null
+++ b/phpBB/install_old/install_update.php
@@ -0,0 +1,1790 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @todo check for writable cache/store/files directory
+*/
+
+if (!defined('IN_INSTALL'))
+{
+ // Someone has tried to access the file directly. This is not a good idea, so exit
+ exit;
+}
+
+if (!empty($setmodules))
+{
+ // If phpBB is not installed we do not include this module
+ if (!phpbb_check_installation_exists($phpbb_root_path, $phpEx) || file_exists($phpbb_root_path . 'cache/install_lock'))
+ {
+ return;
+ }
+
+ $module[] = array(
+ 'module_type' => 'update',
+ 'module_title' => 'UPDATE',
+ 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
+ 'module_order' => 30,
+ 'module_subs' => '',
+ 'module_stages' => array('INTRO', 'VERSION_CHECK', 'FILE_CHECK', 'UPDATE_FILES', 'UPDATE_DB'),
+ 'module_reqs' => ''
+ );
+}
+
+/**
+* Update Installation
+*/
+class install_update extends module
+{
+ var $p_master;
+ var $update_info;
+
+ var $old_location;
+ var $new_location;
+ var $latest_version;
+ var $current_version;
+
+ var $update_to_version;
+
+ protected $filesystem;
+
+ // Set to false
+ var $test_update = false;
+
+ function install_update(&$p_master)
+ {
+ $this->p_master = &$p_master;
+ }
+
+ function main($mode, $sub)
+ {
+ global $template, $phpEx, $phpbb_root_path, $user, $db, $config, $cache, $auth, $language;
+ global $request, $phpbb_admin_path, $phpbb_adm_relative_path, $phpbb_container, $phpbb_config_php_file;
+
+ // We must enable super globals, otherwise creating a new instance of the request class,
+ // using the new container with a dbal connection will fail with the following PHP Notice:
+ // Object of class phpbb_request_deactivated_super_global could not be converted to int
+ $request->enable_super_globals();
+
+ // Create a normal container now
+ $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $phpbb_container = $phpbb_container_builder
+ ->with_config($phpbb_config_php_file)
+ ->without_cache()
+ ->without_extensions()
+ ;
+
+ if (file_exists($phpbb_root_path . 'install/update/new/config'))
+ {
+ $phpbb_container_builder->with_config_path($phpbb_root_path . 'install/update/new/config');
+ }
+ $phpbb_container = $phpbb_container_builder->get_container();
+
+ // Writes into global $cache
+ /* @var $cache \phpbb\cache\service */
+ $cache = $phpbb_container->get('cache');
+
+ $this->filesystem = $phpbb_container->get('filesystem');
+
+ $this->tpl_name = 'install_update';
+ $this->page_title = 'UPDATE_INSTALLATION';
+
+ $this->old_location = $phpbb_root_path . 'install/update/old/';
+ $this->new_location = $phpbb_root_path . 'install/update/new/';
+
+ // Init DB
+ extract($phpbb_config_php_file->get_all());
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+
+ // Special options for conflicts/modified files
+ define('MERGE_NO_MERGE_NEW', 1);
+ define('MERGE_NO_MERGE_MOD', 2);
+ define('MERGE_NEW_FILE', 3);
+ define('MERGE_MOD_FILE', 4);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
+
+ // Connect to DB
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
+
+ // We do not need this any longer, unset for safety purposes
+ unset($dbpasswd);
+
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy, CONFIG_TABLE);
+
+ // Force template recompile
+ $config['load_tplcompile'] = 1;
+
+ // First of all, init the user session
+ $user->session_begin();
+ $auth->acl($user->data);
+
+ // Overwrite user's language with the selected one.
+ // Config needs to be changed to ensure that guests also get the selected language.
+ $config_default_lang = $config['default_lang'];
+ $config['default_lang'] = $language;
+ $user->data['user_lang'] = $language;
+
+ $user->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
+
+ // Reset the default_lang
+ $config['default_lang'] = $config_default_lang;
+ unset($config_default_lang);
+
+ // If we are within the intro page we need to make sure we get up-to-date version info
+ if ($sub == 'intro')
+ {
+ $cache->destroy('_version_info');
+ }
+
+ // Set custom template again. ;)
+ $paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
+ $paths = array_filter($paths, 'is_dir');
+ $template->set_custom_style(array(
+ array(
+ 'name' => 'adm',
+ 'ext_path' => 'adm/style/',
+ ),
+ ), $paths);
+
+ $template->assign_vars(array(
+ 'S_USER_LANG' => $user->lang['USER_LANG'],
+ 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
+ 'S_CONTENT_ENCODING' => 'UTF-8',
+ 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
+ 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
+ ));
+
+ // Get current and latest version
+ /* @var $version_helper \phpbb\version_helper */
+ $version_helper = $phpbb_container->get('version_helper');
+ try
+ {
+ $this->latest_version = $version_helper->get_latest_on_current_branch(true);
+ }
+ catch (\RuntimeException $e)
+ {
+ $this->latest_version = false;
+
+ $update_info = array();
+ include($phpbb_root_path . 'install/update/index.' . $phpEx);
+ $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
+
+ if ($info !== false)
+ {
+ $this->latest_version = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false;
+ }
+ }
+
+ // For the current version we trick a bit. ;)
+ $this->current_version = (!empty($config['version_update_from'])) ? $config['version_update_from'] : $config['version'];
+
+ $up_to_date = (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->latest_version)), '<')) ? false : true;
+
+ // Check for a valid update directory, else point the user to the phpbb.com website
+ if (!file_exists($phpbb_root_path . 'install/update') || !file_exists($phpbb_root_path . 'install/update/index.' . $phpEx) || !file_exists($this->old_location) || !file_exists($this->new_location))
+ {
+ $template->assign_vars(array(
+ 'S_ERROR' => true,
+ 'ERROR_MSG' => ($up_to_date) ? $user->lang['NO_UPDATE_FILES_UP_TO_DATE'] : sprintf($user->lang['NO_UPDATE_FILES_OUTDATED'], $config['version'], $this->current_version, $this->latest_version))
+ );
+
+ return;
+ }
+
+ $this->update_info = $this->get_file('update_info');
+
+ // Make sure the update directory holds the correct information
+ // Since admins are able to run the update/checks more than once we only check if the current version is lower or equal than the version to which we update to.
+ if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '>'))
+ {
+ $template->assign_vars(array(
+ 'S_ERROR' => true,
+ 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $config['version'], $this->update_info['version']['from'], $this->update_info['version']['to']))
+ );
+
+ return;
+ }
+
+ // Check if the update files are actually meant to update from the current version
+ if ($this->current_version != $this->update_info['version']['from'])
+ {
+ $template->assign_vars(array(
+ 'S_ERROR' => true,
+ 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $this->current_version, $this->update_info['version']['from'], $this->update_info['version']['to']),
+ ));
+ }
+
+ // Check if the update files stored are for the latest version...
+ if (version_compare(strtolower($this->latest_version), strtolower($this->update_info['version']['to']), '>'))
+ {
+ $template->assign_vars(array(
+ 'S_WARNING' => true,
+ 'WARNING_MSG' => sprintf($user->lang['OLD_UPDATE_FILES'], $this->update_info['version']['from'], $this->update_info['version']['to'], $this->latest_version))
+ );
+ }
+
+ // We store the "update to" version, because it is not always the latest. ;)
+ $this->update_to_version = $this->update_info['version']['to'];
+
+ // Fill DB version
+ if (empty($config['dbms_version']))
+ {
+ $config->set('dbms_version', $db->sql_server_info(true));
+ }
+
+ if ($this->test_update === false)
+ {
+ // What about the language file? Got it updated?
+ if (in_array('language/' . $language . '/install.' . $phpEx, $this->update_info['files']))
+ {
+ $lang = array();
+ include($this->new_location . 'language/' . $language . '/install.' . $phpEx);
+ // this is the user's language.. just merge it
+ $user->lang = array_merge($user->lang, $lang);
+ }
+ if ($language != 'en' && in_array('language/en/install.' . $phpEx, $this->update_info['files']))
+ {
+ $lang = array();
+ include($this->new_location . 'language/en/install.' . $phpEx);
+ // only add new keys to user's language in english
+ $new_keys = array_diff(array_keys($lang), array_keys($user->lang));
+ foreach ($new_keys as $i => $new_key)
+ {
+ $user->lang[$new_key] = $lang[$new_key];
+ }
+ }
+ }
+
+ // Include renderer and engine
+ $this->include_file('includes/diff/diff.' . $phpEx);
+ $this->include_file('includes/diff/engine.' . $phpEx);
+ $this->include_file('includes/diff/renderer.' . $phpEx);
+
+ // Make sure we stay at the file check if checking the files again
+ if ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST))
+ {
+ $sub = $this->p_master->sub = 'file_check';
+ }
+
+ switch ($sub)
+ {
+ case 'intro':
+ $this->page_title = 'UPDATE_INSTALLATION';
+
+ $template->assign_vars(array(
+ 'S_INTRO' => true,
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=version_check"),
+ ));
+
+ // Make sure the update list is destroyed.
+ $cache->destroy('_update_list');
+ $cache->destroy('_diff_files');
+ $cache->destroy('_expected_files');
+ break;
+
+ case 'version_check':
+ $this->page_title = 'STAGE_VERSION_CHECK';
+
+ $template->assign_vars(array(
+ 'S_VERSION_CHECK' => true,
+
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
+
+ 'S_UP_TO_DATE' => $up_to_date,
+ 'LATEST_VERSION' => $this->latest_version,
+ 'CURRENT_VERSION' => $this->current_version,
+ ));
+
+ // Print out version the update package updates to
+ if ($this->latest_version != $this->update_info['version']['to'])
+ {
+ $template->assign_var('PACKAGE_VERSION', $this->update_info['version']['to']);
+ }
+
+ // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
+ // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
+ // We now try to cope with this by triggering the update process
+ if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
+ {
+ $template->assign_vars(array(
+ 'S_UP_TO_DATE' => false,
+ ));
+ }
+
+ break;
+
+ case 'update_db':
+ // Redirect the user to the database update script with some explanations...
+ $template->assign_vars(array(
+ 'S_DB_UPDATE' => true,
+ 'S_DB_UPDATE_FINISHED' => ($config['version'] == $this->update_info['version']['to']) ? true : false,
+ 'U_DB_UPDATE' => append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=1&amp;language=' . $user->data['user_lang']),
+ 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
+ 'L_EVERYTHING_UP_TO_DATE' => $user->lang('EVERYTHING_UP_TO_DATE', append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'), append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login&amp;redirect=' . $phpbb_adm_relative_path . 'index.php%3Fi=send_statistics%26mode=send_statistics')),
+ ));
+
+ // Do not display incompatible package note after successful update
+ if ($config['version'] == $this->update_info['version']['to'])
+ {
+ $template->assign_var('S_ERROR', false);
+ }
+ break;
+
+ case 'file_check':
+
+ // retrieve info on what changes should have already been made to the files.
+ $expected_files = $cache->get('_expected_files');
+ if (!$expected_files)
+ {
+ $expected_files = array();
+ }
+
+ // Now make sure the previous file collection is no longer valid...
+ $cache->destroy('_diff_files');
+
+ $this->page_title = 'STAGE_FILE_CHECK';
+
+ // Now make sure our update list is correct if the admin refreshes
+ $action = $request->variable('action', '');
+
+ // We are directly within an update. To make sure our update list is correct we check its status.
+ $update_list = ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST)) ? false : $cache->get('_update_list');
+ $modified = ($update_list !== false) ? @filemtime($cache->get_driver()->cache_dir . 'data_update_list.' . $phpEx) : 0;
+
+ // Make sure the list is up-to-date
+ if ($update_list !== false)
+ {
+ $get_new_list = false;
+ foreach ($this->update_info['files'] as $file)
+ {
+ if (file_exists($phpbb_root_path . $file) && filemtime($phpbb_root_path . $file) > $modified)
+ {
+ $get_new_list = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $get_new_list = true;
+ }
+
+ if (!$get_new_list && $update_list['status'] != -1)
+ {
+ $get_new_list = true;
+ }
+
+ if ($get_new_list)
+ {
+ $this->get_update_structure($update_list, $expected_files);
+ $cache->put('_update_list', $update_list);
+
+ // Refresh the page if we are still not finished...
+ if ($update_list['status'] != -1)
+ {
+ $refresh_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check");
+ meta_refresh(2, $refresh_url);
+
+ $template->assign_vars(array(
+ 'S_IN_PROGRESS' => true,
+ 'S_COLLECTED' => (int) $update_list['status'],
+ 'S_TO_COLLECT' => sizeof($this->update_info['files']),
+ 'L_IN_PROGRESS' => $user->lang['COLLECTING_FILE_DIFFS'],
+ 'L_IN_PROGRESS_EXPLAIN' => sprintf($user->lang['NUMBER_OF_FILES_COLLECTED'], (int) $update_list['status'], sizeof($this->update_info['files']) + sizeof($this->update_info['deleted'])),
+ ));
+
+ return;
+ }
+ }
+
+ if ($action == 'diff')
+ {
+ $this->show_diff($update_list);
+ return;
+ }
+
+ if (sizeof($update_list['no_update']))
+ {
+ $template->assign_vars(array(
+ 'S_NO_UPDATE_FILES' => true,
+ 'NO_UPDATE_FILES' => implode(', ', array_map('htmlspecialchars', $update_list['no_update'])))
+ );
+ }
+
+ $new_expected_files = array();
+
+ // Now assign the list to the template
+ foreach ($update_list as $status => $filelist)
+ {
+ if ($status == 'no_update' || !sizeof($filelist) || $status == 'status' || $status == 'status_deleted')
+ {
+ continue;
+ }
+
+/* $template->assign_block_vars('files', array(
+ 'S_STATUS' => true,
+ 'STATUS' => $status,
+ 'L_STATUS' => $user->lang['STATUS_' . strtoupper($status)],
+ 'TITLE' => $user->lang['FILES_' . strtoupper($status)],
+ 'EXPLAIN' => $user->lang['FILES_' . strtoupper($status) . '_EXPLAIN'],
+ )
+ );*/
+
+ foreach ($filelist as $file_struct)
+ {
+ $s_binary = (!empty($this->update_info['binary']) && in_array($file_struct['filename'], $this->update_info['binary'])) ? true : false;
+
+ $filename = htmlspecialchars($file_struct['filename']);
+ if (strrpos($filename, '/') !== false)
+ {
+ $dir_part = substr($filename, 0, strrpos($filename, '/') + 1);
+ $file_part = substr($filename, strrpos($filename, '/') + 1);
+ }
+ else
+ {
+ $dir_part = '';
+ $file_part = $filename;
+ }
+
+ $diff_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check&amp;action=diff&amp;status=$status&amp;file=" . urlencode($file_struct['filename']));
+
+ if (isset($file_struct['as_expected']) && $file_struct['as_expected'])
+ {
+ $new_expected_files[$file_struct['filename']] = $expected_files[$file_struct['filename']];
+ }
+ else
+ {
+ $template->assign_block_vars($status, array(
+ 'STATUS' => $status,
+
+ 'FILENAME' => $filename,
+ 'DIR_PART' => $dir_part,
+ 'FILE_PART' => $file_part,
+ 'NUM_CONFLICTS' => (isset($file_struct['conflicts'])) ? $file_struct['conflicts'] : 0,
+
+ 'S_CUSTOM' => ($file_struct['custom']) ? true : false,
+ 'S_BINARY' => $s_binary,
+ 'CUSTOM_ORIGINAL' => ($file_struct['custom']) ? $file_struct['original'] : '',
+
+ 'U_SHOW_DIFF' => $diff_url,
+ 'L_SHOW_DIFF' => ($status != 'up_to_date') ? $user->lang['SHOW_DIFF_' . strtoupper($status)] : '',
+
+ 'U_VIEW_MOD_FILE' => $diff_url . '&amp;op=' . MERGE_MOD_FILE,
+ 'U_VIEW_NEW_FILE' => $diff_url . '&amp;op=' . MERGE_NEW_FILE,
+ 'U_VIEW_NO_MERGE_MOD' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_MOD,
+ 'U_VIEW_NO_MERGE_NEW' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_NEW,
+ ));
+ }
+ }
+ }
+
+ $cache->put('_expected_files', $new_expected_files);
+
+ $all_up_to_date = true;
+ foreach ($update_list as $status => $filelist)
+ {
+ if ($status != 'up_to_date' && $status != 'custom' && $status != 'status' && $status != 'status_deleted' && sizeof($filelist))
+ {
+ $all_up_to_date = false;
+ break;
+ }
+ }
+
+ $template->assign_vars(array(
+ 'S_FILE_CHECK' => true,
+ 'S_ALL_UP_TO_DATE' => $all_up_to_date,
+ 'S_VERSION_UP_TO_DATE' => $up_to_date,
+ 'S_UP_TO_DATE' => $up_to_date,
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
+ 'U_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
+ 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
+ ));
+
+ // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
+ // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
+ // We now try to cope with this by triggering the update process
+ if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
+ {
+ $template->assign_vars(array(
+ 'S_UP_TO_DATE' => false,
+ ));
+ }
+
+ if ($all_up_to_date)
+ {
+ global $phpbb_container;
+
+ /* @var $phpbb_log \phpbb\log\log_interface */
+ $phpbb_log = $phpbb_container->get('log');
+
+ // Add database update to log
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UPDATE_PHPBB', time(), array($this->current_version, $this->update_to_version));
+
+ $db->sql_return_on_error(true);
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
+ $db->sql_return_on_error(false);
+
+ $cache->purge();
+ }
+
+ break;
+
+ case 'update_files':
+
+ $this->page_title = 'STAGE_UPDATE_FILES';
+
+ $s_hidden_fields = '';
+ $params = array();
+ $conflicts = $request->variable('conflict', array('' => 0));
+ $modified = $request->variable('modified', array('' => 0));
+
+ foreach ($conflicts as $filename => $merge_option)
+ {
+ $s_hidden_fields .= '<input type="hidden" name="conflict[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
+ $params[] = 'conflict[' . urlencode($filename) . ']=' . urlencode($merge_option);
+ }
+
+ foreach ($modified as $filename => $merge_option)
+ {
+ if (!$merge_option)
+ {
+ continue;
+ }
+ $s_hidden_fields .= '<input type="hidden" name="modified[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
+ $params[] = 'modified[' . urlencode($filename) . ']=' . urlencode($merge_option);
+ }
+
+ $no_update = $request->variable('no_update', array(0 => ''));
+
+ foreach ($no_update as $index => $filename)
+ {
+ $s_hidden_fields .= '<input type="hidden" name="no_update[]" value="' . htmlspecialchars($filename) . '" />';
+ $params[] = 'no_update[]=' . urlencode($filename);
+ }
+
+ // Before the user is choosing his preferred method, let's create the content list...
+ $update_list = $cache->get('_update_list');
+
+ if ($update_list === false)
+ {
+ trigger_error($user->lang['NO_UPDATE_INFO'], E_USER_ERROR);
+ }
+
+ // Check if the conflicts data is valid
+ if (sizeof($conflicts))
+ {
+ $conflict_filenames = array();
+ foreach ($update_list['conflict'] as $files)
+ {
+ $conflict_filenames[] = $files['filename'];
+ }
+
+ $new_conflicts = array();
+ foreach ($conflicts as $filename => $diff_method)
+ {
+ if (in_array($filename, $conflict_filenames))
+ {
+ $new_conflicts[$filename] = $diff_method;
+ }
+ }
+
+ $conflicts = $new_conflicts;
+ }
+
+ // Build list for modifications
+ if (sizeof($modified))
+ {
+ $modified_filenames = array();
+ foreach ($update_list['modified'] as $files)
+ {
+ $modified_filenames[] = $files['filename'];
+ }
+
+ $new_modified = array();
+ foreach ($modified as $filename => $diff_method)
+ {
+ if (in_array($filename, $modified_filenames))
+ {
+ $new_modified[$filename] = $diff_method;
+ }
+ }
+
+ $modified = $new_modified;
+ }
+
+ // Check number of conflicting files, they need to be equal. For modified files the number can differ
+ if (sizeof($update_list['conflict']) != sizeof($conflicts))
+ {
+ trigger_error($user->lang['MERGE_SELECT_ERROR'], E_USER_ERROR);
+ }
+
+ // Before we do anything, let us diff the files and store the raw file information "somewhere"
+ $get_files = false;
+ $file_list = $cache->get('_diff_files');
+ $expected_files = $cache->get('_expected_files');
+
+ if ($file_list === false || $file_list['status'] != -1)
+ {
+ $get_files = true;
+ }
+
+ if ($get_files)
+ {
+ if ($file_list === false)
+ {
+ $file_list = array(
+ 'status' => 0,
+ );
+ }
+
+ if (!isset($expected_files) || $expected_files === false)
+ {
+ $expected_files = array();
+ }
+
+ $processed = 0;
+ foreach ($update_list as $status => $files)
+ {
+ if (!is_array($files))
+ {
+ continue;
+ }
+
+ foreach ($files as $file_struct)
+ {
+ // Skip this file if the user selected to not update it
+ if (in_array($file_struct['filename'], $no_update))
+ {
+ $expected_files[$file_struct['filename']] = false;
+ continue;
+ }
+
+ // Already handled... then skip of course...
+ if (isset($file_list[$file_struct['filename']]))
+ {
+ continue;
+ }
+
+ // Refresh if we reach 5 diffs...
+ if ($processed >= 5)
+ {
+ $cache->put('_diff_files', $file_list);
+
+ if ($request->variable('download', false))
+ {
+ $params[] = 'download=1';
+ }
+
+ $redirect_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;" . implode('&amp;', $params));
+ meta_refresh(3, $redirect_url);
+
+ $template->assign_vars(array(
+ 'S_IN_PROGRESS' => true,
+ 'L_IN_PROGRESS' => $user->lang['MERGING_FILES'],
+ 'L_IN_PROGRESS_EXPLAIN' => $user->lang['MERGING_FILES_EXPLAIN'],
+ ));
+
+ return;
+ }
+
+ if (file_exists($phpbb_root_path . $file_struct['filename']))
+ {
+ $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
+ if (isset($expected_files[$file_struct['filename']]) && md5($contents) == $expected_files[$file_struct['filename']])
+ {
+ continue;
+ }
+ }
+
+ $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
+
+ switch ($status)
+ {
+ case 'modified':
+
+ $option = (isset($modified[$file_struct['filename']])) ? $modified[$file_struct['filename']] : 0;
+
+ switch ($option)
+ {
+ case MERGE_NO_MERGE_NEW:
+ $contents = file_get_contents($this->new_location . $original_filename);
+ break;
+
+ case MERGE_NO_MERGE_MOD:
+ $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
+ break;
+
+ default:
+ $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
+
+ $contents = implode("\n", $diff->merged_output());
+ unset($diff);
+ break;
+ }
+
+ $expected_files[$file_struct['filename']] = md5($contents);
+ $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
+ $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
+
+ $file_list['status']++;
+ $processed++;
+
+ break;
+
+ case 'conflict':
+
+ $option = $conflicts[$file_struct['filename']];
+ $contents = '';
+
+ switch ($option)
+ {
+ case MERGE_NO_MERGE_NEW:
+ $contents = file_get_contents($this->new_location . $original_filename);
+ break;
+
+ case MERGE_NO_MERGE_MOD:
+ $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
+ break;
+
+ default:
+
+ $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
+
+ if ($option == MERGE_NEW_FILE)
+ {
+ $contents = implode("\n", $diff->merged_new_output());
+ }
+ else if ($option == MERGE_MOD_FILE)
+ {
+ $contents = implode("\n", $diff->merged_orig_output());
+ }
+ else
+ {
+ unset($diff);
+ break 2;
+ }
+
+ unset($diff);
+ break;
+ }
+
+ $expected_files[$file_struct['filename']] = md5($contents);
+ $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
+ $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
+
+ $file_list['status']++;
+ $processed++;
+
+ break;
+ }
+ }
+ }
+ $cache->put('_expected_files', $expected_files);
+ }
+
+ $file_list['status'] = -1;
+ $cache->put('_diff_files', $file_list);
+
+ if ($request->variable('download', false))
+ {
+ $this->include_file('includes/functions_compress.' . $phpEx);
+
+ $use_method = $request->variable('use_method', '');
+ $methods = array('.tar');
+
+ $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
+ foreach ($available_methods as $type => $module)
+ {
+ if (!@extension_loaded($module))
+ {
+ continue;
+ }
+
+ $methods[] = $type;
+ }
+
+ // Let the user decide in which format he wants to have the pack
+ if (!$use_method)
+ {
+ $this->page_title = 'SELECT_DOWNLOAD_FORMAT';
+
+ $radio_buttons = '';
+ foreach ($methods as $method)
+ {
+ $radio_buttons .= '<label><input type="radio"' . ((!$radio_buttons) ? ' id="use_method"' : '') . ' class="radio" value="' . $method . '" name="use_method" /> ' . $method . '</label>';
+ }
+
+ $template->assign_vars(array(
+ 'S_DOWNLOAD_FILES' => true,
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
+ 'RADIO_BUTTONS' => $radio_buttons,
+ 'S_HIDDEN_FIELDS' => $s_hidden_fields)
+ );
+
+ // To ease the update process create a file location map
+ $update_list = $cache->get('_update_list');
+ $script_path = ($config['force_server_vars']) ? (($config['script_path'] == '/') ? '/' : $config['script_path'] . '/') : $user->page['root_script_path'];
+
+ foreach ($update_list as $status => $files)
+ {
+ if ($status == 'up_to_date' || $status == 'no_update' || $status == 'status' || $status == 'status_deleted')
+ {
+ continue;
+ }
+
+ foreach ($files as $file_struct)
+ {
+ if (in_array($file_struct['filename'], $no_update))
+ {
+ continue;
+ }
+
+ $template->assign_block_vars('location', array(
+ 'SOURCE' => htmlspecialchars($file_struct['filename']),
+ 'DESTINATION' => $script_path . htmlspecialchars($file_struct['filename']),
+ ));
+ }
+ }
+ return;
+ }
+
+ if (!in_array($use_method, $methods))
+ {
+ $use_method = '.tar';
+ }
+
+ $update_mode = 'download';
+ }
+ else
+ {
+ $this->include_file('includes/functions_transfer.' . $phpEx);
+
+ // Choose FTP, if not available use fsock...
+ $method = basename($request->variable('method', ''));
+ $submit = (isset($_POST['submit'])) ? true : false;
+ $test_ftp_connection = $request->variable('test_connection', '');
+
+ if (!$method || !class_exists($method))
+ {
+ $method = 'ftp';
+ $methods = transfer::methods();
+
+ if (!in_array('ftp', $methods))
+ {
+ $method = $methods[0];
+ }
+ }
+
+ $test_connection = false;
+ if ($test_ftp_connection || $submit)
+ {
+ $transfer = new $method(
+ $request->variable('host', ''),
+ $request->variable('username', ''),
+ htmlspecialchars_decode($request->untrimmed_variable('password', '')),
+ $request->variable('root_path', ''),
+ $request->variable('port', ''),
+ $request->variable('timeout', '')
+ );
+ $test_connection = $transfer->open_session();
+
+ // Make sure that the directory is correct by checking for the existence of common.php
+ if ($test_connection === true)
+ {
+ // Check for common.php file
+ if (!$transfer->file_exists($phpbb_root_path, 'common.' . $phpEx))
+ {
+ $test_connection = 'ERR_WRONG_PATH_TO_PHPBB';
+ }
+ }
+
+ $transfer->close_session();
+
+ // Make sure the login details are correct before continuing
+ if ($submit && $test_connection !== true)
+ {
+ $submit = false;
+ $test_ftp_connection = true;
+ }
+ }
+
+ $s_hidden_fields .= build_hidden_fields(array('method' => $method));
+
+ if (!$submit)
+ {
+ $this->page_title = 'SELECT_FTP_SETTINGS';
+
+ if (!class_exists($method))
+ {
+ trigger_error('Method does not exist.', E_USER_ERROR);
+ }
+
+ $requested_data = call_user_func(array($method, 'data'));
+ foreach ($requested_data as $data => $default)
+ {
+ $template->assign_block_vars('data', array(
+ 'DATA' => $data,
+ 'NAME' => $user->lang[strtoupper($method . '_' . $data)],
+ 'EXPLAIN' => $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'],
+ 'DEFAULT' => $request->variable($data, (string) $default),
+ ));
+ }
+
+ $template->assign_vars(array(
+ 'S_CONNECTION_SUCCESS' => ($test_ftp_connection && $test_connection === true) ? true : false,
+ 'S_CONNECTION_FAILED' => ($test_ftp_connection && $test_connection !== true) ? true : false,
+ 'ERROR_MSG' => ($test_ftp_connection && $test_connection !== true) ? $user->lang[$test_connection] : '',
+
+ 'S_FTP_UPLOAD' => true,
+ 'UPLOAD_METHOD' => $method,
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
+ 'U_DOWNLOAD_METHOD' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;download=1"),
+ 'S_HIDDEN_FIELDS' => $s_hidden_fields,
+ ));
+
+ return;
+ }
+
+ $update_mode = 'upload';
+ }
+
+ // Now update the installation or download the archive...
+ $download_filename = 'update_' . $this->update_info['version']['from'] . '_to_' . $this->update_info['version']['to'];
+ $archive_filename = $download_filename . '_' . time() . '_' . unique_id();
+
+ // Now init the connection
+ if ($update_mode == 'download')
+ {
+ if ($this->filesystem->is_writable($phpbb_root_path . 'store/'))
+ {
+ trigger_error(sprintf('The directory ā€œ%sā€ is not writable.', $phpbb_root_path . 'store/'), E_USER_ERROR);
+ }
+
+ if ($use_method == '.zip')
+ {
+ $compress = new compress_zip('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method);
+ }
+ else
+ {
+ $compress = new compress_tar('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method, $use_method);
+ }
+ }
+ else
+ {
+ $transfer = new $method(
+ $request->variable('host', ''),
+ $request->variable('username', ''),
+ htmlspecialchars_decode($request->untrimmed_variable('password', '')),
+ $request->variable('root_path', ''),
+ $request->variable('port', ''),
+ $request->variable('timeout', '')
+ );
+ $transfer->open_session();
+ }
+
+ // Ok, go through the update list and do the operations based on their status
+ foreach ($update_list as $status => $files)
+ {
+ if (!is_array($files))
+ {
+ continue;
+ }
+
+ foreach ($files as $file_struct)
+ {
+ // Skip this file if the user selected to not update it
+ if (in_array($file_struct['filename'], $no_update))
+ {
+ continue;
+ }
+
+ $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
+
+ switch ($status)
+ {
+ case 'new':
+ case 'new_conflict':
+ case 'not_modified':
+
+ if ($update_mode == 'download')
+ {
+ $compress->add_custom_file($this->new_location . $original_filename, $file_struct['filename']);
+ }
+ else
+ {
+ if ($status != 'new')
+ {
+ $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
+ }
+
+ // New directory too?
+ $dirname = dirname($file_struct['filename']);
+
+ if ($dirname && !file_exists($phpbb_root_path . $dirname))
+ {
+ $transfer->make_dir($dirname);
+ }
+
+ $transfer->copy_file($this->new_location . $original_filename, $file_struct['filename']);
+ }
+ break;
+
+ case 'modified':
+
+ $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
+
+ if ($update_mode == 'download')
+ {
+ $compress->add_data($contents, $file_struct['filename']);
+ }
+ else
+ {
+ // @todo add option to specify if a backup file should be created?
+ $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
+ $transfer->write_file($file_struct['filename'], $contents);
+ }
+ break;
+
+ case 'conflict':
+
+ $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
+
+ if ($update_mode == 'download')
+ {
+ $compress->add_data($contents, $file_struct['filename']);
+ }
+ else
+ {
+ $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
+ $transfer->write_file($file_struct['filename'], $contents);
+ }
+ break;
+
+ case 'deleted':
+
+ if ($update_mode != 'download')
+ {
+ $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
+ }
+ break;
+ }
+ }
+ }
+
+ if ($update_mode == 'download')
+ {
+ $compress->close();
+
+ $compress->download($archive_filename, $download_filename);
+ @unlink($phpbb_root_path . 'store/' . $archive_filename . $use_method);
+
+ exit;
+ }
+ else
+ {
+ $transfer->close_session();
+
+ $template->assign_vars(array(
+ 'S_UPLOAD_SUCCESS' => true,
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"))
+ );
+ return;
+ }
+
+ break;
+
+ }
+ }
+
+ /**
+ * Show file diff
+ */
+ function show_diff(&$update_list)
+ {
+ global $phpbb_root_path, $template, $user, $request, $phpbb_adm_relative_path;
+
+ $this->tpl_name = 'install_update_diff';
+
+ $this->page_title = 'VIEWING_FILE_DIFF';
+
+ $status = $request->variable('status', '');
+ $file = $request->variable('file', '');
+ $diff_mode = $request->variable('diff_mode', 'inline');
+
+ // First of all make sure the file is within our file update list with the correct status
+ $found_entry = array();
+ foreach ($update_list[$status] as $index => $file_struct)
+ {
+ if ($file_struct['filename'] === $file)
+ {
+ $found_entry = $update_list[$status][$index];
+ }
+ }
+
+ if (empty($found_entry))
+ {
+ trigger_error($user->lang['FILE_DIFF_NOT_ALLOWED'], E_USER_ERROR);
+ }
+
+ // If the status is 'up_to_date' then we do not need to show a diff
+ if ($status == 'up_to_date')
+ {
+ trigger_error($user->lang['FILE_ALREADY_UP_TO_DATE'], E_USER_ERROR);
+ }
+
+ $original_file = ($found_entry['custom']) ? $found_entry['original'] : $file;
+
+ // Get the correct diff
+ switch ($status)
+ {
+ case 'conflict':
+ $option = $request->variable('op', 0);
+
+ switch ($option)
+ {
+ case MERGE_NO_MERGE_NEW:
+ case MERGE_NO_MERGE_MOD:
+
+ $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
+
+ $template->assign_var('S_DIFF_NEW_FILE', true);
+ $diff_mode = 'inline';
+ $this->page_title = 'VIEWING_FILE_CONTENTS';
+
+ break;
+
+ // Merge differences and use new phpBB code for conflicted blocks
+ case MERGE_NEW_FILE:
+ case MERGE_MOD_FILE:
+
+ $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
+
+ $template->assign_vars(array(
+ 'S_DIFF_CONFLICT_FILE' => true,
+ 'NUM_CONFLICTS' => $diff->get_num_conflicts())
+ );
+
+ $diff = $this->return_diff($phpbb_root_path . $file, ($option == MERGE_NEW_FILE) ? $diff->merged_new_output() : $diff->merged_orig_output());
+ break;
+
+ // Download conflict file
+ default:
+
+ $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
+
+ header('Pragma: no-cache');
+ header("Content-Type: application/octetstream; name=\"$file\"");
+ header("Content-disposition: attachment; filename=$file");
+
+ @set_time_limit(0);
+
+ echo implode("\n", $diff->get_conflicts_content());
+
+ flush();
+ exit;
+
+ break;
+ }
+
+ break;
+
+ case 'modified':
+ $option = $request->variable('op', 0);
+
+ switch ($option)
+ {
+ case MERGE_NO_MERGE_NEW:
+ case MERGE_NO_MERGE_MOD:
+
+ $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
+
+ $template->assign_var('S_DIFF_NEW_FILE', true);
+ $diff_mode = 'inline';
+ $this->page_title = 'VIEWING_FILE_CONTENTS';
+
+ break;
+
+ default:
+ $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $original_file, $this->new_location . $file);
+ $diff = $this->return_diff($phpbb_root_path . $file, $diff->merged_output());
+ break;
+ }
+ break;
+
+ case 'not_modified':
+ case 'new_conflict':
+ $diff = $this->return_diff($phpbb_root_path . $file, $this->new_location . $original_file);
+ break;
+
+ case 'new':
+
+ $diff = $this->return_diff(array(), $this->new_location . $original_file);
+
+ $template->assign_var('S_DIFF_NEW_FILE', true);
+ $diff_mode = 'inline';
+ $this->page_title = 'VIEWING_FILE_CONTENTS';
+
+ break;
+
+ case 'deleted':
+
+ $diff = $this->return_diff(array(), $phpbb_root_path . $original_file);
+
+ $template->assign_var('S_DIFF_NEW_FILE', true);
+ $diff_mode = 'inline';
+ $this->page_title = 'VIEWING_FILE_CONTENTS';
+
+ break;
+ }
+
+ $diff_mode_options = '';
+ foreach (array('side_by_side', 'inline', 'unified', 'raw') as $option)
+ {
+ $diff_mode_options .= '<option value="' . $option . '"' . (($diff_mode == $option) ? ' selected="selected"' : '') . '>' . $user->lang['DIFF_' . strtoupper($option)] . '</option>';
+ }
+
+ // Now the correct renderer
+ $render_class = 'diff_renderer_' . $diff_mode;
+
+ if (!class_exists($render_class))
+ {
+ trigger_error('Chosen diff mode is not supported', E_USER_ERROR);
+ }
+
+ $renderer = new $render_class();
+
+ $template->assign_vars(array(
+ 'DIFF_CONTENT' => $renderer->get_diff_content($diff),
+ 'DIFF_MODE' => $diff_mode,
+ 'S_DIFF_MODE_OPTIONS' => $diff_mode_options,
+ 'S_SHOW_DIFF' => true,
+ ));
+
+ unset($diff, $renderer);
+ }
+
+ /**
+ * Collect all file status infos we need for the update by diffing all files
+ */
+ function get_update_structure(&$update_list, $expected_files)
+ {
+ global $phpbb_root_path, $phpEx, $user;
+
+ if ($update_list === false)
+ {
+ $update_list = array(
+ 'up_to_date' => array(),
+ 'new' => array(),
+ 'not_modified' => array(),
+ 'modified' => array(),
+ 'new_conflict' => array(),
+ 'conflict' => array(),
+ 'no_update' => array(),
+ 'deleted' => array(),
+ 'status' => 0,
+ 'status_deleted'=> 0,
+ );
+ }
+
+ /* if (!empty($this->update_info['custom']))
+ {
+ foreach ($this->update_info['custom'] as $original_file => $file_ary)
+ {
+ foreach ($file_ary as $index => $file)
+ {
+ $this->make_update_diff($update_list, $original_file, $file, true);
+ }
+ }
+ } */
+
+ // Get a list of those files which are completely new by checking with file_exists...
+ $num_bytes_processed = 0;
+
+ foreach ($this->update_info['files'] as $index => $file)
+ {
+ if (is_int($update_list['status']) && $index < $update_list['status'])
+ {
+ continue;
+ }
+
+ if ($num_bytes_processed >= 500 * 1024)
+ {
+ return;
+ }
+
+ if (!file_exists($phpbb_root_path . $file))
+ {
+ // Make sure the update files are consistent by checking if the file is in new_files...
+ if (!file_exists($this->new_location . $file))
+ {
+ trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
+ }
+
+ // If the file exists within the old directory the file got removed and we will write it back
+ // not a biggie, but we might want to state this circumstance separately later.
+ // if (file_exists($this->old_location . $file))
+ // {
+ // $update_list['removed'][] = $file;
+ // }
+
+ /* Only include a new file as new if the underlying path exist
+ // The path normally do not exist if the original style or language has been removed
+ if (file_exists($phpbb_root_path . dirname($file)))
+ {
+ $this->get_custom_info($update_list['new'], $file);
+ $update_list['new'][] = array('filename' => $file, 'custom' => false);
+ }
+ else
+ {
+ // Do not include style-related or language-related content
+ if (strpos($file, 'styles/') !== 0 && strpos($file, 'language/') !== 0)
+ {
+ $update_list['no_update'][] = $file;
+ }
+ }*/
+
+ if (!phpbb_ignore_new_file_on_update($phpbb_root_path, $file))
+ {
+ $this->get_custom_info($update_list['new'], $file);
+ $update_list['new'][] = array('filename' => $file, 'custom' => false);
+ }
+
+ // unset($this->update_info['files'][$index]);
+ }
+ else
+ {
+ // not modified?
+ $this->make_update_diff($update_list, $file, $file, $expected_files);
+ }
+
+ $num_bytes_processed += (file_exists($this->new_location . $file)) ? filesize($this->new_location . $file) : 100 * 1024;
+ $update_list['status']++;
+ }
+
+ foreach ($this->update_info['deleted'] as $index => $file)
+ {
+ if (is_int($update_list['status_deleted']) && $index < $update_list['status_deleted'])
+ {
+ continue;
+ }
+
+ if ($num_bytes_processed >= 500 * 1024)
+ {
+ return;
+ }
+
+ if (file_exists($phpbb_root_path . $file))
+ {
+ $update_list['deleted'][] = array('filename' => $file, 'custom' => false, 'as_expected' => false);
+ $num_bytes_processed += filesize($phpbb_root_path . $file);
+ }
+
+ $update_list['status_deleted']++;
+ $update_list['status']++;
+ }
+
+ $update_list['status_deleted'] = -1;
+ $update_list['status'] = -1;
+
+/* if (!sizeof($this->update_info['files']))
+ {
+ return $update_list;
+ }
+
+ // Now diff the remaining files to get information about their status (not modified/modified/up-to-date)
+
+ // not modified?
+ foreach ($this->update_info['files'] as $index => $file)
+ {
+ $this->make_update_diff($update_list, $file, $file);
+ }
+
+ // Now to the styles...
+ if (empty($this->update_info['custom']))
+ {
+ return $update_list;
+ }
+
+ foreach ($this->update_info['custom'] as $original_file => $file_ary)
+ {
+ foreach ($file_ary as $index => $file)
+ {
+ $this->make_update_diff($update_list, $original_file, $file, true);
+ }
+ }
+
+ return $update_list;*/
+ }
+
+ /**
+ * Compare files for storage in update_list
+ */
+ function make_update_diff(&$update_list, $original_file, $file, $expected_files, $custom = false)
+ {
+ global $phpbb_root_path, $user;
+
+ $update_ary = array('filename' => $file, 'custom' => $custom, 'as_expected' => false);
+
+ if ($custom)
+ {
+ $update_ary['original'] = $original_file;
+ }
+
+ if (file_exists($phpbb_root_path . $file))
+ {
+ $content = file_get_contents($phpbb_root_path . $file);
+
+ if (isset($expected_files[$file]) && // the user already selected what to do with this file
+ ($expected_files[$file] === false || // the user wanted this file to stay the same, so just assume it's alright
+ $expected_files[$file] === md5($content)))
+ {
+ // the file contains what it was supposed to contain after the merge
+ $update_ary['as_expected'] = true;
+ $update_ary['was_ignored'] = ($expected_files[$file] === false);
+ $update_list['up_to_date'][] = $update_ary;
+
+ return;
+ }
+ }
+
+ // we only want to know if the files are successfully merged and newlines could result in errors (duplicate addition of lines and such things)
+ // Therefore we check for empty diffs with two methods, preserving newlines and not preserving them (which mostly works best, therefore the first option)
+
+ // On a successfull update the new location file exists but the old one does not exist.
+ // Check for this circumstance, the new file need to be up-to-date with the current file then...
+ if (!file_exists($this->old_location . $original_file) && file_exists($this->new_location . $original_file) && file_exists($phpbb_root_path . $file))
+ {
+ $tmp = array(
+ 'file1' => file_get_contents($this->new_location . $original_file),
+ 'file2' => $content,
+ );
+
+ // We need to diff the contents here to make sure the file is really the one we expect
+ $diff = new diff($tmp['file1'], $tmp['file2'], false);
+ $empty = $diff->is_empty();
+
+ unset($tmp, $diff);
+
+ // if there are no differences we have an up-to-date file...
+ if ($empty)
+ {
+ $update_list['up_to_date'][] = $update_ary;
+ return;
+ }
+
+ // If no other status matches we have another file in the way...
+ $update_list['new_conflict'][] = $update_ary;
+ return;
+ }
+
+ // Old file removed?
+ if (file_exists($this->old_location . $original_file) && !file_exists($this->new_location . $original_file))
+ {
+ return;
+ }
+
+ // Check for existance, else abort immediately
+ if (!file_exists($this->old_location . $original_file) || !file_exists($this->new_location . $original_file))
+ {
+ trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
+ }
+
+ $preserve_cr_ary = array(false, true);
+
+ foreach ($preserve_cr_ary as $preserve_cr)
+ {
+ $tmp = array(
+ 'file1' => file_get_contents($this->old_location . $original_file),
+ 'file2' => $content,
+ );
+
+ // We need to diff the contents here to make sure the file is really the one we expect
+ $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
+ $empty_1 = $diff->is_empty();
+
+ unset($tmp, $diff);
+
+ $tmp = array(
+ 'file1' => file_get_contents($this->new_location . $original_file),
+ 'file2' => $content,
+ );
+
+ $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
+ $empty_2 = $diff->is_empty();
+
+ unset($tmp, $diff);
+
+ // If the file is not modified we are finished here...
+ if ($empty_1)
+ {
+ // Further check if it is already up to date - it could happen that non-modified files
+ // slip through
+ if ($empty_2)
+ {
+ $update_list['up_to_date'][] = $update_ary;
+ return;
+ }
+
+ $update_list['not_modified'][] = $update_ary;
+ return;
+ }
+
+ // If the file had been modified then we need to check if it is already up to date
+
+ // if there are no differences we have an up-to-date file...
+ if ($empty_2)
+ {
+ $update_list['up_to_date'][] = $update_ary;
+ return;
+ }
+ }
+
+ $conflicts = false;
+
+ foreach ($preserve_cr_ary as $preserve_cr)
+ {
+ // if the file is modified we try to make sure a merge succeed
+ $tmp = array(
+ 'orig' => file_get_contents($this->old_location . $original_file),
+ 'final1' => file_get_contents($phpbb_root_path . $file),
+ 'final2' => file_get_contents($this->new_location . $original_file),
+ );
+
+ $diff = new diff3($tmp['orig'], $tmp['final1'], $tmp['final2'], $preserve_cr);
+ unset($tmp);
+
+ if (!$diff->get_num_conflicts())
+ {
+ $tmp = array(
+ 'file1' => file_get_contents($phpbb_root_path . $file),
+ 'file2' => implode("\n", $diff->merged_output()),
+ );
+
+ // now compare the merged output with the original file to see if the modified file is up to date
+ $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
+ $empty = $diff2->is_empty();
+
+ unset($diff, $diff2);
+
+ if ($empty)
+ {
+ $update_list['up_to_date'][] = $update_ary;
+ return;
+ }
+
+ // If we preserve cr tag it as modified because the conflict would not show in this mode anyway
+ if ($preserve_cr)
+ {
+ $update_list['modified'][] = $update_ary;
+ return;
+ }
+ }
+ else
+ {
+ // There is one special case... users having merged with a conflicting file... we need to check this
+ $tmp = array(
+ 'file1' => file_get_contents($phpbb_root_path . $file),
+ 'file2' => implode("\n", $diff->merged_new_output()),
+ );
+
+ $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
+ $empty = $diff2->is_empty();
+
+ if (!$empty)
+ {
+ unset($tmp, $diff2);
+
+ // We check if the user merged with his output
+ $tmp = array(
+ 'file1' => file_get_contents($phpbb_root_path . $file),
+ 'file2' => implode("\n", $diff->merged_orig_output()),
+ );
+
+ $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
+ $empty = $diff2->is_empty();
+ }
+
+ if (!$empty)
+ {
+ $conflicts = $diff->get_num_conflicts();
+ }
+
+ unset($diff, $diff2);
+
+ if ($empty)
+ {
+ // A conflict got resolved...
+ $update_list['up_to_date'][] = $update_ary;
+ return;
+ }
+ }
+ }
+
+ if ($conflicts !== false)
+ {
+ $update_ary['conflicts'] = $conflicts;
+ $update_list['conflict'][] = $update_ary;
+ return;
+ }
+
+ // If no other status matches we have a modified file...
+ $update_list['modified'][] = $update_ary;
+ }
+
+ /**
+ * Update update_list with custom new files
+ */
+ function get_custom_info(&$update_list, $file)
+ {
+ if (empty($this->update_info['custom']))
+ {
+ return;
+ }
+
+ if (isset($this->update_info['custom'][$file]))
+ {
+ foreach ($this->update_info['custom'][$file] as $_file)
+ {
+ $update_list[] = array('filename' => $_file, 'custom' => true, 'original' => $file);
+ }
+ }
+ }
+
+ /**
+ * Get remote file
+ */
+ function get_file($mode)
+ {
+ global $user, $db;
+
+ $errstr = '';
+ $errno = 0;
+
+ switch ($mode)
+ {
+ case 'update_info':
+ global $phpbb_root_path, $phpEx;
+
+ $update_info = array();
+ include($phpbb_root_path . 'install/update/index.' . $phpEx);
+
+ $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
+ $errstr = ($info === false) ? $user->lang['WRONG_INFO_FILE_FORMAT'] : '';
+
+ if ($info !== false)
+ {
+ // We assume that all file extensions have been renamed to .$phpEx,
+ // if someone is using a non .php file extension for php files.
+ // However, in $update_info['files'] we use hardcoded .php.
+ // We therefore replace .php with .$phpEx.
+ $info['files'] = preg_replace('/\.php$/i', ".$phpEx", $info['files']);
+
+ // Adjust the update info file to hold some specific style-related information
+ $info['custom'] = array();
+/*
+ // Get custom installed styles...
+ $sql = 'SELECT style_name, style_path
+ FROM ' . STYLES_TABLE . "
+ WHERE LOWER(style_name) NOT IN ('prosilver')";
+ $result = $db->sql_query($sql);
+
+ $templates = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $templates[] = $row;
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($templates))
+ {
+ foreach ($info['files'] as $filename)
+ {
+ // Template update?
+ if (strpos(strtolower($filename), 'styles/prosilver/template/') === 0)
+ {
+ foreach ($templates as $row)
+ {
+ $info['custom'][$filename][] = str_replace('/prosilver/', '/' . $row['style_path'] . '/', $filename);
+ }
+ }
+ }
+ }
+*/
+ }
+ break;
+
+ default:
+ trigger_error('Mode for getting remote file not specified', E_USER_ERROR);
+ break;
+ }
+
+ if ($info === false)
+ {
+ trigger_error($errstr, E_USER_ERROR);
+ }
+
+ return $info;
+ }
+
+ /**
+ * Function for including files...
+ */
+ function include_file($filename)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ if (!empty($this->update_info['files']) && in_array($filename, $this->update_info['files']))
+ {
+ include_once($this->new_location . $filename);
+ }
+ else
+ {
+ include_once($phpbb_root_path . $filename);
+ }
+ }
+
+ /**
+ * Wrapper for returning a diff object
+ */
+ function return_diff()
+ {
+ $args = func_get_args();
+ $three_way_diff = (func_num_args() > 2) ? true : false;
+
+ $file1 = array_shift($args);
+ $file2 = array_shift($args);
+
+ $tmp['file1'] = (!empty($file1) && is_string($file1)) ? file_get_contents($file1) : $file1;
+ $tmp['file2'] = (!empty($file2) && is_string($file2)) ? file_get_contents($file2) : $file2;
+
+ if ($three_way_diff)
+ {
+ $file3 = array_shift($args);
+ $tmp['file3'] = (!empty($file3) && is_string($file3)) ? file_get_contents($file3) : $file3;
+
+ $diff = new diff3($tmp['file1'], $tmp['file2'], $tmp['file3']);
+ }
+ else
+ {
+ $diff = new diff($tmp['file1'], $tmp['file2']);
+ }
+
+ unset($tmp);
+
+ return $diff;
+ }
+}
diff --git a/phpBB/install_old/phpinfo.php b/phpBB/install_old/phpinfo.php
new file mode 100644
index 0000000000..1512b00563
--- /dev/null
+++ b/phpBB/install_old/phpinfo.php
@@ -0,0 +1,14 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+phpinfo();