diff options
Diffstat (limited to 'phpBB/install_old')
| -rw-r--r-- | phpBB/install_old/convertors/convert_phpbb20.php | 975 | ||||
| -rw-r--r-- | phpBB/install_old/convertors/functions_phpbb20.php | 1984 | ||||
| -rw-r--r-- | phpBB/install_old/data/confusables.php | 645 | ||||
| -rw-r--r-- | phpBB/install_old/database_update.php | 267 | ||||
| -rw-r--r-- | phpBB/install_old/index.php | 867 | ||||
| -rw-r--r-- | phpBB/install_old/install_convert.php | 2153 | ||||
| -rw-r--r-- | phpBB/install_old/install_update.php | 1790 | ||||
| -rw-r--r-- | phpBB/install_old/phpinfo.php | 14 |
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="\1"]', $message); + $message = preg_replace('/\[quote=\\\"(.*?)\\\"\]/s', '[quote="\1"]', $message); + + // let's hope that this solves more problems than it causes. Deal with escaped quotes. + $message = str_replace('\"', '"', $message); + $message = str_replace('\"', '"', $message); + } + + // Already the new user id ;) + $user_id = $convert->row['poster_id']; + + $message = str_replace('<br />', "\n", $message); + $message = str_replace('<', '<', $message); + $message = str_replace('>', '>', $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('<', '<', $code); + return str_replace('>', '>', $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ē¹','ļ¼'=>'1','š'=>'1','š'=>'1','š£'=>'1','š'=>'1','š·'=>'1','ā'=>'1','ā'=>'1','š'=>'1','š¼'=>'1','š°'=>'1','š'=>'1','š'=>'1','š“'=>'1','šØ'=>'1','š'=>'1','š'=>'1','š'=>'1','šø'=>'1','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','ć '=>'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.','ć½'=>'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ē¹','ļ¼'=>'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ē¹','ą©§'=>'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/c','ā'=>'a/s','Ʀ'=>'ae','ļ½'=>'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/o','ā'=>'c/u','ļ½'=>'d','ā
¾'=>'d','ā
'=>'d','š'=>'d','š'=>'d','š
'=>'d','š¹'=>'d','š'=>'d','š”'=>'d','š'=>'d','š'=>'d','š½'=>'d','š±'=>'d','š„'=>'d','š'=>'d','š'=>'d','É'=>'dĢ','Ę'=>'dĢ','É'=>'dĢ¢','Ä'=>'d̵','dz'=>'dz','Ē'=>'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Ģ”','ļ½'=>'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̵','įæ¾'=>'Ź»','ā'=>'Ź»','ā'=>'Ź»','ʽ'=>'Ź»','ā³'=>'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','š„'=>'Č·','ļ½'=>'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','ļ½'=>'o','ā“'=>'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Ģ','ļ½'=>'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Ģ¢','ā«'=>'Ź','ā¬'=>'ŹŹ','ā'=>'ŹŹŹ','āØ'=>'ŹŹŹŹ','ļ½'=>'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','ļ½'=>'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','ā
ŗ'=>'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̵','Č'=>'Ź','?'=>'Ź','ļ¼'=>'Ź','ā'=>'ŹŹ','ā'=>'ŹĒ','į¾½'=>'ʼ','᾿'=>'ʼ','ā'=>'ʼ','ʾ'=>'ʼ','!'=>'Ē','ļ¼'=>'Ē','ā'=>'ĒŹ','ā¼'=>'ĒĒ','āŗ'=>'α','š'=>'α','š¼'=>'α','š¶'=>'α','š°'=>'α','šŖ'=>'α','š'=>'β','š½'=>'β','š·'=>'β','š±'=>'β','š«'=>'β','ā½'=>'γ','š'=>'γ','š¾'=>'γ','šø'=>'γ','š²'=>'γ','š¬'=>'γ','š
'=>'Ī“','šæ'=>'Ī“','š¹'=>'Ī“','š³'=>'Ī“','š'=>'Ī“','š'=>'Ļ','š'=>'ζ','š'=>'ζ','š»'=>'ζ','šµ'=>'ζ','šÆ'=>'ζ','ā¬'=>'Īø','š'=>'Īø','š'=>'Īø','š'=>'Īø','š'=>'Īø','š½'=>'Īø','š'=>'Īø','š·'=>'Īø','š'=>'Īø','š±'=>'Īø','š
'=>'Īø','š'=>'Ī»','š'=>'Ī»','š'=>'Ī»','šŗ'=>'Ī»','š“'=>'Ī»','š¬'=>'Ī','š¦'=>'Ī','š '=>'Ī','š'=>'Ī','š'=>'μ','š'=>'μ','š'=>'μ','š»'=>'μ','šµ'=>'μ','š'=>'ξ','š'=>'ξ','š'=>'ξ','š½'=>'ξ','š·'=>'ξ','šÆ'=>'Ī','š©'=>'Ī','š£'=>'Ī','š'=>'Ī','ā¼'=>'Ļ','š'=>'Ļ','š”'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š
'=>'Ļ','š'=>'Ļ','šæ'=>'Ļ','š'=>'Ļ','š¹'=>'Ļ','š'=>'Ļ','ᓨ'=>'Ļ','ā'=>'Ī ','š·'=>'Ī ','š±'=>'Ī ','š«'=>'Ī ','š„'=>'Ī ','š'=>'Ī ','š'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š¼'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š'=>'Ļ','š½'=>'Ļ','š'=>'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>® Forum Software © 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"> </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) . '&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&sub=update_db&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&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 . "&sub=$option&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>® Forum Software © 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 />» 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 . ' ' . $tpl_no : $tpl_no . ' ' . $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}&sub=intro&new_conv=1&language=$language", + 'U_CONTINUE_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&sub=in_progress&tag={$options['tag']}{$options['step']}&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&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}&language=$language&sub=settings&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}&sub=in_progress&tag=$convertor_tag&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}&sub=settings&tag=$convertor_tag&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}&sub=in_progress&tag={$convert->convertor_tag}&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('&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('&current_table=' . $current_table . '&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('&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('&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('&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}&sub=in_progress&tag={$convert->convertor_tag}$step&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}&sub=final&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('&jump=1&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('&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('&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&mode=$mode&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&mode=$mode&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&language=' . $user->data['user_lang']), + 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&mode=$mode&sub=update_db"), + 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&mode=$mode&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&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&mode=$mode&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&mode=$mode&sub=file_check&action=diff&status=$status&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 . '&op=' . MERGE_MOD_FILE, + 'U_VIEW_NEW_FILE' => $diff_url . '&op=' . MERGE_NEW_FILE, + 'U_VIEW_NO_MERGE_MOD' => $diff_url . '&op=' . MERGE_NO_MERGE_MOD, + 'U_VIEW_NO_MERGE_NEW' => $diff_url . '&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&mode=$mode&sub=file_check"), + 'U_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&mode=$mode&sub=update_files"), + 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&mode=$mode&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&mode=$mode&sub=update_files&" . implode('&', $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&mode=$mode&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&mode=$mode&sub=update_files"), + 'U_DOWNLOAD_METHOD' => append_sid($this->p_master->module_url, "language=$language&mode=$mode&sub=update_files&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&mode=$mode&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(); |
