aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--phpBB/includes/functions_convert.php2280
-rw-r--r--phpBB/install/convertors/convert_phpbb20.php847
-rw-r--r--phpBB/install/convertors/functions_phpbb20.php1307
-rw-r--r--phpBB/install/install_convert.php1667
4 files changed, 6101 insertions, 0 deletions
diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php
new file mode 100644
index 0000000000..0895e1b1fc
--- /dev/null
+++ b/phpBB/includes/functions_convert.php
@@ -0,0 +1,2280 @@
+<?php
+/**
+*
+* @package install
+* @version $Id$
+* @copyright (c) 2006 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/*
+* @todo Make all spellings consistant with those in the main code (eg smilie, etc) as there are several used
+*/
+
+// Default avatar width/height
+define('DEFAULT_AVATAR_X', 80);
+define('DEFAULT_AVATAR_Y', 80);
+
+/**
+* Global functions - all functions can be used by convertors
+*/
+
+/**
+* Determine whether we are approaching the maximum execution time
+*/
+function still_on_time()
+{
+ static $max_execution_time, $start_time;
+
+ $time = explode(' ', microtime());
+ $current_time = $time[0] + $time[1];
+
+ if (empty($max_execution_time))
+ {
+ $max_execution_time = (function_exists('ini_get')) ? (int) ini_get('max_execution_time') : (int) get_cfg_var('max_execution_time');
+
+ // If zero, then set to something higher to not let the user catch the ten seconds barrier.
+ if ($max_execution_time === 0)
+ {
+ $max_execution_time = 300;
+ }
+
+ $max_execution_time = min(max(10, $max_execution_time), 300);
+
+ global $starttime;
+ $start_time = (empty($starttime)) ? $current_time : $starttime;
+ }
+
+ return (ceil($current_time - $start_time) < $max_execution_time) ? true : false;
+}
+
+// SIMPLE FUNCTIONS
+
+/**
+* Return the preceding value
+*/
+function dec($var)
+{
+ return --$var;
+}
+
+/**
+* Return the next value
+*/
+function inc($var)
+{
+ return ++$var;
+}
+
+/**
+* Return whether the value is positive
+*/
+function is_positive($n)
+{
+ return ($n > 0) ? 1 : 0;
+}
+
+/**
+* Boolean inverse of the value
+*/
+function not($var)
+{
+ return ($var) ? 0 : 1;
+}
+
+/**
+* Convert a textual value to it's equivalent boolean value
+*
+* @param string $str String to convert (converts yes, on, y, 1 and true to boolean true)
+* @return boolean The equivalent value
+*/
+function str_to_bool($str)
+{
+ $str = strtolower($str);
+ return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false;
+}
+
+/**
+* Function to mimic php's empty() function (it is the same)
+*/
+function is_empty($mixed)
+{
+ return empty($mixed);
+}
+
+/**
+* Convert the name of a user's primary group to the appropriate equivalent phpBB group id
+*
+* @param string $status The name of the group
+* @return int The group_id corresponding to the equivalent group
+*/
+function str_to_primary_group($status)
+{
+ switch (ucfirst(strtolower($status)))
+ {
+ case 'Administrator':
+ return get_group_id('administrators');
+ break;
+
+ case 'Super moderator':
+ case 'Global moderator':
+ case 'Moderator':
+ return get_group_id('global_moderators');
+ break;
+
+ case 'Guest':
+ case 'Anonymous':
+ return get_group_id('guests');
+ break;
+
+ default:
+ return get_group_id('registered');
+ break;
+ }
+}
+
+/**
+* Convert a boolean into the appropriate phpBB constant indicating whether the item is locked
+*/
+function is_item_locked($bool)
+{
+ return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED;
+}
+
+/**
+* Convert a value from days to seconds
+*/
+function days_to_seconds($days)
+{
+ return ($days * 86400);
+}
+
+/**
+* Determine whether a user is anonymous and return the appropriate new user_id
+*/
+function is_user_anonymous($user_id)
+{
+ return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS;
+}
+
+/**
+* Generate a key value based on existing values
+*
+* @param int $pad Amount to add to the maximum value
+* @return int Key value
+*/
+function auto_id($pad = 0)
+{
+ global $auto_id, $convert_row;
+
+ if (!empty($convert_row['max_id']))
+ {
+ return $convert_row['max_id'] + $pad;
+ }
+
+ return $auto_id + $pad;
+}
+
+/**
+* Convert a boolean into the appropriate phpBB constant indicating whether the user is active
+*/
+function set_user_type($user_active)
+{
+ return ($user_active) ? USER_NORMAL : USER_INACTIVE;
+}
+
+/**
+* Convert a value from minutes to hours
+*/
+function minutes_to_hours($minutes)
+{
+ return ($minutes / 3600);
+}
+
+/**
+* Return the group_id for a given group name
+*/
+function get_group_id($group_name)
+{
+ global $db, $group_mapping;
+
+ if (empty($group_mapping))
+ {
+ $sql = 'SELECT group_name, group_id
+ FROM ' . GROUPS_TABLE;
+ $result = $db->sql_query($sql);
+
+ $group_mapping = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id'];
+ }
+ $db->sql_freeresult($result);
+ }
+
+ if (!sizeof($group_mapping))
+ {
+ add_default_groups();
+ return get_group_id($group_name);
+ }
+
+ if (isset($group_mapping[strtoupper($group_name)]))
+ {
+ return $group_mapping[strtoupper($group_name)];
+ }
+
+ return $group_mapping['REGISTERED'];
+}
+
+/**
+* Generate the email hash stored in the users table
+*/
+function gen_email_hash($email)
+{
+ return (crc32(strtolower($email)) . strlen($email));
+}
+
+/**
+* Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked
+*/
+function is_topic_locked($bool)
+{
+ return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED;
+}
+
+/**
+* Generate a bbcode_uid value
+*/
+function make_uid($timestamp)
+{
+ return substr(md5($timestamp), 0, BBCODE_UID_LEN);
+}
+
+/**
+* Validate a website address
+*/
+function validate_website($url)
+{
+ return ($url == 'http://') ? '' : $url;
+}
+
+/**
+* Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination
+*/
+function null_to_zero($value)
+{
+ return ($value === NULL) ? 0 : $value;
+}
+
+/**
+* Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination
+*/
+function null_to_str($value)
+{
+ return ($value === NULL) ? '' : $value;
+}
+
+// EXTENDED FUNCTIONS
+
+/**
+* Get old config value
+*/
+function get_config_value($config_name)
+{
+ static $convert_config;
+
+ if (!isset($convert_config))
+ {
+ $convert_config = get_config();
+ }
+
+ if (!isset($convert_config[$config_name]))
+ {
+ return false;
+ }
+
+ return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name];
+}
+
+/**
+* Convert an IP address from the hexidecimal notation to normal dotted-quad notation
+*/
+function decode_ip($int_ip)
+{
+ if (!$int_ip)
+ {
+ return '';
+ }
+
+ $hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
+ return hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
+}
+
+/**
+* Reverse the encoding of wild-carded bans
+*/
+function decode_ban_ip($int_ip)
+{
+ return str_replace('255', '*', decode_ip($int_ip));
+}
+
+/**
+* Determine the MIME-type of a specified filename
+* This does not actually inspect the file, but simply uses the file extension
+*/
+function mimetype($filename)
+{
+ if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m))
+ {
+ return 'application/octet-stream';
+ }
+
+ switch (strtolower($m[1]))
+ {
+ case 'zip': return 'application/zip';
+ case 'jpeg': return 'image/jpeg';
+ case 'jpg': return 'image/jpeg';
+ case 'jpe': return 'image/jpeg';
+ case 'png': return 'image/png';
+ case 'gif': return 'image/gif';
+ case 'htm':
+ case 'html': return 'text/html';
+ case 'tif': return 'image/tiff';
+ case 'tiff': return 'image/tiff';
+ case 'ras': return 'image/x-cmu-raster';
+ case 'pnm': return 'image/x-portable-anymap';
+ case 'pbm': return 'image/x-portable-bitmap';
+ case 'pgm': return 'image/x-portable-graymap';
+ case 'ppm': return 'image/x-portable-pixmap';
+ case 'rgb': return 'image/x-rgb';
+ case 'xbm': return 'image/x-xbitmap';
+ case 'xpm': return 'image/x-xpixmap';
+ case 'xwd': return 'image/x-xwindowdump';
+ case 'z': return 'application/x-compress';
+ case 'gtar': return 'application/x-gtar';
+ case 'tgz': return 'application/x-gtar';
+ case 'gz': return 'application/x-gzip';
+ case 'tar': return 'application/x-tar';
+ case 'xls': return 'application/excel';
+ case 'pdf': return 'application/pdf';
+ case 'ppt': return 'application/powerpoint';
+ case 'rm': return 'application/vnd.rn-realmedia';
+ case 'wma': return 'audio/x-ms-wma';
+ case 'swf': return 'application/x-shockwave-flash';
+ case 'ief': return 'image/ief';
+ case 'doc':
+ case 'dot':
+ case 'wrd': return 'application/msword';
+ case 'ai':
+ case 'eps':
+ case 'ps': return 'application/postscript';
+ case 'asc':
+ case 'txt':
+ case 'c':
+ case 'cc':
+ case 'h':
+ case 'hh':
+ case 'cpp':
+ case 'hpp':
+ case 'php':
+ case 'php3': return 'text/plain';
+ default: return 'application/octet-stream';
+ }
+}
+
+/**
+* Obtain the dimensions of all remotely hosted avatars
+* This should only be called from execute_last
+* There can be significant network overhead if there are a large number of remote avatars
+* @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions
+*/
+function remote_avatar_dims()
+{
+ global $db;
+
+ $sql = 'SELECT user_id, user_avatar
+ FROM ' . USERS_TABLE . '
+ WHERE user_avatar_type = ' . AVATAR_REMOTE;
+ $result = $db->sql_query($sql);
+
+ $remote_avatars = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $remote_avatars[(int) $row['user_id']] = $row['user_avatar'];
+ }
+ $db->sql_freeresult($result);
+
+ foreach ($remote_avatars as $user_id => $avatar)
+ {
+ $width = (int) get_remote_avatar_dim($avatar, 0);
+ $height = (int) get_remote_avatar_dim($avatar, 1);
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . '
+ WHERE user_id = ' . $user_id;
+ $db->sql_query($sql);
+ }
+}
+
+function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false)
+{
+ global $config, $convert, $phpbb_root_path, $user;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (empty($convert->convertor['avatar_gallery_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__);
+ }
+
+ $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path);
+
+ if (is_dir($src_path))
+ {
+ copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, true, $relative_path);
+
+ // only doing 1 level deep. (ibf 1.x)
+ // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below).
+ // recursive subdirs ignored. -- i don't know if other forums support recursive galleries. if they do, this following code could be upgraded to be recursive.
+ if ($subdirs_as_galleries)
+ {
+ $dirlist = array();
+ if ($handle = @opendir($src_path))
+ {
+ while ($entry = readdir($handle))
+ {
+ if ($entry[0] == '.')
+ {
+ continue;
+ }
+
+ if (is_dir($src_path . $entry))
+ {
+ $dirlist[] = $entry;
+ }
+ }
+ closedir($handle);
+ }
+ else if ($dir = @dir($src_path))
+ {
+ while ($entry = $dir->read())
+ {
+ if (substr($entry, 0, 1) == '.')
+ {
+ continue;
+ }
+
+ if (is_dir($src_path . $entry))
+ {
+ $dirlist[] = $entry;
+ }
+ }
+ $dir->close();
+ }
+
+ for ($i = 0; $i < sizeof($dirlist); ++$i)
+ {
+ $dir = $dirlist[$i];
+ copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, true, $relative_path);
+ }
+ }
+ }
+}
+
+function import_attachment_files($category_name = '')
+{
+ global $config, $convert, $phpbb_root_path, $db, $user;
+
+ $sql = 'SELECT config_value AS upload_path
+ FROM ' . CONFIG_TABLE . "
+ WHERE config_name = 'upload_path'";
+ $result = $db->sql_query($sql);
+ $config['upload_path'] = $db->sql_fetchfield('upload_path');
+ $db->sql_freeresult($result);
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (empty($convert->convertor['upload_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__);
+ }
+
+ if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path)))
+ {
+ copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path);
+ }
+}
+
+function attachment_forum_perms($forum_id)
+{
+ if (!is_array($forum_id))
+ {
+ $forum_id = array($forum_id);
+ }
+
+ return serialize($forum_id);
+}
+
+// base64todec function
+// -> from php manual?
+function base64_unpack($string)
+{
+ $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-';
+ $base = strlen($chars);
+
+ $length = strlen($string);
+ $number = 0;
+
+ for ($i = 1; $i <= $length; $i++)
+ {
+ $pos = $length - $i;
+ $operand = strpos($chars, substr($string, $pos, 1));
+ $exponent = pow($base, $i-1);
+ $dec_value = $operand * $exponent;
+ $number += $dec_value;
+ }
+
+ return $number;
+}
+
+function import_attachment($source, $target = '')
+{
+ if (empty($source))
+ {
+ return '';
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (empty($convert->convertor['upload_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__);
+ }
+
+ $target = $config['upload_path'] . '/' . basename(empty($target) ? $source : $target);
+
+ if (strpos($source, $convert->convertor['upload_path']) !== 0)
+ {
+ $source = $convert->convertor['upload_path'] . $source;
+ }
+
+ if (file_exists(relative_base($source, $relative_path, __LINE__, __FILE__)))
+ {
+ if ($result = copy_file($source, $target, false, false, $relative_path))
+ {
+ // Thumbnails?
+ if (is_array($convert->convertor['thumbnails']))
+ {
+ $thumb_dir = $convert->convertor['thumbnails'][0];
+ $thumb_prefix = $convert->convertor['thumbnails'][1];
+ $thumb_source = $thumb_dir . $thumb_prefix . basename($source);
+
+ if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0)
+ {
+ $thumb_source = $convert->convertor['upload_path'] . $thumb_source;
+ }
+ $thumb_target = $config['upload_path'] . '/thumb_' . basename($target);
+
+ if (file_exists(relative_base($thumb_source, $relative_path, __LINE__, __FILE__)))
+ {
+ copy_file($thumb_source, $thumb_target, false, false, $relative_path);
+ }
+ }
+
+ return basename($target);
+ }
+ }
+
+ // Even though the image might not be displayed, the admin is able to manually copy the relevant files
+ return $source;
+}
+
+function import_rank($source, $target = '')
+{
+ if (empty($source))
+ {
+ return '';
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (!isset($convert->convertor['ranks_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__);
+ }
+
+ $target = $config['ranks_path'] . '/' . basename(empty($target) ? $source : $target);
+
+ if (!empty($convert->convertor['ranks_path']) && strpos($source, $convert->convertor['ranks_path']) !== 0)
+ {
+ $source = $convert->convertor['ranks_path'] . $source;
+ }
+
+ if (file_exists(relative_base($source, $relative_path, __LINE__, __FILE__)))
+ {
+ if ($result = copy_file($source, $target, false, false, $relative_path))
+ {
+ return basename($target);
+ }
+ }
+
+ // Even though the image might not be displayed, the admin is able to manually copy the relevant files
+ return $source;
+}
+
+function import_smiley($source, $target = '')
+{
+ if (empty($source))
+ {
+ return '';
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (!isset($convert->convertor['smilies_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__);
+ }
+
+ $target = $config['smilies_path'] . '/' . basename(empty($target) ? $source : $target);
+
+ if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0)
+ {
+ $source = $convert->convertor['smilies_path'] . $source;
+ }
+
+ if (file_exists(relative_base($source, $relative_path, __LINE__, __FILE__)))
+ {
+ if ($result = copy_file($source, $target, false, false, $relative_path))
+ {
+ return basename($target);
+ }
+ }
+
+ return $source;
+}
+
+function import_avatar($source, $target = '')
+{
+ if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source))
+ {
+ return;
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (!isset($convert->convertor['avatar_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__);
+ }
+
+ $target = $config['avatar_path'] . '/' . basename(empty($target) ? $source : $target);
+
+ if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0)
+ {
+ $source = $convert->convertor['avatar_path'] . $source;
+ }
+
+ if (file_exists(relative_base($source, $relative_path, __LINE__, __FILE__)))
+ {
+ if ($result = copy_file($source, $target, false, false, $relative_path))
+ {
+ return basename($target);
+ }
+ }
+
+ return $source;
+}
+
+/**
+* @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really).
+*/
+
+/**
+* Calculate the size of the specified image
+* Called from the following functions for calculating the size of specific image types
+*/
+function get_image_dim($source)
+{
+ if (empty($source))
+ {
+ return array(0, 0);
+ }
+
+ global $convert;
+
+ $relative_path = empty($convert->convertor['source_path_absolute']);
+
+ if (file_exists(relative_base($source, $relative_path)))
+ {
+ $image = relative_base($source, $relative_path);
+ return getimagesize($image);
+ }
+
+ return false;
+}
+
+/**
+* Obtain the width of the specified smilie
+*/
+function get_smiley_width($src)
+{
+ return get_smiley_dim($src, 0);
+}
+
+/**
+* Obtain the height of the specified smilie
+*/
+function get_smiley_height($src)
+{
+ return get_smiley_dim($src, 1);
+}
+
+/**
+* Obtain the size of the specified smilie (using the cache if possible) and cache the value
+*/
+function get_smiley_dim($source, $axis)
+{
+ if (empty($source))
+ {
+ return 15;
+ }
+
+ static $smiley_cache = array();
+
+ if (isset($smiley_cache[$source]))
+ {
+ return $smiley_cache[$source][$axis];
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $orig_source = $source;
+
+ if (!isset($convert->convertor['smilies_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__);
+ }
+
+ if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0)
+ {
+ $source = $convert->convertor['smilies_path'] . $source;
+ }
+
+ $smiley_cache[$orig_source] = get_image_dim($source);
+
+ if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1]))
+ {
+ $smiley_cache[$orig_source] = array(15, 15);
+ return 15;
+ }
+
+ return $smiley_cache[$orig_source][$axis];
+}
+
+/**
+* Obtain the width of the specified avatar
+*/
+function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false)
+{
+ return get_avatar_dim($src, 0, $func, $arg1, $arg2);
+}
+
+/**
+* Obtain the height of the specified avatar
+*/
+function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false)
+{
+ return get_avatar_dim($src, 1, $func, $arg1, $arg2);
+}
+
+/**
+*/
+function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false)
+{
+ $avatar_type = AVATAR_UPLOAD;
+
+ if ($func)
+ {
+ if ($arg1 || $arg2)
+ {
+ $ary = array($arg1);
+
+ if ($arg2)
+ {
+ $ary[] = $arg2;
+ }
+
+ $avatar_type = call_user_func_array($func, $ary);
+ }
+ else
+ {
+ $avatar_type = call_user_func($func);
+ }
+ }
+
+ switch ($avatar_type)
+ {
+ case AVATAR_UPLOAD:
+ return get_upload_avatar_dim($src, $axis);
+ break;
+
+ case AVATAR_GALLERY:
+ return get_gallery_avatar_dim($src, $axis);
+ break;
+
+ case AVATAR_REMOTE:
+ // see notes on this functions usage and (hopefully) model $func to avoid this accordingly
+ return get_remote_avatar_dim($src, $axis);
+ break;
+
+ default:
+ return $axis ? DEFAULT_AVATAR_Y : DEFAULT_AVATAR_X;
+ break;
+ }
+}
+
+/**
+* Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value
+*/
+function get_upload_avatar_dim($source, $axis)
+{
+ static $cachedims = false;
+ static $cachekey = false;
+
+ if (empty($source))
+ {
+ return 0;
+ }
+
+ if ($cachekey == $source)
+ {
+ return $cachedims[$axis];
+ }
+
+ $orig_source = $source;
+
+ if (substr($source, 0, 7) == 'upload:')
+ {
+ $source = substr($source, 7);
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ if (!isset($convert->convertor['avatar_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__);
+ }
+
+ if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0)
+ {
+ $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source;
+ }
+
+ $cachedims = get_image_dim($source);
+
+ if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1]))
+ {
+ $cachedims = array(DEFAULT_AVATAR_X, DEFAULT_AVATAR_Y);
+ }
+
+ return $cachedims[$axis];
+}
+
+/**
+* Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value
+*/
+function get_gallery_avatar_dim($source, $axis)
+{
+ if (empty($source))
+ {
+ return 0;
+ }
+
+ static $avatar_cache = array();
+
+ if (isset($avatar_cache[$source]))
+ {
+ return $avatar_cache[$source][$axis];
+ }
+
+ global $convert, $phpbb_root_path, $config, $user;
+
+ $orig_source = $source;
+
+ if (!isset($convert->convertor['avatar_gallery_path']))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__);
+ }
+
+ if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0)
+ {
+ $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source;
+ }
+
+ $avatar_cache[$orig_source] = get_image_dim($source);
+
+ if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1]))
+ {
+ $avatar_cache[$orig_source] = array(DEFAULT_AVATAR_X, DEFAULT_AVATAR_Y);
+ }
+
+ return $avatar_cache[$orig_source][$axis];
+}
+
+/**
+* Obtain the size of the specified remote avatar (using the cache if possible) and cache the value
+* Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option
+* This should only be called from a post processing step due to the possibility of network timeouts
+*/
+function get_remote_avatar_dim($src,$axis)
+{
+ if (empty($src))
+ {
+ return 0;
+ }
+
+ static $avatar_cache = array();
+
+ if (isset($avatar_cache[$src]))
+ {
+ return $avatar_cache[$src][$axis];
+ }
+
+ $avatar_cache[$src] = getimagesize($src);
+
+ if (empty($avatar_cache[$src]) || empty($avatar_cache[$src][0]) || empty($avatar_cache[$src][1]))
+ {
+ $avatar_cache[$src] = array(DEFAULT_AVATAR_X, DEFAULT_AVATAR_Y);
+ }
+
+ return $avatar_cache[$src][$axis];
+}
+
+function set_user_options()
+{
+ global $convert_row;
+
+ // Key need to be set in row, else default value is chosen
+ $keyoptions = array(
+ 'viewimg' => array('bit' => 0, 'default' => 1),
+ 'viewflash' => array('bit' => 1, 'default' => 1),
+ 'viewsmilies' => array('bit' => 2, 'default' => 1),
+ 'viewsigs' => array('bit' => 3, 'default' => 1),
+ 'viewavatars' => array('bit' => 4, 'default' => 1),
+ 'viewcensors' => array('bit' => 5, 'default' => 1),
+ 'attachsig' => array('bit' => 6, 'default' => 0),
+ 'bbcode' => array('bit' => 8, 'default' => 1),
+ 'smilies' => array('bit' => 9, 'default' => 1),
+ 'popuppm' => array('bit' => 10, 'default' => 0),
+ );
+
+ $option_field = 0;
+
+ foreach ($keyoptions as $key => $key_ary)
+ {
+ $value = (isset($row[$key])) ? (int) $row[$key] : $key_ary['default'];
+
+ if ($value && !($option_field & 1 << $key_ary['bit']))
+ {
+ $option_field += 1 << $key_ary['bit'];
+ }
+ }
+
+ return $option_field;
+}
+
+/**
+* Index messages on the fly as we convert them
+* @todo naderman, can you check that this works with the new search plugins as it's use is currently disabled (and thus untested)
+function search_indexing($message = '')
+{
+ global $fulltext_search, $convert_row;
+
+ if (!isset($convert_row['post_id']))
+ {
+ return;
+ }
+
+ if (!$message)
+ {
+ if (!isset($convert_row['message']))
+ {
+ return;
+ }
+
+ $message = $convert_row['message'];
+ }
+
+ $title = (isset($convert_row['title'])) ? $convert_row['title'] : '';
+
+ $fulltext_search->index('post', $convert_row['post_id'], $message, $title, $convert_row['poster_id'], $convert_row['forum_id']);
+}
+*/
+
+function make_unique_filename($filename)
+{
+ if (!strlen($filename))
+ {
+ $filename = md5(unique_id()) . '.dat';
+ }
+ else if ($filename[0] == '.')
+ {
+ $filename = md5(unique_id()) . $filename;
+ }
+ else if (preg_match('/\.([a-z]+)$/i', $filename, $m))
+ {
+ $filename = preg_replace('/\.([a-z]+)$/i', '_' . md5(unique_id()) . '.\1', $filename);
+ }
+ else
+ {
+ $filename .= '_' . md5(unique_id()) . '.dat';
+ }
+
+ return $filename;
+}
+
+function words_unique(&$words)
+{
+ reset($words);
+ $return_array = array();
+
+ $word = current($words);
+ do
+ {
+ $return_array[$word] = $word;
+ }
+ while ($word = next($words));
+
+ return $return_array;
+}
+
+/**
+* Adds a user to the specified group and optionally makes them a group leader
+* This function does not create the group if it does not exist and so should only be called after the groups have been created
+*/
+function add_user_group($group_id, $user_id, $group_leader=false)
+{
+ global $convert, $phpbb_root_path, $config, $user, $db;
+
+ $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array(
+ 'group_id' => $group_id,
+ 'user_id' => $user_id,
+ 'group_leader' => ($group_leader) ? 1 : 0,
+ 'user_pending' => 0));
+ $db->sql_query($sql);
+}
+
+// STANDALONE FUNCTIONS
+
+/**
+* Add users to the pre-defined "special" groups
+* @param string $group The name of the special group to add to
+* @param string $select_query An SQL query to retrieve the user(s) to add to the group
+*
+* @todo Is this perhaps misnamed? It doesn't appear to directly have anything to do with auth
+*/
+function user_group_auth($group, $select_query)
+{
+ global $convert, $phpbb_root_path, $config, $user, $db;
+
+ if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots')))
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_WRONG_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
+ return;
+ }
+
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = '" . $db->sql_escape(strtoupper($group)) . "'";
+ $result = $db->sql_query($sql);
+ $group_id = (int) $db->sql_fetchfield('group_id');
+ $db->sql_freeresult($result);
+
+ if (!$group_id)
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
+ return;
+ }
+
+ $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' (user_id, group_id, user_pending)
+ ' . str_replace('{' . strtoupper($group) . '}', $group_id . ', 0', $select_query);
+ $db->sql_query($sql);
+}
+
+/**
+* Retrieves configuration information from the source forum and caches it as an array
+* Both database and file driven configuration formats can be handled
+* (the type used is specified in $config_schema, see convert_phpbb20.php for more details)
+*/
+function get_config()
+{
+ static $convert_config;
+ global $user;
+
+ if (isset($convert_config))
+ {
+ return $convert_config;
+ }
+
+ global $db, $phpbb_root_path, $config;
+ global $convert;
+
+ if ($convert->config_schema['table_format'] != 'file')
+ {
+ $sql = 'SELECT * FROM ' . $convert->src_table_prefix . $convert->config_schema['table_name'];
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+
+ if (!$row)
+ {
+ $convert->p_master->error($user->lang['CONV_ERROR_GET_CONFIG'], __LINE__, __FILE__);
+ }
+ }
+
+ if (is_array($convert->config_schema['table_format']))
+ {
+ $convert_config = array();
+ list($key, $val) = each($convert->config_schema['table_format']);
+
+ do
+ {
+ $convert_config[$row[$key]] = $row[$val];
+ }
+ while ($row = $db->sql_fetchrow($result));
+ $db->sql_freeresult($result);
+ }
+ else if ($convert->config_schema['table_format'] == 'file')
+ {
+ $filename = $convert->convertor_status['forum_path'] . '/' . $convert->config_schema['filename'];
+ if (!file_exists($filename))
+ {
+ $convert->p_master->error($user->lang['FILE_NOT_FOUND'] . ': ' . $filename, __LINE__, __FILE__);
+ }
+
+ $convert_config = extract_variables_from_file($filename);
+ if (!empty($convert->config_schema['array_name']))
+ {
+ $convert_config = $convert_config[$convert->config_schema['array_name']];
+ }
+ }
+ else
+ {
+ $convert_config = $row;
+ }
+
+ if (!sizeof($convert_config))
+ {
+ $convert->p_master->error($lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__);
+ }
+
+ return $convert_config;
+}
+
+/**
+* Transfers the relevant configuration information from the source forum
+* The mapping of fields is specified in $config_schema, see convert_phpbb20.php for more details
+*/
+function restore_config($schema)
+{
+ global $db, $config;
+
+ $convert_config = get_config();
+ foreach ($schema['settings'] as $config_name => $src)
+ {
+ if (preg_match('/(.*)\((.*)\)/', $src, $m))
+ {
+ $var = (empty($m[2])) ? '' : "'" . addslashes($convert_config[$m[2]]) . "'";
+ $exec = '$config_value = ' . $m[1] . '(' . $var . ');';
+ eval($exec);
+ }
+ else
+ {
+ $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : '';
+ }
+
+ if ($config_value !== '')
+ {
+ set_config($config_name, $config_value);
+ }
+ }
+}
+
+/**
+* Update the count of PM's in custom folders for all users
+*/
+function update_folder_pm_count()
+{
+ global $db, $convert, $user;
+
+ $sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages
+ FROM ' . PRIVMSGS_TO_TABLE . '
+ WHERE folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ', ' . PRIVMSGS_INBOX . ', ' . PRIVMSGS_OUTBOX . ', ' . PRIVMSGS_SENTBOX . ')
+ GROUP BY folder_id';
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $db->sql_query('UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = ' . $row['num_messages'] . '
+ WHERE user_id = ' . $row['user_id'] . ' AND folder_id = ' . $row['folder_id']);
+ }
+ $db->sql_freeresult($result);
+}
+
+// Functions mainly used by the main converter script
+
+function path($path, $path_relative = true)
+{
+ if (substr($path, -1) != '/')
+ {
+ $path .= '/';
+ }
+
+ if (!$path_relative)
+ {
+ return $path;
+ }
+
+ if (substr($path, 0, 1) == '/')
+ {
+ $path = substr($path, 1);
+ }
+
+ return $path;
+}
+
+/**
+* Extract the variables defined in a configuration file
+* @todo As noted by Xore we need to look at this from a security perspective
+*/
+function extract_variables_from_file($_filename)
+{
+ include($_filename);
+
+ $vars = get_defined_vars();
+ unset($vars['_filename']);
+
+ return $vars;
+}
+
+function get_path($src_path, $src_url, $test_file)
+{
+ global $config, $phpbb_root_path, $phpEx;
+
+ $board_config = get_config();
+
+ $test_file = preg_replace('/\.php$/i', ".$phpEx", $test_file);
+ $src_path = path($src_path);
+
+ if (@file_exists($phpbb_root_path . $src_path . $test_file))
+ {
+ return $src_path;
+ }
+
+ if (!empty($src_url) && !empty($board_config['server_name']))
+ {
+ if (!preg_match('#https?://([^/]+)(.*)#i', $src_url, $m))
+ {
+ return false;
+ }
+
+ if ($m[1] != $board_config['server_name'])
+ {
+ return false;
+ }
+
+ $url_parts = explode('/', $m[2]);
+ if (substr($src_url, -1) != '/')
+ {
+ if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[count($url_parts) - 1]))
+ {
+ $url_parts[sizeof($url_parts) - 1] = '';
+ }
+ else
+ {
+ $url_parts[] = '';
+ }
+ }
+
+ $script_path = $board_config['script_path'];
+ if (substr($script_path, -1) == '/')
+ {
+ $script_path = substr($script_path, 0, -1);
+ }
+
+ $path_array = array();
+
+ $phpbb_parts = explode('/', $script_path);
+ for ($i = 0; $i < sizeof($url_parts); ++$i)
+ {
+ if ($i < sizeof($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i])
+ {
+ $path_array[] = $url_parts[$i];
+ unset($url_parts[$i]);
+ }
+ else
+ {
+ $path = '';
+ for ($j = $i; $j < sizeof($phpbb_parts); ++$j)
+ {
+ $path .= '../';
+ }
+ $path .= implode('/', $url_parts);
+ break;
+ }
+ }
+
+ if (!empty($path))
+ {
+ if (@file_exists($phpbb_root_path . $path . $test_file))
+ {
+ return $path;
+ }
+ }
+ }
+
+ return false;
+}
+
+function compare_table($tables, $tablename, &$prefixes)
+{
+ for ($i = 0; $i < sizeof($tables); ++$i)
+ {
+ if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m))
+ {
+ if (empty($m[1]))
+ {
+ $m[1] = '*';
+ }
+
+ if (isset($prefixes[$m[1]]))
+ {
+ $prefixes[$m[1]]++;
+ }
+ else
+ {
+ $prefixes[$m[1]] = 1;
+ }
+ }
+ }
+}
+
+/**
+* Grant permissions to a specified user or group
+*
+* @param string $ug_type user|group|user_role|group_role
+* @param mixed $forum_id forum ids (array|int|0) -> 0 == all forums
+* @param mixed $ug_id [int] user_id|group_id : [string] usergroup name
+* @param mixed $acl_list [string] acl entry : [array] acl entries : [string] role entry
+* @param int $setting ACL_YES|ACL_NO|ACL_NEVER
+*/
+function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO)
+{
+ global $db, $convert, $user, $config;
+ static $acl_option_ids, $group_ids;
+
+ if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id))
+ {
+ if (!isset($group_ids[$ug_id]))
+ {
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = '" . $db->sql_escape(strtoupper($ug_id)) . "'";
+ $result = $db->sql_query_limit($sql, 1);
+ $id = (int) $db->sql_fetchfield('group_id');
+ $db->sql_freeresult($result);
+
+ if (!$id)
+ {
+ return;
+ }
+
+ $group_ids[$ug_id] = $id;
+ }
+
+ $ug_id = (int) $group_ids[$ug_id];
+ }
+
+ $table = ($ug_type == 'user' || $ug_type == 'user_role') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE;
+ $id_field = ($ug_type == 'user' || $ug_type == 'user_role') ? 'user_id' : 'group_id';
+
+ // Role based permissions are the simplest to handle so check for them first
+ if ($ug_type == 'user_role' || $ug_type == 'group_role')
+ {
+ $sql = 'SELECT role_id
+ FROM ' . ACL_ROLES_TABLE . "
+ WHERE role_description = 'ROLE_DESCRIPTION_" . $db->sql_escape($acl_list) . "'";
+ $result = $db->sql_query_limit($sql, 1);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $sql = "INSERT INTO $table ($id_field, forum_id, auth_role_id) VALUES ($ug_id, $forum_id, " . $row['role_id'] . ')';
+ $db->sql_query($sql);
+
+ return;
+ }
+
+ // Build correct parameters
+ $auth = array();
+
+ if (!is_array($acl_list))
+ {
+ $auth = array($acl_list => $setting);
+ }
+ else
+ {
+ foreach ($acl_list as $auth_option)
+ {
+ $auth[$auth_option] = $setting;
+ }
+ }
+ unset($acl_list);
+
+ if (!is_array($forum_id))
+ {
+ $forum_id = array($forum_id);
+ }
+
+ // Set any flags as required
+ foreach ($auth as $auth_option => $acl_setting)
+ {
+ $flag = substr($auth_option, 0, strpos($auth_option, '_') + 1);
+ if (empty($auth[$flag]))
+ {
+ $auth[$flag] = $acl_setting;
+ }
+ }
+
+ if (!is_array($acl_option_ids) || empty($acl_option_ids))
+ {
+ $sql = 'SELECT auth_option_id, auth_option
+ FROM ' . ACL_OPTIONS_TABLE;
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $acl_option_ids[$row['auth_option']] = $row['auth_option_id'];
+ }
+ $db->sql_freeresult($result);
+ }
+
+ $sql_forum = 'AND a.forum_id IN (' . implode(', ', array_map('intval', $forum_id)) . ')';
+
+ $sql = ($ug_type == 'user') ? 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.user_id = $ug_id" : 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.group_id = $ug_id";
+ $result = $db->sql_query($sql);
+
+ $cur_auth = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $cur_auth[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
+ }
+ $db->sql_freeresult($result);
+
+ $sql_ary = array();
+ foreach ($forum_id as $forum)
+ {
+ foreach ($auth as $auth_option => $setting)
+ {
+ $auth_option_id = $acl_option_ids[$auth_option];
+
+ if (!$auth_option_id)
+ {
+ continue;
+ }
+
+ switch ($setting)
+ {
+ case ACL_NO:
+ if (isset($cur_auth[$forum][$auth_option_id]))
+ {
+ $sql_ary['delete'][] = "DELETE FROM $table
+ WHERE forum_id = $forum
+ AND auth_option_id = $auth_option_id
+ AND $id_field = $ug_id";
+ }
+ break;
+
+ default:
+ if (!isset($cur_auth[$forum][$auth_option_id]))
+ {
+ $sql_ary['insert'][] = "$ug_id, $forum, $auth_option_id, $setting";
+ }
+ else if ($cur_auth[$forum][$auth_option_id] != $setting)
+ {
+ $sql_ary['update'][] = "UPDATE " . $table . "
+ SET auth_setting = $setting
+ WHERE $id_field = $ug_id
+ AND forum_id = $forum
+ AND auth_option_id = $auth_option_id";
+ }
+ }
+ }
+ }
+ unset($cur_auth);
+
+ $sql = '';
+ foreach ($sql_ary as $sql_type => $sql_subary)
+ {
+ switch ($sql_type)
+ {
+ case 'insert':
+ switch ($db->sql_layer)
+ {
+ case 'mysql':
+ case 'mysql4':
+ $sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary));
+ break;
+
+ case 'mssql':
+ case 'sqlite':
+ $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary));
+ break;
+
+ default:
+ foreach ($sql_subary as $sql)
+ {
+ $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)";
+ $db->sql_query($sql);
+ $sql = '';
+ }
+ }
+
+ if ($sql != '')
+ {
+ $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql";
+ $db->sql_query($sql);
+ }
+ break;
+
+ case 'update':
+ case 'delete':
+ foreach ($sql_subary as $sql)
+ {
+ $db->sql_query($sql);
+ $sql = '';
+ }
+ break;
+ }
+ unset($sql_ary[$sql_type]);
+ }
+ unset($sql_ary);
+
+}
+
+/**
+* Update the count of unread private messages for all users
+*/
+function update_unread_count()
+{
+ global $db;
+
+ $sql = 'SELECT user_id, COUNT(msg_id) as num_messages
+ FROM ' . PRIVMSGS_TO_TABLE . '
+ WHERE pm_unread = 1
+ AND folder_id <> ' . PRIVMSGS_OUTBOX . '
+ GROUP BY user_id';
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_unread_privmsg = ' . $row['num_messages'] . '
+ WHERE user_id = ' . $row['user_id']);
+ }
+ $db->sql_freeresult($result);
+}
+
+/**
+* Add any of the pre-defined "special" groups which are missing from the database
+*/
+function add_default_groups()
+{
+ global $db;
+
+ $default_groups = array(
+ 'GUESTS' => array('', 0),
+ 'REGISTERED' => array('', 0),
+ 'REGISTERED_COPPA' => array('', 0),
+ 'GLOBAL_MODERATORS' => array('00AA00', 1),
+ 'ADMINISTRATORS' => array('AA0000', 1),
+ 'BOTS' => array('9E8DA7', 0)
+ );
+
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name IN ('" . implode("', '", array_keys($default_groups)) . "')";
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ unset($default_groups[strtoupper($row['group_name'])]);
+ }
+ $db->sql_freeresult($result);
+
+ $sql_ary = array();
+
+ foreach ($default_groups as $name => $data)
+ {
+ $sql_ary[] = array(
+ 'group_name' => (string) $name,
+ 'group_desc' => '',
+ 'group_desc_uid' => '',
+ 'group_desc_bitfield' => '',
+ 'group_type' => GROUP_SPECIAL,
+ 'group_colour' => $data[0],
+ 'group_legend' => $data[1],
+ );
+ }
+
+ if (sizeof($sql_ary))
+ {
+ $db->sql_multi_insert(GROUPS_TABLE, $sql_ary);
+ }
+}
+
+/**
+* Add the search bots into the database
+* This code should be used in execute_last if the source database did not have bots
+* If you are converting bots this function should not be called
+* @todo We might want to look at sharing the bot list between the install code and this code for consistancy
+*/
+function add_bots()
+{
+ global $db, $convert, $user;
+
+ $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'";
+ $result = $db->sql_query($sql);
+ $group_id = (int) $db->sql_fetchfield('group_id', 0, $result);
+ $db->sql_freeresult($result);
+
+ if (!$group_id)
+ {
+ add_default_groups();
+
+ $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'";
+ $result = $db->sql_query($sql);
+ $group_id = (int) $db->sql_fetchfield('group_id', 0, $result);
+ $db->sql_freeresult($result);
+
+ if (!$group_id)
+ {
+ $install->error($user->lang['CONV_ERROR_INCONSISTENT_GROUPS'], __LINE__, __FILE__);
+ }
+ }
+
+ $bots = array(
+ 'AdsBot [Google]' => array('AdsBot-Google', ''),
+ 'Alexa [Bot]' => array('ia_archiver', ''),
+ 'Alta Vista [Bot]' => array('Scooter/', ''),
+ 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''),
+ 'Baidu [Spider]' => array('Baiduspider+(', ''),
+ 'Exabot [Bot]' => array('Exabot/', ''),
+ 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''),
+ 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''),
+ 'Francis [Bot]' => array('http://www.neomo.de/', ''),
+ 'Gigabot [Bot]' => array('Gigabot/', ''),
+ 'Google Adsense [Bot]' => array('Mediapartners-Google/', ''),
+ 'Google Desktop' => array('Google Desktop', ''),
+ 'Google Feedfetcher' => array('Feedfetcher-Google', ''),
+ 'Google [Bot]' => array('Googlebot', ''),
+ 'Heise IT-Markt [Crawler]' => array('heise-IT-Markt-Crawler', ''),
+ 'Heritrix [Crawler]' => array('heritrix/1.', ''),
+ 'IBM Research [Bot]' => array('ibm.com/cs/crawler', ''),
+ 'ICCrawler - ICjobs' => array('ICCrawler - ICjobs', ''),
+ 'ichiro [Crawler]' => array('ichiro/2', ''),
+ 'Majestic-12 [Bot]' => array('MJ12bot/', ''),
+ 'Metager [Bot]' => array('MetagerBot/', ''),
+ 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''),
+ 'MSN [Bot]' => array('msnbot/', ''),
+ 'MSNbot Media' => array('msnbot-media/', ''),
+ 'NG-Search [Bot]' => array('NG-Search/', ''),
+ 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''),
+ 'Nutch/CVS [Bot]' => array('NutchCVS/', ''),
+ 'OmniExplorer [Bot]' => array('OmniExplorer_Bot/', ''),
+ 'Online link [Validator]' => array('online link validator', ''),
+ 'psbot [Picsearch]' => array('psbot/0', ''),
+ 'Seekport [Bot]' => array('Seekbot/', ''),
+ 'Sensis [Crawler]' => array('Sensis Web Crawler', ''),
+ 'SEO Crawler' => array('SEO search Crawler/', ''),
+ 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''),
+ 'SEOSearch [Crawler]' => array('SEOsearch/', ''),
+ 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''),
+ 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''),
+ 'Synoo [Bot]' => array('SynooBot/', ''),
+ 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''),
+ 'TurnitinBot [Bot]' => array('TurnitinBot/', ''),
+ 'Voyager [Bot]' => array('voyager/1.0', ''),
+ 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''),
+ 'W3C [Linkcheck]' => array('W3C-checklink/', ''),
+ 'W3C [Validator]' => array('W3C_*Validator', ''),
+ 'WiseNut [Bot]' => array('http://www.WISEnutbot.com', ''),
+ 'Yacy [Bot]' => array('yacybot', ''),
+ 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''),
+ 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''),
+ 'Yahoo [Bot]' => array('Yahoo! Slurp', ''),
+ 'YahooSeeker [Bot]' => array('YahooSeeker/', ''),
+ );
+
+ foreach ($bots as $bot_name => $bot_ary)
+ {
+ $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
+ 'user_type' => GROUP_HIDDEN,
+ 'group_id' => $group_id,
+ 'username' => $bot_name,
+ 'username_clean' => utf8_clean_string($bot_name),
+ 'user_regdate' => time(),
+ 'user_permissions' => '',
+ 'user_sig' => '',
+ 'user_interests' => '',
+ 'user_password' => '',
+ 'user_lang' => 'en',
+ 'user_style' => 1,
+ 'user_rank' => 1,
+ 'user_colour' => '9E8DA7')
+ );
+ $db->sql_query($sql);
+
+ $user_id = $db->sql_nextid();
+
+ add_user_group($group_id, $user_id, false);
+
+ $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
+ 'bot_active' => 1,
+ 'bot_name' => $bot_name,
+ 'user_id' => $user_id,
+ 'bot_agent' => $bot_ary[0],
+ 'bot_ip' => $bot_ary[1])
+ );
+ $db->sql_query($sql);
+ }
+}
+
+/**
+* Update any dynamic configuration variables after the conversion is finished
+* @todo Confirm that this updates all relevant values since it has not necessarily been kept in sync with all changes
+*/
+function update_dynamic_config()
+{
+ global $db, $config;
+
+ // Get latest username
+ $sql = 'SELECT user_id, username, user_colour
+ FROM ' . USERS_TABLE . '
+ WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
+ ORDER BY user_id DESC';
+ $result = $db->sql_query_limit($sql, 1);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if ($row)
+ {
+ set_config('newest_user_id', $row['user_id'], true);
+ set_config('newest_username', $row['username'], true);
+ set_config('newest_user_colour', $row['user_colour'], true);
+ }
+
+ set_config('record_online_users', 1, true);
+ set_config('record_online_date', time(), true);
+
+ $sql = 'SELECT COUNT(post_id) AS stat
+ FROM ' . POSTS_TABLE . '
+ WHERE post_approved = 1';
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ set_config('num_posts', (int) $row['stat'], true);
+
+ $sql = 'SELECT COUNT(topic_id) AS stat
+ FROM ' . TOPICS_TABLE . '
+ WHERE topic_approved = 1';
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ set_config('num_topics', (int) $row['stat'], true);
+
+ $sql = 'SELECT COUNT(user_id) AS stat
+ FROM ' . USERS_TABLE . '
+ WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')';
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ set_config('num_users', (int) $row['stat'], true);
+
+ $sql = 'SELECT COUNT(attach_id) as stat
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE is_orphan = 0';
+ $result = $db->sql_query($sql);
+ set_config('num_files', (int) $db->sql_fetchfield('stat'), true);
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT SUM(filesize) as stat
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE is_orphan = 0';
+ $result = $db->sql_query($sql);
+ set_config('upload_dir_size', (int) $db->sql_fetchfield('stat'), true);
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
+ FROM ' . POSTS_TABLE . '
+ WHERE post_postcount = 1
+ GROUP BY poster_id';
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}");
+ }
+ $db->sql_freeresult($result);
+}
+
+/**
+* Updates topics_posted entries
+*/
+function update_topics_posted()
+{
+ global $db, $config;
+
+ $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . TOPICS_POSTED_TABLE);
+
+ // This can get really nasty... therefore we only do the last six months
+ $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60);
+
+ // Select forum ids, do not include categories
+ $sql = 'SELECT forum_id
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_type <> ' . FORUM_CAT;
+ $result = $db->sql_query($sql);
+
+ $forum_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $forum_ids[] = $row['forum_id'];
+ }
+ $db->sql_freeresult($result);
+
+ // Any global announcements? ;)
+ $forum_ids[] = 0;
+
+ // Now go through the forums and get us some topics...
+ foreach ($forum_ids as $forum_id)
+ {
+ $sql = 'SELECT p.poster_id, p.topic_id
+ FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
+ WHERE t.forum_id = ' . $forum_id . '
+ AND t.topic_moved_id = 0
+ AND t.topic_last_post_time > ' . $get_from_time . '
+ AND t.topic_id = p.topic_id
+ AND p.poster_id <> ' . ANONYMOUS . '
+ GROUP BY p.poster_id, p.topic_id';
+ $result = $db->sql_query($sql);
+
+ $posted = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $posted[$row['poster_id']][] = $row['topic_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $sql_ary = array();
+ foreach ($posted as $user_id => $topic_row)
+ {
+ foreach ($topic_row as $topic_id)
+ {
+ $sql_ary[] = array(
+ 'user_id' => $user_id,
+ 'topic_id' => $topic_id,
+ 'topic_posted' => 1,
+ );
+ }
+ }
+ unset($posted);
+
+ $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
+ }
+}
+
+/**
+* Ensure that all users have a default group specified and update related information such as their colour
+*/
+function fix_empty_primary_groups()
+{
+ global $db;
+
+ // Set group ids for users not already having it
+ $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
+ WHERE group_id = 0 AND user_type = ' . USER_INACTIVE;
+ $db->sql_query($sql);
+
+ $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
+ WHERE group_id = 0 AND user_type = ' . USER_NORMAL;
+ $db->sql_query($sql);
+
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('guests') . ' WHERE user_id = ' . ANONYMOUS);
+
+ $sql = 'SELECT ban_userid as user_id FROM ' . BANLIST_TABLE . ' WHERE ban_userid > 0';
+ $result = $db->sql_query($sql);
+
+ $user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $user_ids[] = $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($user_ids))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_type = ' . USER_IGNORE . '
+ WHERE user_id IN (' . implode(',', $user_ids) . ')');
+ }
+
+ $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('administrators');
+ $result = $db->sql_query($sql);
+
+ $user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $user_ids[] = $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($user_ids))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('administrators') . '
+ WHERE group_id = 0 AND user_id IN (' . implode(', ', $user_ids) . ')');
+ }
+
+ $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators');
+
+ $user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $user_ids[] = $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($user_ids))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('global_moderators') . '
+ WHERE group_id = 0 AND user_id IN (' . implode(', ', $user_ids) . ')');
+ }
+
+ // Set user colour
+ $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . "
+ WHERE group_colour <> ''";
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_colour = '{$row['group_colour']}' WHERE group_id = {$row['group_id']}");
+ }
+ $db->sql_freeresult($result);
+}
+
+function convert_bbcode($message, $convert_size = true, $extended_bbcodes = false)
+{
+ static $orig, $repl, $origx, $replx, $str_from, $str_to;
+
+ if (empty($orig))
+ {
+ $orig = $repl = array();
+
+ $orig[] = '#\[(php|sql)\](.*?)\[/(php|sql)\]#is';
+ $repl[] = '[code]\2[/code]';
+
+ $orig[] = '#\[font=[^\]]+\](.*?)\[/font\]#is';
+ $repl[] = '\1';
+
+ $orig[] = '#\[align=[a-z]+\](.*?)\[/align\]#is';
+ $repl[] = '\1';
+
+ $orig[] = '#\[/list=.*?\]#is';
+ $repl[] = '[/list]';
+
+ $origx = array(
+ '#\[glow[^\]]+\](.*?)\[/glow\]#is',
+ '#\[shadow[^\]]+\](.*?)\[/shadow\]#is',
+ '#\[flash[^\]]+\](.*?)\[/flash\]#is'
+ );
+
+ $replx = array(
+ '\1',
+ '\1',
+ '[url=\1]Flash[/url]'
+ );
+
+ $str_from = array(
+ '[ftp]', '[/ftp]',
+ '[ftp=', '[/ftp]',
+ '[pre]', '[/pre]',
+ '[table]', '[/table]',
+ '[td]', '[/td]',
+ '[tr]', '[/tr]',
+ '[s]', '[/s]',
+ '[left]', '[/left]',
+ '[right]', '[/right]',
+ '[center]', '[/center]',
+ '[sub]', '[/sub]',
+ '[sup]', '[/sup]',
+ '[tt]', '[/tt]',
+ '[move]', '[/move]',
+ '[hr]'
+ );
+
+ $str_to = array(
+ '[url]', '[/url]',
+ '[url=', '[/url]',
+ '[code]', '[/code]',
+ "\n", '',
+ '', '',
+ "\n", '',
+ '', '',
+ '', '',
+ '', '',
+ '', '',
+ '', '',
+ '', '',
+ '', '',
+ '', '',
+ "\n\n"
+ );
+
+ for ($i = 0; $i < sizeof($str_from); ++$i)
+ {
+ $origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is';
+ $replx[] = $str_to[$i];
+ }
+ }
+
+ if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m))
+ {
+ for ($i = 0; $i < sizeof($m[1]); ++$i)
+ {
+ if ($m[1][$i] == $m[2][$i])
+ {
+ $message = str_replace($m[0][$i], '[email]' . $m[1][$i] . '[/email]', $message);
+ }
+ else
+ {
+ $message = str_replace($m[0][$i], $m[2][$i] . ' ([email]' . $m[1][$i] . '[/email])', $message);
+ }
+ }
+ }
+
+ if ($convert_size && preg_match('#\[size=[0-9]+\].*?\[/size\]#i', $message))
+ {
+ $size = array(9, 9, 12, 15, 18, 24, 29, 29, 29, 29);
+ $message = preg_replace('#\[size=([0-9]+)\](.*?)\[/size\]#i', '[size=\1]\2[/size]', $message);
+ $message = preg_replace('#\[size=[0-9]{2,}\](.*?)\[/size\]#i', '[size=29]\1[/size]', $message);
+
+ for ($i = sizeof($size); $i; )
+ {
+ $i--;
+ $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message);
+ }
+ }
+
+ if ($extended_bbcodes)
+ {
+ $message = preg_replace($origx, $replx, $message);
+ }
+
+ $message = preg_replace($orig, $repl, $message);
+ return $message;
+}
+
+
+function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
+{
+ global $convert, $phpbb_root_path, $config, $user, $db;
+
+ if (substr($trg, -1) == '/')
+ {
+ $trg .= basename($src);
+ }
+ $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
+ $trg_path = $trg;
+
+ if (!$overwrite && @file_exists($trg_path))
+ {
+ return true;
+ }
+
+ if (!@file_exists($src_path))
+ {
+ return;
+ }
+
+ $path = $phpbb_root_path;
+ $parts = explode('/', $trg);
+ unset($parts[sizeof($parts) - 1]);
+
+ for ($i = 0; $i < sizeof($parts); ++$i)
+ {
+ $path .= $parts[$i] . '/';
+
+ if (!is_dir($path))
+ {
+ @mkdir($path, 0777);
+ }
+ }
+
+ if (!is_writable($path))
+ {
+ @chmod($path, 0777);
+ }
+
+ if (!@copy($src_path, $phpbb_root_path . $trg_path))
+ {
+ $convert->p_master->error(sprintf($user->lang['COULD_NOT_COPY'], $src_path, $phpbb_root_path . $trg), __LINE__, __FILE__, !$die_on_failure);
+ return;
+ }
+
+ if ($perm = @fileperms($src_path))
+ {
+ @chmod($phpbb_root_path . $trg_path, $perm);
+ }
+
+ return true;
+}
+
+function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
+{
+ global $convert, $phpbb_root_path, $config, $user, $db;
+
+ $dirlist = $filelist = $bad_dirs = array();
+ $src = path($src, $source_relative_path);
+ $trg = path($trg);
+ $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
+ $trg_path = $phpbb_root_path . $trg;
+
+ if (!is_dir($trg_path))
+ {
+ @mkdir($trg_path, 0777);
+ @chmod($trg_path, 0777);
+ }
+
+ if (!is_writeable($trg_path))
+ {
+ $bad_dirs[] = path($config['script_path']) . $trg;
+ }
+
+ if ($handle = @opendir($src_path))
+ {
+ while ($entry = readdir($handle))
+ {
+ if ($entry[0] == '.')
+ {
+ continue;
+ }
+
+ if (is_dir($src_path . $entry))
+ {
+ $dirlist[] = $entry;
+ }
+ else
+ {
+ $filelist[] = $entry;
+ }
+ }
+ closedir($handle);
+ }
+ else if ($dir = @dir($src_path))
+ {
+ while ($entry = $dir->read())
+ {
+ if (substr($entry, 0, 1) == '.')
+ {
+ continue;
+ }
+
+ if (is_dir($src_path . $entry))
+ {
+ $dirlist[] = $entry;
+ }
+ else
+ {
+ $filelist[] = $entry;
+ }
+ }
+ $dir->close();
+ }
+ else
+ {
+ $convert->p_master->error(sprintf($user->lang['CONV_ERROR_COULD_NOT_READ'], relative_base($src, $source_relative_path)), __LINE__, __FILE__);
+ }
+
+ if ($copy_subdirs)
+ {
+ for ($i = 0; $i < sizeof($dirlist); ++$i)
+ {
+ $dir = $dirlist[$i];
+
+ if ($dir == 'CVS')
+ {
+ continue;
+ }
+
+ if (!is_dir($trg_path . $dir))
+ {
+ @mkdir($trg_path . $dir, 0777);
+ @chmod($trg_path . $dir, 0777);
+ }
+
+ if (!is_writeable($trg_path . $dir))
+ {
+ $bad_dirs[] = $trg . $dir;
+ $bad_dirs[] = $trg_path . $dir;
+ }
+
+ if (!sizeof($bad_dirs))
+ {
+ copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path);
+ }
+ }
+ }
+
+ if (sizeof($bad_dirs))
+ {
+ $str = (sizeof($bad_dirs) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
+ sort($bad_dirs);
+ $convert->p_master->error(sprintf($str, implode('<br />', $bad_dirs)), __LINE__, __FILE__);
+ }
+
+ for ($i = 0; $i < sizeof($filelist); ++$i)
+ {
+ copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path);
+ }
+}
+
+function relative_base($path, $is_relative = true, $line = false, $file = false)
+{
+ global $convert, $phpbb_root_path, $config, $user, $db;
+
+ if (!$is_relative)
+ {
+ return $path;
+ }
+
+ if (empty($convert->convertor_status['forum_path']) && $is_relative)
+ {
+ $line = $line ? $line : __LINE__;
+ $file = $file ? $file : __FILE__;
+
+ $convert->p_master->error($user->lang['CONV_ERROR_NO_FORUM_PATH'], $line, $file);
+ }
+
+ return $convert->convertor_status['forum_path'] . '/' . $path;
+}
+
+?> \ No newline at end of file
diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php
new file mode 100644
index 0000000000..80143f18f8
--- /dev/null
+++ b/phpBB/install/convertors/convert_phpbb20.php
@@ -0,0 +1,847 @@
+<?php
+/**
+*
+* @package install
+* @version $Id$
+* @copyright (c) 2006 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* 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;
+}
+
+/**
+* $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' => '0.9',
+ 'phpbb_version' => '3.0.0',
+ 'author' => '<a href="http://www.phpbb.com/">phpBB Group</a>',
+ 'table_prefix' => 'phpbb_',
+ 'forum_path' => '../forums',
+ 'author_notes' => 'Avatars may be on a different width/height than with the old forum. This is due to dimensions being stored within phpBB3 but not within phpBB2. The default dimension was set to 80x80 for avatars where dimension settings could not be determined. You might wish to instruct your users to check their profiles after the conversion to ensure that the size is correct.',
+);
+
+/**
+* $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
+* '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' => 'sitename',
+ 'site_desc' => 'site_desc',
+ 'session_length' => 'session_length',
+ 'board_email_sig' => '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' => 'default_dateformat',
+ 'board_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
+ // @todo Check the relevant MODs - I believe there are 2 that add this, but am not sure if their data is compatible or not
+ if (get_config_value('birthday_required') !== false)
+ {
+ define('MOD_BIRTHDAY', true);
+ }
+
+ // Test to see if the attachment MOD is installed on the source forum
+ // If it is, we will convert this data as well
+ $db->sql_return_on_error(true);
+
+ $sql = "SELECT config_value
+ FROM {$convert->src_table_prefix}attachments_config
+ WHERE config_name = 'upload_dir'";
+ $result = $db->sql_query($sql);
+
+ if ($result && $row = $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'
+ );
+
+ $db->sql_freeresult($result);
+ }
+
+ /**
+ * Tests for further MODs can be included here.
+ * Please use constants for this, prefixing them with MOD_
+ */
+
+ $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 = $db->sql_query($sql);
+ $user_id = (int) $db->sql_fetchfield('user_id');
+ $db->sql_freeresult($result);
+
+ // If there is a user id 1, we need to increment user ids. :/
+ if ($user_id === 1)
+ {
+ set_config('increment_user_id', 1, true);
+ }
+ else
+ {
+ set_config('increment_user_id', 0, true);
+ }
+
+/**
+* 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' => 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(
+ $convert->truncate_statement . SEARCH_RESULTS_TABLE,
+ $convert->truncate_statement . SEARCH_WORDLIST_TABLE,
+ $convert->truncate_statement . SEARCH_WORDMATCH_TABLE,
+ $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(); }
+
+ 'execute_first' => '
+ 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();
+ ', '
+ phpbb_convert_authentication(\'start\');
+ ', '
+ phpbb_convert_authentication(\'first\');
+ ', '
+ phpbb_convert_authentication(\'second\');
+ ', '
+ phpbb_convert_authentication(\'third\');
+ '),
+
+ 'schema' => array(
+
+ array(
+ 'target' => (defined('MOD_ATTACHMENT')) ? ATTACHMENTS_TABLE : '',
+ 'primary' => 'attachments.attach_id',
+ 'query_first' => (defined('MOD_ATTACHMENT')) ? $convert->truncate_statement . ATTACHMENTS_TABLE : '',
+
+ 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', 'phpbb_user_id'),
+ array('physical_filename', 'attachments_desc.physical_filename', 'import_attachment'),
+ array('real_filename', 'attachments_desc.real_filename', ''),
+ array('download_count', 'attachments_desc.download_count', ''),
+ array('attach_comment', 'attachments_desc.comment', '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',
+
+ 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', 'phpbb_user_id'),
+ array('physical_filename', 'attachments_desc.physical_filename', 'import_attachment'),
+ array('real_filename', 'attachments_desc.real_filename', ''),
+ array('download_count', 'attachments_desc.download_count', ''),
+ array('attach_comment', 'attachments_desc.comment', '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')) ? $convert->truncate_statement . EXTENSIONS_TABLE : '',
+
+ 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')) ? $convert->truncate_statement . EXTENSION_GROUPS_TABLE : '',
+
+ array('group_id', 'extension_groups.group_id', ''),
+ array('group_name', 'extension_groups.group_name', '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,
+ 'query_first' => $convert->truncate_statement . BANLIST_TABLE,
+
+ array('ban_ip', 'banlist.ban_ip', 'decode_ban_ip'),
+ array('ban_userid', 'banlist.ban_userid', 'phpbb_user_id'),
+
+ 'where' => "banlist.ban_ip NOT LIKE '%.%'",
+ ),
+
+ array(
+ 'target' => BANLIST_TABLE,
+
+ array('ban_email', 'banlist.ban_email', ''),
+ array('ban_userid', 'banlist.ban_userid', 'phpbb_user_id'),
+
+ 'where' => "banlist.ban_ip = ''",
+ ),
+
+ array(
+ 'target' => DISALLOW_TABLE,
+ 'query_first' => $convert->truncate_statement . DISALLOW_TABLE,
+
+ array('disallow_username', 'disallow.disallow_username', ''),
+ ),
+
+ array(
+ 'target' => RANKS_TABLE,
+ 'query_first' => $convert->truncate_statement . RANKS_TABLE,
+
+ array('rank_id', 'ranks.rank_id', ''),
+ array('rank_title', 'ranks.rank_title', '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' => $convert->truncate_statement . TOPICS_TABLE,
+ 'primary' => 'topics.topic_id',
+
+ array('topic_id', 'topics.topic_id', ''),
+ array('forum_id', 'topics.forum_id', ''),
+ array('icon_id', 0, ''),
+ array('topic_poster', 'topics.topic_poster', 'phpbb_user_id'),
+ array('topic_attachment', ((defined('MOD_ATTACHMENT')) ? 'topics.topic_attachment' : 0), ''),
+ array('topic_title', 'topics.topic_title', ''),
+ array('topic_time', 'topics.topic_time', ''),
+ array('topic_views', 'topics.topic_views', ''),
+ array('topic_replies', 'topics.topic_replies', ''),
+ array('topic_replies_real', 'topics.topic_replies', ''),
+ 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('poll_title', 'vote_desc.vote_text', array('function1' => 'null_to_str', 'function2' => '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_TABLE,
+ 'primary' => 'topics.topic_id',
+
+ array('topic_id', 'topics.topic_id', ''),
+ array('forum_id', 'topics.forum_id', ''),
+ array('icon_id', 0, ''),
+ array('topic_poster', 'topics.topic_poster', 'phpbb_user_id'),
+ array('topic_attachment', ((defined('MOD_ATTACHMENT')) ? 'topics.topic_attachment' : 0), ''),
+ array('topic_title', 'topics.topic_title', ''),
+ array('topic_time', 'topics.topic_time', ''),
+ array('topic_views', 'topics.topic_views', ''),
+ array('topic_replies', 'topics.topic_replies', ''),
+ array('topic_replies_real', 'topics.topic_replies', ''),
+ 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('poll_title', 'vote_desc.vote_text', array('function1' => 'null_to_str', 'function2' => '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' => $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' => $convert->truncate_statement . SMILIES_TABLE,
+
+ array('smiley_id', 'smilies.smilies_id', ''),
+ array('code', 'smilies.code', ''),
+ array('emotion', 'smilies.emoticon', ''),
+ 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', array(
+ 'execute' => '{RESULT} = ({VALUE}[0] <= 20) ? 1 : 0;',
+ )),
+
+ 'order_by' => 'smilies.smilies_id ASC',
+ ),
+
+ array(
+ 'target' => POLL_OPTIONS_TABLE,
+ 'primary' => 'vote_results.vote_option_id',
+ 'query_first' => $convert->truncate_statement . POLL_OPTIONS_TABLE,
+
+ array('poll_option_id', 'vote_results.vote_option_id', ''),
+ array('topic_id', 'vote_desc.topic_id', ''),
+ array('poll_option_text', 'vote_results.vote_option_text', 'utf8_htmlspecialchars'),
+ array('poll_option_total', 'vote_results.vote_result', ''),
+
+ 'where' => 'vote_results.vote_id = vote_desc.vote_id',
+ ),
+
+ array(
+ 'target' => POLL_VOTES_TABLE,
+ 'primary' => 'vote_desc.topic_id',
+ 'query_first' => $convert->truncate_statement . POLL_VOTES_TABLE,
+
+ array('poll_option_id', 1, ''),
+ 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' => $convert->truncate_statement . WORDS_TABLE,
+
+ array('word_id', 'words.word_id', ''),
+ array('word', 'words.word', ''),
+ array('replacement', 'words.replacement', ''),
+ ),
+
+ array(
+ 'target' => POSTS_TABLE,
+ 'primary' => 'posts.post_id',
+ 'query_first' => $convert->truncate_statement . POSTS_TABLE,
+ 'execute_first' => '
+ $config["max_post_chars"] = 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', ''),
+ array('post_subject', 'posts_text.post_subject', ''),
+ 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('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',
+ 'query_first' => array(
+ $convert->truncate_statement . PRIVMSGS_TABLE,
+ $convert->truncate_statement . PRIVMSGS_RULES_TABLE,
+ ),
+
+ 'execute_first' => '
+ $config["max_post_chars"] = 0;
+ ',
+
+ array('msg_id', 'privmsgs.privmsgs_id', ''),
+ array('root_level', 0, ''),
+ array('author_id', 'privmsgs.privmsgs_from_userid', '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', 'utf8_htmlspecialchars'),
+ 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('', 'privmsgs.privmsgs_from_userid AS poster_id', ''),
+ array('bbcode_bitfield', '', 'get_bbcode_bitfield'),
+ array('to_address', 'privmsgs.privmsgs_to_userid', 'phpbb_privmsgs_to_userid'),
+
+ 'where' => 'privmsgs.privmsgs_id = privmsgs_text.privmsgs_text_id'
+ ),
+
+ array(
+ 'target' => PRIVMSGS_FOLDER_TABLE,
+ 'primary' => 'users.user_id',
+ 'query_first' => $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' => $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_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', '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_OUTBOX, ''),
+
+ 'where' => '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_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_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_type = 4',
+ ),
+
+ array(
+ 'target' => GROUPS_TABLE,
+ 'query_first' => $convert->truncate_statement . GROUPS_TABLE,
+
+ array('group_id', 'groups.group_id', ''),
+ array('group_type', 'groups.group_type', 'phpbb_convert_group_type'),
+ array('group_display', 0, ''),
+ array('group_name', 'groups.group_name', 'phpbb_convert_group_name'),
+ array('group_desc', 'groups.group_description', ''),
+
+ 'where' => 'groups.group_single_user = 0',
+ ),
+
+ array(
+ 'target' => USER_GROUP_TABLE,
+ 'query_first' => $convert->truncate_statement . USER_GROUP_TABLE,
+ 'execute_first' => '
+ add_default_groups();
+ ',
+
+ 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',
+ 'query_first' => array(
+ 'DELETE FROM ' . USERS_TABLE . ' WHERE user_id <> ' . ANONYMOUS,
+ $convert->truncate_statement . BOTS_TABLE
+ ),
+
+ array('user_id', 'users.user_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', ''),
+ array('username_clean', 'users.username', 'utf8_clean_string'),
+ array('user_password', 'users.user_password', ''),
+ array('user_pass_convert', 1, ''),
+ array('user_posts', 'users.user_posts', ''),
+ array('user_email', 'users.user_email', ''),
+ 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', ''),
+ array('user_lang', $config['default_lang'], ''),
+ array('user_timezone', 'users.user_timezone', ''),
+ array('user_dateformat', 'users.user_dateformat', ''),
+ array('user_inactive_reason', '', 'phpbb_inactive_reason'),
+ array('user_inactive_time', '', 'phpbb_inactive_time'),
+
+ array('user_interests', 'users.user_interests', 'utf8_htmlspecialchars'),
+ array('user_occ', 'users.user_occ', 'utf8_htmlspecialchars'),
+ array('user_website', 'users.user_website', 'validate_website'),
+ array('user_jabber', '', ''),
+ array('user_msnm', 'users.user_msnm', ''),
+ array('user_yim', 'users.user_yim', ''),
+ array('user_aim', 'users.user_aim', ''),
+ array('user_icq', 'users.user_icq', ''),
+ array('user_from', 'users.user_from', 'utf8_htmlspecialchars'),
+ array('user_rank', 'users.user_rank', ''),
+
+ 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', 'get_avatar_width'),
+ array('user_avatar_height', 'users.user_avatar', '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', ''),
+ array('user_emailtime', 'users.user_emailtime', 'null_to_zero'),
+ array('user_notify', 'users.user_notify', ''),
+ array('user_notify_pm', 'users.user_notify_pm', ''),
+ array('user_notify_type', NOTIFY_EMAIL, ''),
+ array('user_allow_pm', 'users.user_allow_pm', ''),
+ array('user_allow_viewonline', 'users.user_allow_viewonline', ''),
+ array('user_allow_viewemail', 'users.user_viewemail', ''),
+ array('user_actkey', 'users.user_actkey', ''),
+ array('user_newpasswd', 'users.user_newpasswd', ''),
+
+ 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', ''),
+
+ 'where' => 'users.user_id <> -1',
+ ),
+ ),
+ );
+}
+
+?> \ No newline at end of file
diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php
new file mode 100644
index 0000000000..8f00067cf6
--- /dev/null
+++ b/phpBB/install/convertors/functions_phpbb20.php
@@ -0,0 +1,1307 @@
+<?php
+/**
+*
+* @package install
+* @version $Id$
+* @copyright (c) 2006 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* Helper functions for phpBB 2.0.x to phpBB 3.0.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, $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 = $db->sql_query($sql);
+ $max_forum_id = (int) $db->sql_fetchfield('max_forum_id');
+ $db->sql_freeresult($result);
+
+ $max_forum_id++;
+
+ // Insert categories
+ $sql = 'SELECT cat_id, cat_title
+ FROM ' . $convert->src_table_prefix . 'categories
+ ORDER BY cat_order';
+ $result = $db->sql_query($sql);
+
+ $cats_added = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $sql_ary = array(
+ 'forum_id' => $max_forum_id,
+ 'forum_name' => ($row['cat_title']) ? htmlspecialchars(phpbb_set_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'] = $cat_row['right_id'] + 1;
+ $sql_ary['right_id'] = $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++;
+ }
+ $db->sql_freeresult($result);
+
+ // Now insert the forums
+ $sql = 'SELECT f.*, 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
+ ORDER BY f.cat_id, f.forum_order';
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ // Define the new forums sql ary
+ $sql_ary = array(
+ 'forum_id' => (int) $row['forum_id'],
+ 'forum_name' => htmlspecialchars(phpbb_set_encoding($row['forum_name']), ENT_COMPAT, 'UTF-8'),
+ 'parent_id' => $cats_added[$row['cat_id']],
+ 'forum_parents' => '',
+ 'forum_desc' => htmlspecialchars(phpbb_set_encoding($row['forum_desc']), ENT_COMPAT, 'UTF-8'),
+ 'forum_type' => FORUM_POST,
+ 'forum_status' => is_item_locked($row['forum_status']),
+ 'enable_prune' => $row['prune_enable'],
+ 'prune_next' => null_to_zero($row['prune_next']),
+ 'prune_days' => null_to_zero($row['prune_days']),
+ 'prune_viewed' => 0,
+ 'prune_freq' => null_to_zero($row['prune_freq']),
+
+ 'forum_flags' => phpbb_forum_flags(),
+
+ // 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' => 0,
+ 'forum_topics' => 0,
+ 'forum_topics_real' => 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'] = $cat_row['right_id'];
+ $sql_ary['right_id'] = $cat_row['right_id'] + 1;
+
+ $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
+ $db->sql_query($sql);
+ }
+ $db->sql_freeresult($result);
+}
+
+function phpbb_set_encoding($text)
+{
+ global $lang_enc_array, $config;
+
+ if (!isset($lang_enc_array[$config['default_lang']]))
+ {
+ global $phpEx, $convert;
+
+ include($convert->convertor_status['forum_path'] . '/language/lang_' . $config['default_lang'] . '/lang_main.' . $phpEx);
+ $lang_enc_array[$config['default_lang']] = $lang['ENCODING'];
+ unset($lang);
+ }
+
+ return utf8_recode($text, $lang_enc_array[$user_lang]);
+}
+
+
+/**
+* Convert Birthday from Birthday MOD to phpBB Format
+* @todo See which birthday MOD's this supports - there appear to be several
+*/
+function phpbb_get_birthday($birthday = '')
+{
+ $birthday = (int) $birthday;
+
+ if (!$birthday || $birthday == 999999)
+ {
+ return ' 0- 0- 0';
+ }
+
+ // @todo Can't this be done with one call to create_date?
+ $bday_day = create_date('j', $birthday * 86400 + 1, 0);
+ $bday_month = create_date('n', $birthday * 86400 + 1, 0);
+ $bday_year = create_date('Y', $birthday * 86400 + 1, 0);
+
+ return sprintf('%2d-%2d-%4d', $bday_day, $bday_month, $bday_year);
+}
+
+/**
+* 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)
+{
+ if (!$user_id)
+ {
+ return 0;
+ }
+
+ if ($user_id == -1)
+ {
+ return ANONYMOUS;
+ }
+
+ global $config;
+
+ // Increment user id if the old forum is having a user with the id 1
+ if (!isset($config['increment_user_id']))
+ {
+ global $db, $convert;
+
+ // 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 = $db->sql_query($sql);
+ $id = (int) $db->sql_fetchfield('user_id');
+ $db->sql_freeresult($result);
+
+ // If there is a user id 1, we need to increment user ids. :/
+ if ($id === 1)
+ {
+ set_config('increment_user_id', 1, true);
+ $config['increment_user_id'] = 1;
+ }
+ else
+ {
+ set_config('increment_user_id', 0, true);
+ $config['increment_user_id'] = 0;
+ }
+ }
+
+ if (!empty($config['increment_user_id']))
+ {
+ $user_id++;
+ }
+
+ return $user_id;
+}
+
+/* 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, $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);
+
+ // Grab user id of first user 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 = $db->sql_query_limit($sql, 1);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $founder_id = phpbb_user_id($row['user_id']);
+
+ // Set a founder admin ... we'll assume it's the first user with admin level access
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET user_type = ' . USER_FOUNDER . "
+ WHERE user_id = $founder_id";
+ $db->sql_query($sql);
+ }
+
+ // Grab forum auth information
+ $sql = "SELECT *
+ FROM {$convert->src_table_prefix}forums";
+ $result = $db->sql_query($sql);
+
+ $forum_access = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $forum_access[] = $row;
+ }
+ $db->sql_freeresult($result);
+
+ // 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
+ WHERE g.group_id = aa.group_id
+ AND g.group_single_user = 1
+ AND ug.group_id = g.group_id";
+ $result = $db->sql_query($sql);
+
+ $user_access = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $user_access[$row['forum_id']][] = $row;
+ }
+ $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 = $db->sql_query($sql);
+
+ $group_access = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $group_access[$row['forum_id']][] = $row;
+ }
+ $db->sql_freeresult($result);
+
+ // Add Forum Access List
+ $auth_map = array(
+ 'auth_view' => array('f_', 'f_list'),
+ 'auth_read' => 'f_read',
+ 'auth_post' => array('f_post', 'f_bbcode', 'f_smilies', 'f_img', 'f_sigs', 'f_search', 'f_postcount'),
+ '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' => 'f_attach',
+ '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);
+ user_group_auth('registered', 'SELECT user_id, {REGISTERED} FROM ' . USERS_TABLE . ' WHERE user_id <> ' . ANONYMOUS);
+
+ // Selecting from old table
+ $auth_sql = 'SELECT ';
+ $auth_sql .= (!empty($config['increment_user_id'])) ? 'user_id + 1 as user_id' : 'user_id';
+ $auth_sql .= ', {ADMINISTRATORS} FROM ' . $convert->src_table_prefix . 'users WHERE user_level = 1';
+
+ user_group_auth('administrators', $auth_sql);
+ }
+ else if ($mode == 'first')
+ {
+ // Go through all 2.0.x forums (we saved those ids for reference)
+ 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_LIMITED_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, '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, $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, 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, $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, phpbb_user_id($access['user_id']), $new_acl, ACL_YES);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if ($mode == 'second')
+ {
+ // Assign permission roles
+
+ // By default all converted administrators are given full access
+ // @todo Review the implications of this - we might want to remove access to clear logs, view phpinfo, etc
+ mass_auth('group_role', 0, 'administrators', 'ADMIN_FULL');
+ mass_auth('group_role', 0, 'administrators', 'MOD_FULL');
+ mass_auth('group_role', 0, 'administrators', 'USER_FULL');
+
+ // All registered users are assigned the standard user role
+ mass_auth('group_role', 0, 'registered', 'USER_STANDARD');
+
+ // 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 = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ mass_auth('user_role', 0, phpbb_user_id($row['user_id']), 'USER_NOAVATAR');
+ }
+ $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 = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ mass_auth('user_role', 0, phpbb_user_id($row['user_id']), 'USER_NOPM');
+ }
+ $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
+ 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, phpbb_user_id($access['user_id']), 'MOD_STANDARD');
+ mass_auth('user_role', $forum_id, phpbb_user_id($access['user_id']), 'FORUM_STANDARD');
+ }
+ }
+ }
+
+ 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, $access['group_id'], 'MOD_STANDARD');
+ mass_auth('group_role', $forum_id, $access['group_id'], 'FORUM_STANDARD');
+ }
+ }
+ }
+
+ // 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');
+ $parent_forums[] = $row;
+ }
+ else
+ {
+ $forums[] = $row;
+ }
+ }
+ $db->sql_freeresult($result);
+
+ global $auth;
+
+ // Let us see if guests/registered users have access to these forums...
+ foreach ($parent_forums as $row)
+ {
+ // Get the childs...
+ $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;
+ }
+ }
+
+ // Now make sure the user is able to read these forums
+ $hold_ary = $auth->acl_group_raw_data(get_group_id('guests'), 'f_list', $forum_ids);
+
+ if (!empty($hold_ary))
+ {
+ mass_auth('group', $row['forum_id'], 'guests', 'f_list', ACL_YES);
+ mass_auth('group', $row['forum_id'], 'registered', '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_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;
+ }
+
+ return GROUP_SPECIAL;
+}
+
+/**
+* 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;
+}
+
+/**
+* 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;
+ global $lang_enc_array;
+
+ /*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 (!$message)
+ {
+ $convert->row['mp_bbcode_bitfield'] = $convert_row = 0;
+ return '';
+ }
+
+ // Decode phpBB 2.0.x Message
+ if (isset($convert->row['old_bbcode_uid']) && $convert->row['old_bbcode_uid'] != '')
+ {
+ $message = preg_replace('/\:(([a-z0-9]:)?)' . $convert->row['old_bbcode_uid'] . '/s', '', $message);
+ }
+
+ if (strpos($message, '[quote=') !== false)
+ {
+ $message = preg_replace('/\[quote="(.*?)"\]/s', '[quote=&quot;\1&quot;]', $message);
+ }
+
+ $user_id = $convert->row['poster_id'];
+
+ $sql = 'SELECT user_lang
+ FROM ' . $convert->src_table_prefix . 'users
+ WHERE user_id = ' . (int) $user_id;
+ $result = $db->sql_query($sql);
+ $user_lang = $db->sql_fetchfield('user_lang');
+ $db->sql_freeresult($result);
+
+ if (empty($lang_enc_array))
+ {
+ $lang_enc_array = array();
+ }
+
+ if (!isset($lang_enc_array[$user_lang]))
+ {
+ $filename = $convert->convertor_status['forum_path'] . '/language/lang_' . $user_lang . '/lang_main.' . $phpEx;
+
+ if (!file_exists($filename))
+ {
+ $user_lang = $config['default_lang'];
+ }
+
+ if (!isset($lang_enc_array[$user_lang]))
+ {
+ include($convert->convertor_status['forum_path'] . '/language/lang_' . $user_lang . '/lang_main.' . $phpEx);
+ $lang_enc_array[$user_lang] = $lang['ENCODING'];
+ unset($lang);
+ }
+ }
+
+ $encoding = $lang_enc_array[$user_lang];
+
+ $message = str_replace('<', '&lt;', $message);
+ $message = str_replace('>', '&gt;', $message);
+ $message = str_replace('<br />', "\n", $message);
+
+ // make the post UTF-8
+ $message = utf8_recode($message, $encoding);
+
+ $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 $db, $convert, $user, $config, $cache;
+
+ $sql = 'SELECT config_value AS upload_dir
+ FROM ' . $convert->src_table_prefix . "attachments_config
+ WHERE config_name = 'upload_dir'";
+ $result = $db->sql_query($sql);
+ $upload_path = $db->sql_fetchfield('upload_dir');
+ $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 = $db->sql_query($sql);
+ $ftp_upload = (int) $db->sql_fetchfield('ftp_upload');
+ $db->sql_freeresult($result);
+
+ 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->convertor_status['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;
+}
+
+/**
+* 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;
+}
+
+/**
+* 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, '');
+ }
+ 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 '';
+}
+
+/**
+* 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, $convert, $config;
+
+ $sql = 'SELECT *
+ FROM ' . $convert->src_table_prefix . 'attachments_config';
+ $result = $db->sql_query($sql);
+
+ $attach_config = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $attach_config[$row['config_name']] = $row['config_value'];
+ }
+ $db->sql_freeresult($result);
+
+ set_config('allow_attachments', 1);
+ set_config('display_order', $attach_config['display_order']);
+ set_config('max_filesize', $attach_config['max_filesize']);
+ set_config('max_filesize_pm', $attach_config['max_filesize_pm']);
+ set_config('attachment_quota', $attach_config['attachment_quota']);
+ set_config('max_attachments', $attach_config['max_attachments']);
+ set_config('max_attachments_pm', $attach_config['max_attachments_pm']);
+ set_config('allow_pm_attach', $attach_config['allow_pm_attach']);
+
+ set_config('img_display_inlined', $attach_config['img_display_inlined']);
+ set_config('img_max_width', $attach_config['img_max_width']);
+ set_config('img_max_height', $attach_config['img_max_height']);
+ set_config('img_link_width', $attach_config['img_link_width']);
+ set_config('img_link_height', $attach_config['img_link_height']);
+ set_config('img_create_thumbnail', $attach_config['img_create_thumbnail']);
+ set_config('img_max_thumb_width', 400);
+ set_config('img_min_thumb_filesize', $attach_config['img_min_thumb_filesize']);
+ set_config('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;
+}
+
+?> \ No newline at end of file
diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php
new file mode 100644
index 0000000000..f9e2583294
--- /dev/null
+++ b/phpBB/install/install_convert.php
@@ -0,0 +1,1667 @@
+<?php
+/**
+*
+* @package install
+* @version $Id$
+* @copyright (c) 2006 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+*/
+
+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 convert
+{
+ var $convertor_status = array();
+
+ var $convertor_tag = '';
+ var $src_table_prefix = '';
+
+ var $convertor_data = array();
+ var $tables = array();
+ var $config_schema = array();
+ var $convertor = array();
+ var $truncate_statement = 'DELETE FROM ';
+
+ var $fulltext_search;
+
+ // Batch size, can be adjusted by the conversion file
+ var $batch_size = 6000;
+ // Number of rows to be inserted at once (extended insert) if supported
+ var $num_wait_rows = 30;
+
+ var $p_master;
+
+ function convert(&$p_master)
+ {
+ $this->p_master = &$p_master;
+ }
+}
+
+class install_convert extends module
+{
+ /**
+ * 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;
+ global $convert;
+
+ $this->tpl_name = 'install_convert';
+ $this->mode = $mode;
+
+ $convert = new convert($this->p_master);
+
+ switch ($sub)
+ {
+ case 'intro':
+ // Try opening config file
+ // @todo If phpBB is not installed, we need to do a cut-down installation here
+ // For now, we redirect to the installation script instead
+ if (@file_exists($phpbb_root_path . 'config.' . $phpEx))
+ {
+ include($phpbb_root_path . 'config.' . $phpEx);
+ }
+
+ if (!defined('PHPBB_INSTALLED'))
+ {
+ $this->p_master->redirect("index.$phpEx?mode=install");
+ }
+
+ require($phpbb_root_path . 'config.' . $phpEx);
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $db = new $sql_db();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false);
+ unset($dbpasswd);
+
+ // We need to fill the config to let internal functions correctly work
+ $sql = 'SELECT *
+ FROM ' . CONFIG_TABLE;
+ $result = $db->sql_query($sql);
+
+ $config = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $config[$row['config_name']] = $row['config_value'];
+ }
+ $db->sql_freeresult($result);
+
+
+ // 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_var('new_conv', 0);
+
+ if ($new_conversion)
+ {
+ $config['convert_progress'] = '';
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'convert_progress'");
+ }
+
+ // Let's see if there is a conversion in the works...
+ $convertor_status = array();
+ if (isset($config['convert_progress']))
+ {
+ $convertor_status = unserialize($config['convert_progress']);
+ // $convertor_status['forum_address'] = $config['conv_forum_address'];
+ $convertor_status['forum_path'] = $config['conv_forum_path'];
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (!empty($convertor_status) && !empty($convertor_status['tag']) && isset($convertor_status['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=$mode&amp;sub=intro&amp;new_conv=1",
+ 'U_CONTINUE_ACTION' => $this->p_master->module_url . "?mode=$mode&amp;sub=in_progress&amp;tag={$convertor_status['tag']}{$convertor_status['step']}",
+ ));
+
+ return;
+ }
+
+ $this->list_convertors($mode, $sub);
+
+ break;
+
+ case 'settings':
+ $this->get_convert_settings($mode, $sub);
+ break;
+
+ case 'in_progress':
+ $this->convert_data($mode, $sub);
+ break;
+
+ case 'final':
+ $this->page_title = $lang['CONVERT_COMPLETE'];
+
+ $template->assign_vars(array(
+ 'TITLE' => $lang['CONVERT_COMPLETE'],
+ 'BODY' => $lang['CONVERT_COMPLETE_EXPLAIN'],
+ ));
+
+ break;
+ }
+ }
+
+ /**
+ * Generate a list of all available conversion modules
+ */
+ function list_convertors($mode, $sub)
+ {
+ global $lang, $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['OPTIONS'],
+ 'L_SOFTWARE' => $lang['SOFTWARE'],
+ 'L_VERSION' => $lang['VERSION'],
+
+ 'S_LIST' => true,
+ ));
+
+ $convertors = $sort = array();
+ $get_info = true;
+
+ $handle = opendir('./convertors/');
+ 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'],
+ '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=$mode&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
+ ));
+ }
+ }
+
+ /**
+ */
+ function get_convert_settings($mode, $sub)
+ {
+ global $lang, $template, $db, $phpbb_root_path, $phpEx, $config, $cache;
+
+ require($phpbb_root_path . 'config.' . $phpEx);
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $db = new $sql_db();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false);
+ unset($dbpasswd);
+
+ $this->page_title = $lang['STAGE_SETTINGS'];
+
+ // We need to fill the config to let internal functions correctly work
+ $sql = 'SELECT *
+ FROM ' . CONFIG_TABLE;
+ $result = $db->sql_query($sql);
+
+ $config = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $config[$row['config_name']] = $row['config_value'];
+ }
+ $db->sql_freeresult($result);
+
+ $convertor_tag = request_var('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_table_prefix = request_var('src_table_prefix', $convertor_data['table_prefix']);
+ $src_path = request_var('src_path', $convertor_data['forum_path']);
+
+ // 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_var('src_url', 'Not in use at the moment');
+
+ $error = array();
+ if ($submit)
+ {
+ if (!file_exists('./../' . $src_path . '/' . $test_file))
+ {
+ $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $src_path);
+ }
+
+ // The forum prefix of the old and the new forum can't be the same because the
+ // convertor requires all tables to be in one database. I.e. there can't be
+ // two tables named 'phpbb_users'
+ if ($src_table_prefix == $table_prefix)
+ {
+ $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
+ }
+
+ // Check table prefix
+ if (!sizeof($error))
+ {
+ $db->sql_return_on_error(true);
+
+ // Try to select one row from the first table to see if the prefix is OK
+ $result = $db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
+
+ if (!$result)
+ {
+ $prefixes = array();
+ if ($result = $db->sql_query('SHOW TABLES'))
+ {
+ while ($row = $db->sql_fetchrow($result))
+ {
+ if (sizeof($row) > 1)
+ {
+ compare_table($tables, $row[0], $prefixes);
+ }
+ else if (list(, $tablename) = @each($row))
+ {
+ compare_table($tables, $tablename, $prefixes);
+ }
+ }
+ $db->sql_freeresult($result);
+ }
+
+ 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;
+ }
+ $db->sql_freeresult($result);
+ $db->sql_return_on_error(false);
+ }
+
+ if (!sizeof($error))
+ {
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => '', 'table_prefix' => $src_table_prefix, 'tag' => $convertor_tag)), true);
+ // set_config('conv_forum_address', $src_url, true); // @todo See note above about this variable
+ set_config('conv_forum_path', './../' . $src_path, true);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $lang['SPECIFY_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=$mode&amp;sub=in_progress&amp;tag=$convertor_tag",
+ ));
+
+ return;
+ }
+ else
+ {
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $lang['SPECIFY_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(
+ 'L_SUBMIT' => $lang['BEGIN_CONVERT'],
+ 'U_ACTION' => $this->p_master->module_url . "?mode=$mode&amp;sub=settings&amp;tag=$convertor_tag",
+ ));
+ }
+
+ /**
+ * The function which does the actual work (or dispatches it to the relevant places)
+ */
+ function convert_data($mode, $sub)
+ {
+ global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
+ global $convert, $convert_row, $message_parser, $skip_rows;
+
+ require($phpbb_root_path . 'config.' . $phpEx);
+ require($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
+ require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $db = new $sql_db();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false);
+ unset($dbpasswd);
+
+ $sql = 'SELECT *
+ FROM ' . CONFIG_TABLE;
+ $result = $db->sql_query($sql);
+
+ $config = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $config[$row['config_name']] = $row['config_value'];
+ }
+ $db->sql_freeresult($result);
+
+ // 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'] = -1;
+
+ // 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->convertor_status = array();
+ if (isset($config['convert_progress']))
+ {
+ $convert->convertor_status = unserialize($config['convert_progress']);
+ // $convert->convertor_status['forum_address'] = $config['conv_forum_address'];
+ $convert->convertor_status['forum_path'] = $config['conv_forum_path'];
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (empty($convert->convertor_status) || empty($convert->convertor_status['tag']) || !isset($convert->convertor_status['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->convertor_status['tag']);
+ $convert->src_table_prefix = $convert->convertor_status['table_prefix'];
+ $convert->truncate_statement = ($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ';
+
+ $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->convertor_status['forum_path'] . '/' . $test_file))
+ {
+ $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->convertor_status['forum_path']), __LINE__, __FILE__);
+ }
+
+ $search_type = $config['search_type'];
+
+ if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
+ {
+ trigger_error('NO_SUCH_SEARCH_MODULE');
+ }
+
+ require($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx);
+
+ $error = false;
+ $convert->fulltext_search = new $search_type($error);
+
+ if ($error)
+ {
+ trigger_error($error);
+ }
+
+ include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ $message_parser = new parse_message();
+
+ $jump = request_var('jump', 0);
+ $sync_batch = request_var('sync_batch', -1);
+ $last_statement = request_var('last', 0);
+
+ // We are running sync...
+ if ($sync_batch >= 0)
+ {
+ $this->sync_forums($sync_batch);
+ return;
+ }
+
+ if ($jump)
+ {
+ $this->jump($jump, $last_statement);
+ return;
+ }
+
+ $current_table = request_var('current_table', 0);
+ $old_current_table = min(-1, $current_table - 1);
+ $skip_rows = request_var('skip_rows', 0);
+
+ if (!$current_table && !$skip_rows)
+ {
+ if (empty($_REQUEST['confirm']))
+ {
+ // 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 (!is_writeable($phpbb_root_path . $local_path))
+ {
+ $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=$mode&amp;sub=in_progress&amp;tag={$convert->convertor_tag}",
+ ));
+ 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
+ $db->sql_return_on_error(true);
+ foreach ($tables_list as $table => $null)
+ {
+ $sql = 'SELECT 1 FROM ' . $table;
+ $_result = $db->sql_query_limit($sql, 1);
+
+ if (!$_result)
+ {
+ $missing_tables[] = $table;
+ }
+ $db->sql_freeresult($_result);
+ }
+ $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(', ', $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
+ }
+
+ $step = '&amp;confirm=1';
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $msg = $user->lang['PRE_CONVERT_COMPLETE'] . '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
+ $url = $this->p_master->module_url . "?mode=$mode&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'L_MESSAGE' => $msg,
+ 'U_ACTION' => $url,
+ ));
+
+ return;
+ } // if (empty($_REQUEST['confirm']))
+
+ $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);
+ }
+
+ $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']))
+ {
+ eval($convert->convertor['execute_first']);
+ }
+
+ if (!empty($convert->convertor['query_first']))
+ {
+ if (!is_array($convert->convertor['query_first']))
+ {
+ $convert->convertor['query_first'] = array($convert->convertor['query_first']);
+ }
+
+ foreach ($convert->convertor['query_first'] as $query_first)
+ {
+ $db->sql_query($query_first);
+ }
+ }
+
+ $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']))
+ {
+ eval($schema['execute_first']);
+ }
+
+ if (!empty($schema['query_first']))
+ {
+ if (!is_array($schema['query_first']))
+ {
+ $schema['query_first'] = array($schema['query_first']);
+ }
+
+ foreach ($schema['query_first'] as $query_first)
+ {
+ $db->sql_query($query_first);
+ }
+ }
+ }
+
+ // 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']))
+ {
+ eval($schema['execute_always']);
+ }
+
+ //
+ // 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
+ $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . $schema['group_by'] : '';
+
+ // Having
+ $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
+
+ // Order By
+ $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_EXTRA')) ? ceil(memory_get_usage()/1024) . ' KB' : ''),
+ ));
+
+ $mtime = explode(' ', microtime());
+ $batch_time = $mtime[0] + $mtime[1];
+
+ // Take skip rows into account and only fetch batch_size amount of rows
+ $___result = $db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
+
+ // This loop processes each row
+ $counting = 0;
+
+ $convert->row = $convert_row = array();
+
+ // Now handle the rows until time is over or no more rows to process...
+ while (still_on_time())
+ {
+ $convert_row = $db->sql_fetchrow($___result);
+
+ if (!$convert_row)
+ {
+ // move to the next batch or table
+ $db->sql_freeresult($___result);
+ 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->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++;
+ }
+ $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();
+ }
+ }
+
+ // 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_EXTRA')*/)
+ {
+ $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.
+ $step = '&amp;current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows;
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $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']));
+
+ $url = $this->p_master->module_url . "?mode=$mode&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $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
+ $step = '&amp;jump=1';
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $url = $this->p_master->module_url . "?mode=$mode&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * Sync function being executed at the very end...
+ */
+ 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_approved', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, false);
+ 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_EXTRA')) ? ' [' . ceil(memory_get_usage()/1024) . ' KB]' : ''),
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $sync_batch += $batch_size;
+ }
+
+ if ($sync_batch >= $primary_max)
+ {
+ $sync_batch = -1;
+
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
+ WHERE config_name = 'convert_progress' OR config_name = 'conv_forum_path' OR config_name = 'conv_forum_address'");
+ $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
+
+ @unlink($phpbb_root_path . 'cache/data_global.php');
+ cache_moderators();
+
+ // And finally, add a note to the log
+ add_log('admin', 'LOG_INSTALL_CONVERTED', $convert->convertor_data['forum_name'], $config['version']);
+
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=final";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ else
+ {
+ $sync_batch -= $batch_size;
+ }
+
+ $step = '&amp;sync_batch=' . $sync_batch;
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->convertor_status['table_prefix'], 'tag' => $convert->convertor_tag)), true);
+
+ $url = $this->p_master->module_url . "?mode=$this->mode&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * This function marks the end of conversion (jump=1)
+ */
+ function jump($jump, $last_statement)
+ {
+ global $template, $user, $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']))
+ {
+ eval($convert->convertor['execute_last']);
+ }
+ else
+ {
+ while ($last_statement < sizeof($convert->convertor['execute_last']))
+ {
+ eval($convert->convertor['execute_last'][$last_statement]);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $convert->convertor['execute_last'][$last_statement],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $last_statement++;
+ $step = '&amp;jump=1&amp;last=' . $last_statement;
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $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);
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $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($convert->convertor['query_last']);
+ }
+
+ foreach ($convert->convertor['query_last'] as $query_last)
+ {
+ $db->sql_query($query_last);
+ }
+ }
+
+ // Sanity check
+ $db->sql_return_on_error(false);
+
+ fix_empty_primary_groups();
+
+ if (!isset($config['board_startdate']))
+ {
+ $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 (($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0) || !isset($config['board_startdate']))
+ {
+ set_config('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'],
+ ));
+
+ $step = '&amp;jump=2';
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $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');
+ $cache->destroy('sql', FORUMS_TABLE);
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['SYNC_FORUMS'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $step = '&amp;jump=3';
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ if ($jump == 3)
+ {
+ update_topics_posted();
+
+ $template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ // Continue with synchronizing the forums...
+ $step = '&amp;sync_batch=0';
+
+ // Save convertor Status
+ set_config('convert_progress', serialize(array('step' => $step, 'table_prefix' => $convert->src_table_prefix, 'tag' => $convert->convertor_tag)), true);
+
+ $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step";
+
+ $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->sql_layer, 'mysql') === 0 && !defined('DEBUG_EXTRA')) ? '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]))
+ {
+ // Execute complex function/eval/typecast
+ $value = $fields[1];
+
+ 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);
+ eval($execution);
+ }
+ }
+ }
+ 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);
+ eval($execution);
+ }
+ }
+ }
+ 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)
+ {
+ if (!defined('DEBUG_EXTRA'))
+ {
+ meta_refresh(5, $url);
+ }
+ }
+
+ /**
+ * The information below will be used to build the input fields presented to the user
+ */
+ var $convert_options = array(
+ 'legend1' => 'SPECIFY_OPTIONS',
+ '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),
+ 'src_path' => array('lang' => 'FORUM_PATH', 'type' => 'text:25:100', 'explain' => true),
+ );
+}
+
+?> \ No newline at end of file