Вход Регистрация
Файл: library/XenForo/Importer/vBulletin.php
Строк: 2128
<?php

class XenForo_Importer_vBulletin extends XenForo_Importer_Abstract
{
    
/**
     * Source database connection.
     *
     * @var Zend_Db_Adapter_Abstract
     */
    
protected $_sourceDb;

    protected 
$_prefix;

    protected 
$_charset 'windows-1252';

    protected 
$_config;

    protected 
$_groupMap null;

    protected 
$_userFieldMap null;

    public static function 
getName()
    {
        return 
'vBulletin 3.7/3.8';
    }

    public function 
configure(XenForo_ControllerAdmin_Abstract $controller, array &$config)
    {
        if (
$config)
        {
            
$errors $this->validateConfiguration($config);
            if (
$errors)
            {
                return 
$controller->responseError($errors);
            }

            if (isset(
$config['attachmentPath']) || isset($config['avatarPath']))
            {
                
// already configured
                
return true;
            }

            
$this->_bootstrap($config);

            
$settings $this->_sourceDb->fetchPairs('
                SELECT varname, value
                FROM ' 
$this->_prefix 'setting
                WHERE varname IN ('
attachpath', 'attachfile', 'avatarpath', 'usefileavatar')
            '
);
            if ((
$settings['attachfile'] && $settings['attachpath'])
                || (
$settings['usefileavatar'] && $settings['avatarpath']))
            {
                return 
$controller->responseView('XenForo_ViewAdmin_Import_vBulletin_Config''import_vbulletin_config', array(
                    
'config' => $config,
                    
'attachmentPath' => ($settings['attachfile'] ? $settings['attachpath'] : ''),
                    
'avatarPath' => ($settings['usefileavatar'] ? $settings['avatarpath'] : ''),
                    
'retainKeys' => $config['retain_keys'],
                ));
            }

            return 
true;
        }
        else
        {

            
$configPath getcwd() . '/includes/config.php';
            if (
file_exists($configPath) && is_readable($configPath))
            {
                
$config = array();
                include(
$configPath);

                
$viewParams = array('input' => $config);
            }
            else
            {
                
$viewParams = array('input' => array
                (
                    
'MasterServer' => array
                    (
                        
'servername' => 'localhost',
                        
'port' => 3306,
                        
'username' => '',
                        
'password' => '',
                    ),
                    
'Database' => array
                    (
                        
'dbname' => '',
                        
'tableprefix' => ''
                    
),
                    
'Mysqli' => array
                    (
                        
'charset' => ''
                    
),
                ));
            }

            return 
$controller->responseView('XenForo_ViewAdmin_Import_vBulletin_Config''import_vbulletin_config'$viewParams);
        }
    }

    public function 
validateConfiguration(array &$config)
    {
        
$errors = array();

        
$config['db']['prefix'] = preg_replace('/[^a-z0-9_]/i'''$config['db']['prefix']);

        try
        {
            
$db Zend_Db::factory('mysqli',
                array(
                    
'host' => $config['db']['host'],
                    
'port' => $config['db']['port'],
                    
'username' => $config['db']['username'],
                    
'password' => $config['db']['password'],
                    
'dbname' => $config['db']['dbname'],
                    
'charset' => $config['db']['charset']
                )
            );
            
$db->getConnection();
        }
        catch (
Zend_Db_Exception $e)
        {
            
$errors[] = new XenForo_Phrase('source_database_connection_details_not_correct_x', array('error' => $e->getMessage()));
        }

        if (
$errors)
        {
            return 
$errors;
        }

        try
        {
            
$db->query('
                SELECT userid
                FROM ' 
$config['db']['prefix'] . 'user
                LIMIT 1
            '
);
        }
        catch (
Zend_Db_Exception $e)
        {
            if (
$config['db']['dbname'] === '')
            {
                
$errors[] = new XenForo_Phrase('please_enter_database_name');
            }
            else
            {
                
$errors[] = new XenForo_Phrase('table_prefix_or_database_name_is_not_correct');
            }
        }

        if (!empty(
$config['attachmentPath']))
        {
            if (!
file_exists($config['attachmentPath']) || !is_dir($config['attachmentPath']))
            {
                
$errors[] = new XenForo_Phrase('attachments_directory_not_found');
            }
        }

        if (!empty(
$config['avatarPath']))
        {
            if (!
file_exists($config['avatarPath']) || !is_dir($config['avatarPath']))
            {
                
$errors[] = new XenForo_Phrase('avatars_directory_not_found');
            }
        }

        if (!
$errors)
        {
            
$defaultLanguageId $db->fetchOne('
                SELECT value
                FROM ' 
$config['db']['prefix'] . 'setting
                WHERE varname = '
languageid'
            '
);
            
$defaultCharset $db->fetchOne('
                SELECT charset
                FROM ' 
$config['db']['prefix'] . 'language
                WHERE languageid = ?
            '
$defaultLanguageId);
            if (!
$defaultCharset || str_replace('-'''strtolower($defaultCharset)) == 'iso88591')
            {
                
$config['charset'] = 'windows-1252';
            }
            else
            {
                
$config['charset'] = strtolower($defaultCharset);
            }
        }

        return 
$errors;
    }

    public function 
getSteps()
    {
        return array(
            
'userGroups' => array(
                
'title' => new XenForo_Phrase('import_user_groups')
            ),
            
'userFields' => array(
                
'title' => new XenForo_Phrase('import_custom_user_fields'),
            ),
            
'users' => array(
                
'title' => new XenForo_Phrase('import_users'),
                
'depends' => array('userGroups''userFields')
            ),
            
'avatars' => array(
                
'title' => new XenForo_Phrase('import_custom_avatars'),
                
'depends' => array('users')
            ),
            
'buddyIgnore' => array(
                
'title' => new XenForo_Phrase('import_buddy_ignore_lists'),
                
'depends' => array('users')
            ),
            
'paidSubscriptions' => array(
                
'title' => new XenForo_Phrase('import_paid_subscriptions'),
                
'depends' => array('users')
            ),
            
'privateMessages' => array(
                
'title' => new XenForo_Phrase('import_private_messages'),
                
'depends' => array('users')
            ),
            
'visitorMessages' => array(
                
'title' => new XenForo_Phrase('import_profile_comments'),
                
'depends' => array('users')
            ),
            
'forums' => array(
                
'title' => new XenForo_Phrase('import_forums'),
                
'depends' => array('userGroups')
            ),
            
'moderators' => array(
                
'title' => new XenForo_Phrase('import_moderators'),
                
'depends' => array('forums''users')
            ),
            
'threadPrefixes' => array(
                
'title' => new XenForo_Phrase('import_thread_prefixes'),
                
'depends' => array('forums')
            ),
            
'threads' => array(
                
'title' => new XenForo_Phrase('import_threads_and_posts'),
                
'depends' => array('forums''users''threadPrefixes')
            ),
            
'postEditHistory' => array(
                
'title' => new XenForo_Phrase('import_post_edit_history'),
                
'depends' => array('threads')
            ),
            
'polls' => array(
                
'title' => new XenForo_Phrase('import_polls'),
                
'depends' => array('threads')
            ),
            
'attachments' => array(
                
'title' => new XenForo_Phrase('import_attached_files'),
                
'depends' => array('threads')
            ),
            
'reputation' => array(
                
'title' => new XenForo_Phrase('import_positive_reputation'),
                
'depends' => array('threads')
            ),
            
'infractions' => array(
                
'title' => new XenForo_Phrase('import_infractions'),
                
'depends' => array('threads')
            ),
        );

        
// deferred: albums/comments, announcements, custom bb code, calendars/events, social groups, tags
    
}

    protected function 
_bootstrap(array $config)
    {
        if (
$this->_sourceDb)
        {
            
// already run
            
return;
        }

        @
set_time_limit(0);

        
$this->_config $config;

        
$this->_sourceDb Zend_Db::factory('mysqli',
            array(
                
'host' => $config['db']['host'],
                
'port' => $config['db']['port'],
                
'username' => $config['db']['username'],
                
'password' => $config['db']['password'],
                
'dbname' => $config['db']['dbname'],
                
'charset' => $config['db']['charset']
            )
        );
        if (empty(
$config['db']['charset']))
        {
            
$this->_sourceDb->query('SET character_set_results = NULL');
        }

        
$this->_prefix preg_replace('/[^a-z0-9_]/i'''$config['db']['prefix']);

        if (!empty(
$config['charset']))
        {
            
$this->_charset $config['charset'];
        }
    }

    public function 
stepUserGroups($start, array $options)
    {
        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;
        
$model->retainableKeys[] = 'user_group_id';

        
$userGroups $sDb->fetchAll('
            SELECT *
            FROM ' 
$prefix 'usergroup
            ORDER BY usergroupid
        '
);

        
$total 0;

        
XenForo_Db::beginTransaction();

        foreach (
$userGroups AS $userGroup)
        {
            
$titlePriority 5;
            switch (
$userGroup['usergroupid'])
            {
                case 
1// guests
                    
$model->logImportData('userGroup'$userGroup['usergroupid'], XenForo_Model_User::$defaultGuestGroupId);
                    break;

                case 
2// registered users
                
case 3// email confirm
                
case 4// moderation
                    
$model->logImportData('userGroup'$userGroup['usergroupid'], XenForo_Model_User::$defaultRegisteredGroupId);
                    break;

                case 
6// admins
                    
$model->logImportData('userGroup'$userGroup['usergroupid'], XenForo_Model_User::$defaultAdminGroupId);
                    continue;

                case 
7// mods
                    
$model->logImportData('userGroup'$userGroup['usergroupid'], XenForo_Model_User::$defaultModeratorGroupId);
                    continue;

                case 
5// super mods
                    
$titlePriority 910;

                default:
                    
$import = array(
                        
'title' => $this->_convertToUtf8($userGroup['title']),
                        
'user_title' => $this->_convertToUtf8($userGroup['usertitle']),
                        
'display_style_priority' => $titlePriority,
                        
'permissions' => $this->_calculateUserGroupPermissions($userGroup)
                    );

                    if (
$model->importUserGroup($userGroup['usergroupid'], $import))
                    {
                        
$total++;
                    }
            }
        }

        
XenForo_Model::create('XenForo_Model_UserGroup')->rebuildDisplayStyleCache();

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return 
true;
    }

    protected function 
_calculateUserGroupPermissions(array $userGroup)
    {
        
$perms = array();

        
$userGroup['forumpermissions'] = intval($userGroup['forumpermissions']);
        
$userGroup['genericpermissions'] = intval($userGroup['genericpermissions']);
        
$userGroup['adminpermissions'] = intval($userGroup['adminpermissions']);

        if (
$userGroup['forumpermissions'] & 1)
        {
            
$perms['general']['view'] = 'allow';
            
$perms['general']['viewNode'] = 'allow';
            
$perms['forum']['like'] = 'allow';
        }

        if (
$userGroup['forumpermissions'] & 524288)
        {
            
$perms['forum']['viewContent'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 2)
        {
            
$perms['forum']['viewOthers'] = 'allow';
        }

        if (
$userGroup['genericpermissions'] & 1)
        {
            
$perms['general']['viewProfile'] = 'allow';
        }

        if ((
$userGroup['adminpermissions'] & 1) || ($userGroup['adminpermissions'] & 2))
        {
            
$perms['general']['bypassFloodCheck'] = 'allow';
        }

        if (
$userGroup['forumpermissions'] & 4)
        {
            
$perms['general']['search'] = 'allow';
        }

        if (
$userGroup['forumpermissions'] & 131072)
        {
            
$perms['general']['followModerationRules'] = 'allow';
        }

        if (
$userGroup['forumpermissions'] & 16)
        {
            
$perms['forum']['postThread'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 32)
        {
            
$perms['forum']['postReply'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 256)
        {
            
$perms['forum']['deleteOwnPost'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 512)
        {
            
$perms['forum']['deleteOwnThread'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 128)
        {
            
$perms['forum']['editOwnPost'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 4096)
        {
            
$perms['forum']['viewAttachment'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 8192)
        {
            
$perms['forum']['uploadAttachment'] = 'allow';
        }
        if (
$userGroup['forumpermissions'] & 32768)
        {
            
$perms['forum']['votePoll'] = 'allow';
        }

        if (
$userGroup['pmsendmax'])
        {
            
$perms['conversation']['start'] = 'allow';
            
$perms['conversation']['receive'] = 'allow';
            
$perms['conversation']['maxRecipients'] = $userGroup['pmsendmax'];
            if (
$perms['conversation']['maxRecipients'] > 2147483647)
            {
                
$perms['conversation']['maxRecipients'] = -1;
            }
        }

        if (
$userGroup['genericpermissions'] & 512)
        {
            
$perms['avatar']['allowed'] = 'allow';
            
$perms['avatar']['maxFileSize'] = ($userGroup['avatarmaxsize'] > $userGroup['avatarmaxsize'] : -1);
            if (
$perms['avatar']['maxFileSize'] > 2147483647)
            {
                
$perms['avatar']['maxFileSize'] = -1;
            }
        }

        if (isset(
$userGroup['visitormessagepermissions']))
        {
            
$userGroup['visitormessagepermissions'] = intval($userGroup['visitormessagepermissions']);

            if (
$userGroup['visitormessagepermissions'] & 1)
            {
                
$perms['profilePost']['view'] = 'allow'// this checks against "can message own", which isn't perfect
                
$perms['profilePost']['like'] = 'allow';
            }
            if (
$userGroup['visitormessagepermissions'] & 2)
            {
                
$perms['profilePost']['post'] = 'allow'// this checks against "can message others"
                
$perms['profilePost']['comment'] = 'allow';
            }
            if (
$userGroup['visitormessagepermissions'] & 4)
            {
                
$perms['profilePost']['editOwn'] = 'allow';
            }
            if (
$userGroup['visitormessagepermissions'] & 8)
            {
                
$perms['profilePost']['deleteOwn'] = 'allow';
            }
            if (
$userGroup['visitormessagepermissions'] & 32)
            {
                
$perms['profilePost']['manageOwn'] = 'allow';
            }
        }
        else
        {
            
// vBulletin 3.6
            
if (isset($perms['general']['view']))
            {
                
$perms['profilepost']['view'] = $perms['general']['view'];
            }
            if (isset(
$perms['forum']['like']))
            {
                
$perms['profilepost']['like'] = $perms['forum']['like'];
            }
            if (isset(
$perms['forum']['postReply']))
            {
                
$perms['profilePost']['post'] = $perms['forum']['postReply'];
            }
            if (isset(
$perms['forum']['editOwnPost']))
            {
                
$perms['profilePost']['editOwn'] = $perms['forum']['editOwnPost'];
            }
            if (isset(
$perms['forum']['deleteOwnPost']))
            {
                
$perms['profilePost']['deleteOwn'] = $perms['forum']['deleteOwnPost'];
            }
        }

        return 
$perms;
    }

    public function 
stepUserFields($start, array $options)
    {
        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        
// fetch all profile fields except 1-4, for which we already have analogues
        
$profileFields $sDb->fetchAll('
            SELECT *
            FROM ' 
$prefix 'profilefield
            WHERE profilefieldid > 4
        '
);

        
$phrases $sDb->fetchPairs('
            SELECT varname, text
            FROM ' 
$prefix 'phrase
            WHERE languageid = 0
            AND fieldname = ?
        '
'cprofilefield');

        
$existingFields XenForo_Model::create('XenForo_Model_UserField')->getUserFields();

        
$userFieldLookups = array();
        
$total 0;

        
XenForo_Db::beginTransaction($this->_db);

        foreach (
$profileFields AS $profileField)
        {
            
$title $this->_convertToUtf8($phrases["field$profileField[profilefieldid]_title"]);
            
$description $this->_convertToUtf8($phrases["field$profileField[profilefieldid]_desc"]);

            
$fieldId $model->getUniqueFieldId(
                
str_replace('-''_'XenForo_Link::getTitleForUrl($titletrue)),
                
$existingFields,
                
25);

            
$import = array(
                
'field_id' => $fieldId,
                
'title' => $title,
                
'description' => $description,
                
'display_order' => $profileField['displayorder'],
                
'max_length' => $profileField['maxlength'],
                
'viewable_profile' => !$profileField['hidden'],
            );

            switch (
$profileField['type'])
            {
                case 
'select':
                case 
'radio':
                case 
'checkbox':
                    
$import['field_type'] = $profileField['type'];
                    
$import['field_choices'] = $this->_convertUserFieldChoices($profileField$userFieldLookups);
                    if (!
$import['field_choices'])
                    {
                        continue;
                    }
                    break;

                case 
'select_multiple':
                    
$import['field_type'] = 'multiselect';
                    
$import['field_choices'] = $this->_convertUserFieldChoices($profileField$userFieldLookups);
                    if (!
$import['field_choices'])
                    {
                        continue;
                    }
                    break;

                case 
'textarea':
                    
$import['field_type'] = 'textarea';
                    break;

                case 
'input':
                default:
                    
$import['field_type'] = 'textbox';
                    break;
            }

            switch (
$profileField['required'])
            {
                case 
3// yes, always
                
case 1// yes, at registration and profile update
                    
$import['required'] = 1;
                    
$import['show_registration'] = 1;
                    break;

                case 
2// no, but display at registration
                    
$import['required'] = 0;
                    
$import['show_registration'] = 1;
                    break;

                case 
0// no
                
default:
                    
$import['required'] = 0;
                    
$import['show_registration'] = 0;
                    break;
            }

            switch (
$profileField['editable'])
            {
                case 
0// no
                    
$import['user_editable'] = 'never';
                    break;

                case 
2// only at registration
                    
$import['user_editable'] = 'once';
                    break;

                case 
1// yes
                
default:
                    
$import['user_editable'] = 'yes';
                    break;
            }

            switch (
$profileField['form'])
            {
                case 
0// edit your details
                    
$import['display_group'] = 'personal';
                    break;

                case 
1// options: login / privacy
                
case 2// options: messaging
                
case 3// options: thread viewing
                
case 4// options: date / time
                
case 5// options: other
                
default:
                    
$import['display_group'] = 'preferences';
                    break;
            }

            if (
$profileField['regex'])
            {
                
$import['match_type'] = 'regex';
                
$import['match_regex'] = $this->_convertToUtf8($profileField['regex']);
            }
            else
            {
                
$import['match_type'] = 'none';
            }

            if (
$imported $model->importUserField($profileField['profilefieldid'], $import))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit($this->_db);

        
$this->_session->setExtraData('userFieldLookups'$userFieldLookups);

        
$this->_session->incrementStepImportTotal($total);

        return 
true;
    }

    protected function 
_convertUserFieldChoices(array $profileField, array &$fieldChoiceLookups)
    {
        try
        {
            
$choiceData = @unserialize($profileField['data']);
        }
        catch (
Exception $e)
        {
            
// this is either corrupted data or an invalid char set. The latter isn't something we can automatically detect
            
return array();
        }

        if (!
is_array($choiceData))
        {
            return array();
        }

        
$choices = array();

        foreach (
$choiceData AS $key => $choice)
        {
            
$choice $this->_convertToUtf8($choice);

            
$choiceId XenForo_Helper_String::wholeWordTrim($choice230'');

            if (
$choiceId != '')
            {
                
$choiceId str_replace('-''_'XenForo_Link::getTitleForUrl($choiceIdtrue));

                
$i 1;
                
$choiceIdBase $choiceId;
                while (isset(
$choices[$choiceId]))
                {
                    
$choiceId $choiceIdBase '_' . ++$i;
                }
            }
            else
            {
                
$choiceId $key;
            }

            
$choices[$choiceId] = $choice;
        }

        
$lookUps = array();

        switch (
$profileField['type'])
        {
            case 
'checkbox':
            case 
'select_multiple':
                
$multiple true;
                
$i 1;
                foreach (
$choices AS $key => $value)
                {
                    
$lookUps[$i] = $key;
                    
$i $i 2;
                }
                break;

            case 
'select':
            case 
'radio':
            default:
                
$multiple false;
                foreach (
$choices AS $key => $value)
                {
                    
$lookUps[$value] = $key;
                }
                break;
        }

        
$fieldChoiceLookups[$profileField['profilefieldid']] = array(
            
'multiple' => $multiple,
            
'choices' => $lookUps
        
);

        return 
$choices;
    }

    public function 
configStepUsers(array $options)
    {
        if (
$options)
        {
            return 
false;
        }

        return 
$this->_controller->responseView('XenForo_ViewAdmin_Import_vBulletin_ConfigUsers''import_config_users');
    }

    public function 
stepUsers($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 100,
            
'max' => false,
            
// all checkbox options must default to false as they may not be submitted
            
'mergeEmail' => false,
            
'mergeName' => false,
            
'gravatar' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(userid)
                FROM ' 
$prefix 'user
            '
);
        }

        
$users $sDb->fetchAll(
            
$sDb->limit($this->_getSelectUserSql('user.userid > ' $sDb->quote($start)), $options['limit'])
        );
        if (!
$users)
        {
            return 
$this->_getNextUserStep();
        }

        
XenForo_Db::beginTransaction();

        
$next 0;
        
$total 0;
        foreach (
$users AS $user)
        {
            
$next $user['userid'];

            
$imported $this->_importOrMergeUser($user$options);
            if (
$imported)
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepBuddyIgnore($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 100,
            
'max' => false,
        ), 
$options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(userid)
                FROM ' 
$prefix 'user
            '
);
        }

        
$users $sDb->fetchAll(
            
$sDb->limit($this->_getSelectUserSql('user.userid > ' $sDb->quote($start)
                . 
" AND (usertextfield.buddylist <> '' OR usertextfield.ignorelist <> '')"), $options['limit'])
        );
        if (!
$users)
        {
            return 
$this->_getNextUserStep();
        }

        
XenForo_Db::beginTransaction();

        
$next 0;
        
$total 0;
        foreach (
$users AS $user)
        {
            
$next $user['userid'];

            if (
$this->_importBuddyIgnore($user$options))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    protected function 
_importBuddyIgnore(array $user, array $options)
    {
        
$userIds $user['userid'] . ' ' $user['buddylist'] . ' ' $user['ignorelist'];
        
$userIds preg_split('/s+/'$userIds, -1PREG_SPLIT_NO_EMPTY);
        
$userMap $this->_importModel->getImportContentMap('user'$userIds);

        
$importedUserId $this->_mapLookUp($userMap$user['userid']);
        if (!
$importedUserId)
        {
            return 
false;
        }

        if (
$user['buddylist'])
        {
            
$buddyIds preg_split('/s/'$user['buddylist'], -1PREG_SPLIT_NO_EMPTY);
            
$buddyIds $this->_mapLookUpList($userMap$buddyIds);
            
$this->_importModel->importFollowing($importedUserId$buddyIds);
        }

        if (
$user['ignorelist'])
        {
            
$ignoreIds preg_split('/s/'$user['ignorelist'], -1PREG_SPLIT_NO_EMPTY);
            
$ignoreIds $this->_mapLookUpList($userMap$ignoreIds);
            
$this->_importModel->importIgnored($importedUserId$ignoreIds);
        }

        return 
$importedUserId;
    }

    public function 
stepUsersMerge($start, array $options)
    {
        
$sDb $this->_sourceDb;

        
$manual $this->_session->getExtraData('userMerge');

        if (
$manual)
        {
            
$merge $sDb->fetchAll($this->_getSelectUserSql('user.userid IN (' $sDb->quote(array_keys($manual)) . ')'));

            
$resolve $this->_controller->getInput()->filterSingle('resolve'XenForo_Input::ARRAY_SIMPLE);
            if (
$resolve && !empty($options['shownForm']))
            {
                
$this->_session->unsetExtraData('userMerge');
                
$this->_resolveUserConflicts($merge$resolve);
            }
            else
            {
                
// prevents infinite loop if redirected back to step
                
$options['shownForm'] = true;
                
$this->_session->setStepInfo(0$options);

                
$users = array();
                foreach (
$merge AS $user)
                {
                    
$users[$user['userid']] = array(
                        
'username' => $this->_convertToUtf8($user['username'], true),
                        
'email' => $this->_convertToUtf8($user['email']),
                        
'message_count' => $user['posts'],
                        
'register_date' => $user['joindate'],
                        
'conflict' => $manual[$user['userid']]
                    );
                }

                return 
$this->_controller->responseView(
                    
'XenForo_ViewAdmin_Import_MergeUsers''import_merge_users', array('users' => $users)
                );
            }
        }

        return 
$this->_getNextUserStep();
    }

    public function 
stepUsersFailed($start, array $options)
    {
        
$sDb $this->_sourceDb;

        
$manual $this->_session->getExtraData('userFailed');

        if (
$manual)
        {
            
$users $this->_sourceDb->fetchAll($this->_getSelectUserSql('user.userid IN (' $sDb->quote(array_keys($manual)) . ')'));

            
$resolve $this->_controller->getInput()->filterSingle('resolve'XenForo_Input::ARRAY_SIMPLE);
            if (
$resolve && !empty($options['shownForm']))
            {
                
$this->_session->unsetExtraData('userFailed');
                
$this->_resolveUserConflicts($users$resolve);
            }
            else
            {
                
// prevents infinite loop if redirected back to step
                
$options['shownForm'] = true;
                
$this->_session->setStepInfo(0$options);

                
$failedUsers = array();
                foreach (
$users AS $user)
                {
                    
$failedUsers[$user['userid']] = array(
                        
'username' => $this->_convertToUtf8($user['username'], true),
                        
'email' => $this->_convertToUtf8($user['email']),
                        
'message_count' => $user['posts'],
                        
'register_date' => $user['joindate'],
                        
'failure' => $manual[$user['userid']]
                    );
                }

                return 
$this->_controller->responseView(
                    
'XenForo_ViewAdmin_Import_FailedUsers''import_failed_users', array('users' => $failedUsers)
                );
            }
        }

        return 
$this->_getNextUserStep();
    }

    protected function 
_resolveUserConflicts(array $users, array $resolve)
    {
        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        
$total 0;

        
XenForo_Db::beginTransaction();

        foreach (
$users AS $user)
        {
            if (empty(
$resolve[$user['userid']]))
            {
                continue;
            }

            
$info $resolve[$user['userid']];

            if (empty(
$info['action']) || $info['action'] == 'change')
            {
                if (isset(
$info['email']))
                {
                    
$user['email'] = $info['email'];
                }
                if (isset(
$info['username']))
                {
                    
$user['username'] = $info['username'];
                }

                
$imported $this->_importOrMergeUser($user);
                if (
$imported)
                {
                    
$total++;
                }
            }
            else if (
$info['action'] == 'merge')
            {
                
$im $this->_importModel;

                if (
$match $im->getUserIdByEmail($this->_convertToUtf8($user['email'])))
                {
                    
$this->_mergeUser($user$match);
                }
                else if (
$match $im->getUserIdByUserName($this->_convertToUtf8($user['username'], true)))
                {
                    
$this->_mergeUser($user$match);
                }

                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total'users');
    }

    protected function 
_getNextUserStep()
    {
        if (
$this->_session->getExtraData('userMerge'))
        {
            return 
'usersMerge';
        }

        if (
$this->_session->getExtraData('userFailed'))
        {
            return 
'usersFailed';
        }

        return 
true;
    }

    protected function 
_importOrMergeUser(array $user, array $options = array())
    {
        
$im $this->_importModel;

        if (
$user['email'] && $emailMatch $im->getUserIdByEmail($this->_convertToUtf8($user['email'])))
        {
            if (!empty(
$options['mergeEmail']))
            {
                return 
$this->_mergeUser($user$emailMatch);
            }
            else
            {
                if (
$im->getUserIdByUserName($this->_convertToUtf8($user['username'], true)))
                {
                    
$this->_session->setExtraData('userMerge'$user['userid'], 'both');
                }
                else
                {
                    
$this->_session->setExtraData('userMerge'$user['userid'], 'email');
                }
                return 
false;
            }
        }

        
$name utf8_substr($this->_convertToUtf8(trim($user['username']), true), 050);

        if (
$nameMatch $im->getUserIdByUserName($name))
        {
            if (!empty(
$options['mergeName']))
            {
                return 
$this->_mergeUser($user$nameMatch);
            }
            else
            {
                
$this->_session->setExtraData('userMerge'$user['userid'], 'name');
                return 
false;
            }
        }

        return 
$this->_importUser($user$options);
    }

    protected function 
_importUser(array $user, array $options)
    {
        if (
$this->_groupMap === null)
        {
            
$this->_groupMap $this->_importModel->getImportContentMap('userGroup');
        }

        if (
$this->_userFieldMap === null)
        {
            
$this->_userFieldMap $this->_importModel->getImportContentMap('userField');
        }

        
$user['options'] = intval($user['options']);

        
$import = array(
            
'username' => $this->_convertToUtf8($user['username'], true),
            
'email' => $this->_convertToUtf8($user['email']),
            
'user_group_id' => $this->_mapLookUp($this->_groupMap$user['usergroupid'], XenForo_Model_User::$defaultRegisteredGroupId),
            
'secondary_group_ids' => $this->_mapLookUpList($this->_groupMapexplode(','$user['membergroupids'])),
            
'authentication' => array(
                
'scheme_class' => 'XenForo_Authentication_vBulletin',
                
'data' => array(
                    
'hash' => $user['password'],
                    
'salt' => $user['salt']
                )
            ),
            
'homepage' => $this->_convertToUtf8($user['homepage']),
            
'last_activity' => $user['lastactivity'],
            
'register_date' => $user['joindate'],
            
'ip' => $user['ipaddress'],
            
'message_count' => $user['posts'],
            
'is_admin' => $user['is_admin'],
            
'is_banned' => $user['is_banned'],
            
'warning_points' => isset($user['ipoints']) ? $user['ipoints'] : 0,
            
'signature' => $this->_convertToUtf8($user['signature']),
            
'timezone' => $this->_importModel->resolveTimeZoneOffset($user['timezoneoffset'], $user['options'] & 64), // 64 = dstauto
            
'content_show_signature' => (($user['options'] & 1) ? 0), // 1 = showsignatures
            
'receive_admin_email' => (($user['options'] & 16) ? 0), // 16 = adminemail
        
);

        if (
$user['customtitle'])
        {
            
$import['custom_title'] = $this->_convertToUtf8($user['usertitle']);
            if (
$user['customtitle'] == 2// admin set
            
{
                
$import['custom_title'] = htmlspecialchars_decode($import['custom_title']);
                
$import['custom_title'] = preg_replace('#<brs*/?>#i'', '$import['custom_title']);
                
$import['custom_title'] = strip_tags($import['custom_title']);
            }
        }

        if (!(
$user['options'] & 2048)) // 2048 = receivepm
        
{
            
$import['allow_send_personal_conversation'] = 'none';
        }
        else if (
$user['options'] & 131072// 131072 = receivepmbuddies
        
{
            
$import['allow_send_personal_conversation'] = 'followed';
        }

        if (!(
$user['options'] & 8388608)) // 8388608 = vm_enable
        
{
            
$import['allow_post_profile'] = 'none';
        }
        else if (
$user['options'] & 16777216// 16777216 = vm_contactonly
        
{
            
$import['allow_post_profile'] = 'followed';
        }

        if (
$user['birthday'])
        {
            
$parts explode('-'$user['birthday']);
            if (
count($parts) == 3)
            {
                
$import['dob_day'] = $parts[1];
                
$import['dob_month'] = $parts[0];
                
$import['dob_year'] = ($parts[2] === '0000' $parts[2]);
            }
        }

        
// try to give users without an avatar that have actually posted a gravatar
        
if (!empty($options['gravatar']))
        {
            if (!
$user['has_custom_avatar'] && $user['email'] && $user['lastpost'] && XenForo_Model_Avatar::gravatarExists($user['email']))
            {
                
$import['gravatar'] = $import['email'];
            }
        }

        
$import['about'] = '';
        if (isset(
$user['field1']))
        {
            
$import['about'] .= $this->_convertToUtf8($user['field1'], true) . "nn";
        }
        if (isset(
$user['field3']))
        {
            
$import['about'] .= $this->_convertToUtf8($user['field3'], true) . "nn";
        }
        
$import['about'] = trim($import['about']);

        if (isset(
$user['field2']))
        {
            
$import['location'] = $this->_convertToUtf8($user['field2'], true);
        }
        if (isset(
$user['field4']))
        {
            
$import['occupation'] = $this->_convertToUtf8($user['field4'], true);
        }

        switch (
$user['usergroupid'])
        {
            case 
3$import['user_state'] = 'email_confirm'; break;
            case 
4$import['user_state'] = 'moderated'; break;
            default: 
$import['user_state'] = 'valid';
        }

        switch (
$user['autosubscribe'])
        {
            case -
1$import['default_watch_state'] = ''; break;
            case 
0$import['default_watch_state'] = 'watch_no_email'; break;
            default: 
$import['default_watch_state'] = 'watch_email';
        }

        switch (
$user['showbirthday'])
        {
            case 
0$import['show_dob_year'] = 0$import['show_dob_date'] = 0; break;
            case 
1$import['show_dob_year'] = 1$import['show_dob_date'] = 0; break;
            case 
2$import['show_dob_year'] = 1$import['show_dob_date'] = 1; break;
            case 
3$import['show_dob_year'] = 0$import['show_dob_date'] = 1; break;
        }

        
// custom user fields
        
$userFieldDefinitions $this->_importModel->getUserFieldDefinitions();

        foreach (array(
'icq''aim''yahoo''msn''skype') AS $identityType)
        {
            if (isset(
$userFieldDefinitions[$identityType]))
            {
                
$import[XenForo_Model_Import::USER_FIELD_KEY][$identityType] = $this->_convertToUtf8($user[$identityType]);
            }
        }

        
$userFieldLookups $this->_session->getExtraData('userFieldLookups');

        foreach (
$this->_userFieldMap AS $oldFieldId => $newFieldId)
        {
            if (!isset(
$userFieldDefinitions[$newFieldId]))
            {
                continue;
            }

            
$userFieldValue '';

            if (
$user["field$oldFieldId"] !== '')
            {
                if (isset(
$userFieldLookups[$oldFieldId]))
                {
                    
$fieldInfo $userFieldLookups[$oldFieldId];

                    
// use the lookup info to resolve the value
                    
if ($fieldInfo['multiple'])
                    {
                        
$userFieldValue = array();

                        foreach (
$fieldInfo['choices'] AS $bitValue => $stringValue)
                        {
                            if (
$user["field$oldFieldId"] & $bitValue)
                            {
                                
$userFieldValue[$stringValue] = $stringValue;
                            }
                        }
                    }
                    else
                    {
                        
$fieldChoiceId $this->_convertToUtf8($user["field$oldFieldId"]);

                        if (isset(
$fieldInfo['choices'][$fieldChoiceId]))
                        {
                            
$userFieldValue $fieldInfo['choices'][$fieldChoiceId];
                        }
                    }
                }
                else
                {
                    
// set the field value directly
                    
$userFieldValue $this->_convertToUtf8($user["field$oldFieldId"], true);
                }
            }

            
$import[XenForo_Model_Import::USER_FIELD_KEY][$newFieldId] = $userFieldValue;
        }

        if (
$user['is_admin'] && $user['admin_permissions'])
        {
            
$user['admin_permissions'] = intval($user['admin_permissions']);

            
$aPerms = array();
            if (
$user['admin_permissions'] & 4) { $aPerms[] = 'option'; }
            if (
$user['admin_permissions'] & 8) { $aPerms[] = 'style'; }
            if (
$user['admin_permissions'] & 16) { $aPerms[] = 'language'; }
            if (
$user['admin_permissions'] & 32) { $aPerms[] = 'node'; }
            if (
$user['admin_permissions'] & 256)
            {
                
$aPerms[] = 'user';
                
$aPerms[] = 'ban';
                
$aPerms[] = 'identityService';
                
$aPerms[] = 'trophy';
                
$aPerms[] = 'userUpgrade';
            }
            if (
$user['admin_permissions'] & 512) { $aPerms[] = 'userGroup'; } // actually, user permissions
            
if ($user['admin_permissions'] & 4096) { $aPerms[] = 'bbCodeSmilie'; }
            if (
$user['admin_permissions'] & 8192) { $aPerms[] = 'cron'; }
            if (
$user['admin_permissions'] & 16384)
            {
                
$aPerms[] = 'import';
                
$aPerms[] = 'upgradeXenForo';
            }
            if (
$user['admin_permissions'] & 65536) { $aPerms[] = 'addOn'; }

            
$import['admin_permissions'] = $aPerms;
        }

        
$importedUserId $this->_importModel->importUser($user['userid'], $import$failedKey);
        if (
$importedUserId)
        {
            if (
$user['is_banned'])
            {
                
$this->_importModel->importBan(array(
                    
'user_id' => $importedUserId,
                    
'ban_user_id' => $this->_importModel->mapUserId($user['ban_user_id'], 0),
                    
'ban_date' => $user['ban_date'],
                    
'end_date' => $user['ban_end_date'],
                    
'user_reason' => $this->_convertToUtf8($user['ban_reason'])
                ));
            }

            if (
$user['is_super_moderator'])
            {
                
$this->_session->setExtraData('superMods'$user['userid'], $importedUserId);
            }
        }
        else if (
$failedKey)
        {
            
$this->_session->setExtraData('userFailed'$user['userid'], $failedKey);
        }

        return 
$importedUserId;
    }

    protected function 
_getSelectUserSql($where)
    {
        return 
'
            SELECT user.*, userfield.*, usertextfield.*,
                IF(admin.userid IS NULL, 0, 1) AS is_admin,
                admin.adminpermissions AS admin_permissions,
                IF(userban.userid IS NULL, 0, 1) AS is_banned,
                userban.bandate AS ban_date,
                userban.liftdate AS ban_end_date,
                userban.reason AS ban_reason,
                userban.adminid AS ban_user_id,
                IF(usergroup.adminpermissions & 1, 1, 0) AS is_super_moderator,
                IF(customavatar.userid, 1, 0) AS has_custom_avatar
            FROM ' 
$this->_prefix 'user AS user
            STRAIGHT_JOIN ' 
$this->_prefix 'userfield AS userfield ON (user.userid = userfield.userid)
            STRAIGHT_JOIN ' 
$this->_prefix 'usertextfield AS usertextfield ON (user.userid = usertextfield.userid)
            LEFT JOIN ' 
$this->_prefix 'administrator AS admin ON (user.userid = admin.userid)
            LEFT JOIN ' 
$this->_prefix 'userban AS userban ON (user.userid = userban.userid)
            LEFT JOIN ' 
$this->_prefix 'usergroup AS usergroup ON (user.usergroupid = usergroup.usergroupid)
            LEFT JOIN ' 
$this->_prefix 'customavatar AS customavatar ON (user.userid = customavatar.userid)
            WHERE ' 
$where '
            ORDER BY user.userid
        '
;
    }

    protected function 
_mergeUser(array $user$targetUserId)
    {
        
$this->_db->query('
            UPDATE xf_user SET
                message_count = message_count + ?,
                register_date = IF(register_date > ?, ?, register_date)
            WHERE user_id = ?
        '
, array($user['posts'], $user['joindate'], $user['joindate'], $targetUserId));

        
$this->_importModel->logImportData('user'$user['userid'], $targetUserId);

        return 
$targetUserId;
    }

    public function 
stepPaidSubscriptions($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 200,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(subscriptionlogid)
                FROM ' 
$prefix 'subscriptionlog
            '
);

            
XenForo_Db::beginTransaction();

            
$userGroupMap $model->getImportContentMap('userGroup');

            
$subs $sDb->fetchAll('
                SELECT sub.*, title.text AS title, description.text AS description
                FROM ' 
$prefix 'subscription AS sub
                INNER JOIN ' 
$prefix 'phrase AS title ON (title.languageid = 0
                    AND title.varname = CONCAT('
sub', sub.subscriptionid, '_title'))
                INNER JOIN ' 
$prefix 'phrase AS description ON (description.languageid = 0
                    AND description.varname = CONCAT('
sub', sub.subscriptionid, '_desc'))
            '
);
            foreach (
$subs AS $sub)
            {
                
$import = array(
                    
'title' => $this->_convertToUtf8($sub['title']),
                    
'description' => $this->_convertToUtf8($sub['description']),
                    
'display_order' => $sub['displayorder'],
                    
'extra_group_ids' => '',
                    
'can_purchase' => 0// never be active as the admin probably needs to verify/setup their configs
                    
'recurring' => 0,
                    
'cost_amount' => 1,
                    
'cost_currency' => 'usd',
                    
'length_amount' => 1,
                    
'length_unit' => 'year'
                
);

                if (
$sub['membergroupids'])
                {
                    
$groupIds = array();
                    foreach (
explode(','$sub['membergroupids']) AS $groupId)
                    {
                        if (isset(
$userGroupMap[$groupId]))
                        {
                            
$groupIds[] = $userGroupMap[$groupId];
                        }
                    }
                    
$import['extra_group_ids'] = implode(','$groupIds);
                }

                
$def = @unserialize($sub['cost']);
                if (
is_array($def))
                {
                    if (isset(
$def[0]))
                    {
                        
$def $def[0];
                    }
                    if (!empty(
$def['cost']) && is_array($def['cost']))
                    {
                        foreach (
$def['cost'] AS $currency => $cost)
                        {
                            if (
floatval($cost) > 0)
                            {
                                
$import['cost_amount'] = floatval($cost);
                                
$import['cost_currency'] = $currency;
                                break;
                            }
                        }
                    }
                    if (!empty(
$def['units']))
                    {
                        
$import['length_amount'] = $def['length'];
                        switch (
$def['units'])
                        {
                            case 
'Y'$import['length_unit'] = 'year'; break;
                            case 
'M'$import['length_unit'] = 'month'; break;
                            case 
'D'$import['length_unit'] = 'day'; break;
                            default:
                                
$import['length_amount'] = 0;
                                
$import['length_unit'] = '';
                        }
                    }
                    else
                    {
                        
$import['length_amount'] = 0;
                        
$import['length_unit'] = '';
                    }
                    
$import['recurring'] = !empty($def['recurring']) ? 0;
                }

                
$model->importUserUpgradeDefinition($sub['subscriptionid'], $import);
            }

            
XenForo_Db::commit();
        }

        
$logs $sDb->fetchAll($sDb->limit(
            
'
                SELECT *
                FROM ' 
$prefix 'subscriptionlog
                WHERE subscriptionlogid > ' 
$sDb->quote($start) . '
                    AND status = 1
                ORDER BY subscriptionlogid
            '
$options['limit']
        ));
        if (!
$logs)
        {
            return 
true;
        }

        
$userIdMap $model->getUserIdsMapFromArray($logs'userid');
        
$upgradeMap $model->getImportContentMap('userUpgrade');
        
$upgrades $model->getModelFromCache('XenForo_Model_UserUpgrade')->getAllUserUpgrades();

        
$next 0;
        
$total 0;

        
XenForo_Db::beginTransaction();

        foreach (
$logs AS $log)
        {
            
$next $log['subscriptionlogid'];

            
$newUserId $this->_mapLookUp($userIdMap$log['userid']);
            if (!
$newUserId)
            {
                continue;
            }

            
$newUpgradeId $this->_mapLookUp($upgradeMap$log['subscriptionid']);
            if (!
$newUpgradeId)
            {
                continue;
            }

            
$import = array(
                
'user_id' => $newUserId,
                
'user_upgrade_id' => $newUpgradeId,
                
'extra' => 'a:0:{}',
                
'start_date' => $log['regdate'],
                
'end_date' => $log['expirydate']
            );
            
$extraGroupIds = isset($upgrades[$newUpgradeId]) ? $upgrades[$newUpgradeId]['extra_group_ids'] : '';

            if (
$model->importActiveUserUpgrade($import$extraGroupIds))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepAvatars($start, array $options)
    {
        
$options array_merge(array(
            
'path' => isset($this->_config['avatarPath']) ? $this->_config['avatarPath'] : '',
            
'limit' => 50,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(userid)
                FROM ' 
$prefix 'customavatar
            '
);
        }

        
$avatars $sDb->fetchAll($sDb->limit(
            
'
                SELECT customavatar.userid, user.avatarrevision
                FROM ' 
$prefix 'customavatar AS customavatar
                INNER JOIN ' 
$prefix 'user AS user ON (user.userid = customavatar.userid)
                WHERE customavatar.userid > ' 
$sDb->quote($start) . '
                ORDER BY customavatar.userid
            '
$options['limit']
        ));
        if (!
$avatars)
        {
            return 
true;
        }

        
$userIdMap $model->getUserIdsMapFromArray($avatars'userid');

        
$next 0;
        
$total 0;

        foreach (
$avatars AS $avatar)
        {
            
$next $avatar['userid'];

            
$newUserId $this->_mapLookUp($userIdMap$avatar['userid']);
            if (!
$newUserId)
            {
                continue;
            }

            if (!
$options['path'])
            {
                
$fData $sDb->fetchOne('
                    SELECT filedata
                    FROM ' 
$prefix 'customavatar
                    WHERE userid = ' 
$sDb->quote($avatar['userid'])
                );
                if (
$fData === '')
                {
                    continue;
                }

                
$avatarFile tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                if (!
$avatarFile || !@file_put_contents($avatarFile$fData))
                {
                    continue;
                }

                
$isTemp true;
            }
            else
            {
                
$avatarFileOrig "$options[path]/avatar$avatar[userid]_$avatar[avatarrevision].gif";
                if (!
file_exists($avatarFileOrig))
                {
                    continue;
                }

                
$avatarFile tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                
copy($avatarFileOrig$avatarFile);

                
$isTemp true;
            }

            if (
$this->_importModel->importAvatar($avatar['userid'], $newUserId$avatarFile))
            {
                
$total++;
            }

            if (
$isTemp)
            {
                @
unlink($avatarFile);
            }
        }

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepPrivateMessages($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 300,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(pmtextid)
                FROM ' 
$prefix 'pmtext
            '
);
        }

        
$pmTexts $sDb->fetchAll($sDb->limit(
            
'
                SELECT *
                FROM ' 
$prefix 'pmtext
                WHERE pmtextid > ' 
$sDb->quote($start) . '
                ORDER BY pmtextid
            '
$options['limit']
        ));
        if (!
$pmTexts)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;

        
XenForo_Db::beginTransaction();

        foreach (
$pmTexts AS $pmText)
        {
            
$next $pmText['pmtextid'];

            
$readState $sDb->fetchPairs('
                SELECT userid, IF(folderid >= 0, messageread, 1)
                FROM ' 
$prefix 'pm
                WHERE pmtextid = ' 
$sDb->quote($pmText['pmtextid'])
            );

            try
            {
                
$toUser = @unserialize($pmText['touserarray']);
            }
            catch (
Exception $e)
            {
                
// this is either corrupted data or an invalid char set. The latter isn't something we can automatically detect
                
continue;
            }

            if (!
is_array($toUser))
            {
                continue;
            }

            
$users = array(
                
$pmText['fromuserid'] => $pmText['fromusername']
            );
            foreach (
$toUser AS $key => $toUser)
            {
                if (
is_array($toUser))
                {
                    foreach (
$toUser AS $subKey => $username)
                    {
                        
$users[$subKey] = $username;
                    }
                }
                else
                {
                    
$users[$key] = $toUser;
                }
            }

            
$mapUserIds $model->getImportContentMap('user'array_keys($users));

            
$newFromUserId $this->_mapLookUp($mapUserIds$pmText['fromuserid']);
            if (!
$newFromUserId)
            {
                continue;
            }

            
$fromUserName $this->_convertToUtf8($pmText['fromusername'], true);

            
$recipients = array();
            foreach (
$users AS $userId => $username)
            {
                
$newUserId $this->_mapLookUp($mapUserIds$userId);
                if (!
$newUserId)
                {
                    continue;
                }

                if (isset(
$readState[$userId]))
                {
                    
$lastReadDate = ($readState[$userId] ? $pmText['dateline'] : 0);
                    
$deleted false;
                }
                else
                {
                    
$lastReadDate $pmText['dateline'];
                    
$deleted true;
                }

                
$recipients[$newUserId] = array(
                    
'username' => $this->_convertToUtf8($usernametrue),
                    
'last_read_date' => $lastReadDate,
                    
'recipient_state' => ($deleted 'deleted' 'active')
                );
            }

            
$conversation = array(
                
'title' => $this->_convertToUtf8($pmText['title'], true),
                
'user_id' => $newFromUserId,
                
'username' => $fromUserName,
                
'start_date' => $pmText['dateline'],
                
'open_invite' => 0,
                
'conversation_open' => 1
            
);

            
$messages = array(
                array(
                    
'message_date' => $pmText['dateline'],
                    
'user_id' => $newFromUserId,
                    
'username' => $fromUserName,
                    
'message' => $this->_convertToUtf8($pmText['message'])
                )
            );

            if (
$model->importConversation($pmText['pmtextid'], $conversation$recipients$messages))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepVisitorMessages($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 200,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(vmid)
                FROM ' 
$prefix 'visitormessage
            '
);
        }

        
$vms $sDb->fetchAll($sDb->limit(
            
'
                SELECT vm.*,
                        IF(user.username IS NULL, vm.postusername, user.username) AS username
                FROM ' 
$prefix 'visitormessage AS vm
                LEFT JOIN ' 
$prefix 'user AS user ON (vm.postuserid = user.userid)
                WHERE vm.vmid > ' 
$sDb->quote($start) . '
                ORDER BY vm.vmid
            '
$options['limit']
        ));
        if (!
$vms)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;

        
$userIds = array();
        foreach (
$vms AS $vm)
        {
            
$userIds[] = $vm['userid'];
            
$userIds[] = $vm['postuserid'];
        }
        
$userIdMap $model->getImportContentMap('user'$userIds);

        
XenForo_Db::beginTransaction();

        
$formatter XenForo_BbCode_Formatter_Base::create('XenForo_BbCode_Formatter_Text');
        
$parser XenForo_BbCode_Parser::create($formatter);

        foreach (
$vms AS $vm)
        {
            if (
trim($vm['postusername']) === '')
            {
                continue;
            }

            
$next $vm['vmid'];

            
$profileUserId $this->_mapLookUp($userIdMap$vm['userid']);
            if (!
$profileUserId)
            {
                continue;
            }

            
$postUserId $this->_mapLookUp($userIdMap$vm['postuserid'], 0);

            
$import = array(
                
'profile_user_id' => $profileUserId,
                
'user_id' => $postUserId,
                
'username' => $this->_convertToUtf8($vm['postusername'], true),
                
'post_date' => $vm['dateline'],
                
'message' => $parser->render($this->_convertToUtf8($vm['pagetext'])),
                
'ip' => XenForo_Helper_Ip::convertIpBinaryToString($vm['ipaddress'])
            );

            switch (
$vm['state'])
            {
                case 
'deleted'$import['message_state'] = 'deleted'; break;
                case 
'moderation'$import['message_state'] = 'moderated'; break;
                default: 
$import['message_state'] = 'visible';
            }

            if (
$model->importProfilePost($vm['vmid'], $import))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepForums($start, array $options)
    {
        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$start 0)
        {
            
// after importing everything, rebuild the full permission cache so forums appear
            
XenForo_Model::create('XenForo_Model_Node')->updateNestedSetInfo();
            
XenForo_Model::create('XenForo_Model_Permission')->rebuildPermissionCache();
            return 
true;
        }

        
$forums $sDb->fetchAll('
            SELECT *
            FROM ' 
$prefix 'forum
        '
);
        if (!
$forums)
        {
            return 
true;
        }

        
$forumTree = array();
        foreach (
$forums AS $forum)
        {
            
$forumTree[$forum['parentid']][$forum['forumid']] = $forum;
        }

        
$forumPermissions = array();
        
$forumPermissionSql $sDb->query('
            SELECT *
            FROM ' 
$prefix 'forumpermission
        '
);
        while (
$forumPermission $forumPermissionSql->fetch())
        {
            
$forumPermissions[$forumPermission['forumid']][$forumPermission['usergroupid']] = $forumPermission['forumpermissions'];
        }

        
XenForo_Db::beginTransaction();

        
$total $this->_importForumTree(-1$forumTree$forumPermissions);

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
1, array(), '');
    }

    protected function 
_importForumTree($parentId, array $forumTree, array $forumPermissions, array $forumIdMap = array())
    {
        if (!isset(
$forumTree[$parentId]))
        {
            return 
0;
        }

        
XenForo_Db::beginTransaction();

        
$total 0;

        foreach (
$forumTree[$parentId] AS $forum)
        {
            
$forum['options'] = intval($forum['options']);

            
$import = array(
                
'title' => $this->_convertToUtf8($forum['title'], true),
                
'description' => $this->_convertToUtf8($forum['description'], true),
                
'display_order' => $forum['displayorder'],
                
'parent_node_id' => $this->_mapLookUp($forumIdMap$forum['parentid'], 0),
                
'display_in_list' => (($forum['options'] & 1) && $forum['displayorder'] > 0// active
            
);

            if (
$forum['link'])
            {
                
$import['node_type_id'] = 'LinkForum';
                
$import['link_url'] = $forum['link'];

                
$nodeId $this->_importModel->importLinkForum($forum['forumid'], $import);
            }
            else if (
$forum['options'] & 4// cancontainthreads
            
{
                
$import['node_type_id'] = 'Forum';
                
$import['discussion_count'] = $forum['threadcount'];
                
$import['message_count'] = $forum['replycount'] + $forum['threadcount'];
                
$import['last_post_date'] = $forum['lastpost'];
                
$import['last_post_username'] = $this->_convertToUtf8($forum['lastposter'], true);
                
$import['last_thread_title'] = $this->_convertToUtf8($forum['lastthread'], true);

                
$nodeId $this->_importModel->importForum($forum['forumid'], $import);
            }
            else
            {
                
$import['node_type_id'] = 'Category';

                
$nodeId $this->_importModel->importCategory($forum['forumid'], $import);
            }

            if (
$nodeId)
            {
                if (!empty(
$forumPermissions[$forum['forumid']]))
                {
                    
$this->_importForumPermissions($nodeId$forumPermissions[$forum['forumid']]);
                }

                
$forumIdMap[$forum['forumid']] = $nodeId;

                
$total++;
                
$total += $this->_importForumTree($forum['forumid'], $forumTree$forumPermissions$forumIdMap);
            }
        }

        
XenForo_Db::commit();

        return 
$total;
    }

    protected function 
_importForumPermissions($nodeId, array $groupPerms)
    {
        if (
$this->_groupMap === null)
        {
            
$this->_groupMap $this->_importModel->getImportContentMap('userGroup');
        }

        
XenForo_Db::beginTransaction();

        foreach (
$groupPerms AS $oldGroupId => $perms)
        {
            if (
$oldGroupId == || $oldGroupId == 4)
            {
                continue; 
// skip these. they'll be treated as guests
            
}

            
$newGroupId $this->_mapLookUp($this->_groupMap$oldGroupId);
            if (!
$newGroupId)
            {
                continue;
            }

            
$newPerms $this->_calculateForumPermissions($perms);
            if (
$newPerms)
            {
                
$this->_importModel->insertNodePermissionEntries($nodeId$newGroupId0$newPerms);
            }
        }

        
XenForo_Db::commit();
    }

    protected 
$_nodePermissionsGrouped null;

    protected function 
_calculateForumPermissions($perms)
    {
        
$output = array();

        if (
$this->_nodePermissionsGrouped === null)
        {
            
$this->_nodePermissionsGrouped $this->_importModel->getNodePermissionsGrouped();
        }

        
$perms intval($perms);

        if (
$perms 1)
        {
            
// viewable
            
$output['general']['viewNode'] = 'content_allow';

            
$output['forum']['viewContent'] = ($perms 524288 'content_allow' 'reset');
            
$output['forum']['viewOthers'] = ($perms 'content_allow' 'reset');
            
$output['forum']['postThread'] = ($perms 16 'content_allow' 'reset');
            
$output['forum']['postReply'] = ($perms 32 'content_allow' 'reset');
            
$output['forum']['editOwnPost'] = ($perms 128 'content_allow' 'reset');
            
$output['forum']['deleteOwnPost'] = ($perms 256 'content_allow' 'reset');
            
$output['forum']['deleteOwnThread'] = ($perms 512 'content_allow' 'reset');
            
$output['forum']['viewAttachment'] = ($perms 4096 'content_allow' 'reset');
            
$output['forum']['uploadAttachment'] = ($perms 8192 'content_allow' 'reset');
            
$output['forum']['votePoll'] = ($perms 32768 'content_allow' 'reset');
        }
        else
        {
            
// not viewable, reset all permissions
            
$output['general']['viewNode'] = 'reset';

            foreach (
$this->_nodePermissionsGrouped AS $groupId => $permissions)
            {
                foreach (
$permissions AS $permissionId => $perm)
                {
                    if (
$perm['permission_type'] == 'flag')
                    {
                        
$output[$groupId][$permissionId] = 'reset';
                    }
                }
            }
        }

        return 
$output;
    }

    public function 
stepModerators($start, array $options)
    {
        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        
$moderators $sDb->fetchAll('
            SELECT moderator.*,
                IF(usergroup.adminpermissions & 1, 1, 0) AS is_super_moderator
            FROM ' 
$prefix 'moderator AS moderator
            INNER JOIN ' 
$prefix 'user AS user ON (moderator.userid = user.userid)
            LEFT JOIN ' 
$this->_prefix 'usergroup AS usergroup ON (user.usergroupid = usergroup.usergroupid)
        '
);
        if (!
$moderators)
        {
            return 
true;
        }

        
$modGrouped = array();
        foreach (
$moderators AS $moderator)
        {
            if (!
array_key_exists('permissions2'$moderator))
            {
                
$moderator['permissions2'] = 0;
            }

            
$modGrouped[$moderator['userid']][$moderator['forumid']] = $moderator;
        }

        
$superMods $this->_session->getExtraData('superMods');
        if (
$superMods)
        {
            foreach (
$superMods AS $oldUserId => $newUserId)
            {
                if (!isset(
$modGrouped[$oldUserId]))
                {
                    
// no record in mod table, but imported as super mod - has everything
                    
$modGrouped[$oldUserId][-1] = array(
                        
'userid' => $oldUserId,
                        
'is_super_moderator' => true,
                        
'forumid' => -1,
                        
'permissions' => -1// bitwise, all 1s
                        
'permissions2' => -// bitwise, all 1s
                    
);
                }
            }
        }

        
$nodeMap $model->getImportContentMap('node');
        
$userIdMap $model->getImportContentMap('user'array_keys($modGrouped));

        
$total 0;

        
XenForo_Db::beginTransaction();

        foreach (
$modGrouped AS $userId => $forums)
        {
            
$newUserId $this->_mapLookUp($userIdMap$userId);
            if (!
$newUserId)
            {
                continue;
            }

            
$globalModPermissions = array();
            
$inserted false;

            if (!empty(
$forums[-1]['is_super_moderator']))
            {
                
$perms $this->_calculateModeratorPermissions($forums[-1]['permissions'], $forums[-1]['permissions2']);
                
$globalModPermissions += $perms['global'] + $perms['forum'];

                
$isSuperMod true;

                
$total++;
                
$inserted true;
            }
            else
            {
                
$isSuperMod false;
            }

            unset(
$forums[-1]);

            foreach (
$forums AS $forumId => $moderator)
            {
                
$newNodeId $this->_mapLookUp($nodeMap$forumId);
                if (!
$newNodeId)
                {
                    continue;
                }

                
$perms $this->_calculateModeratorPermissions($moderator['permissions'], $moderator['permissions2']);
                
$globalModPermissions += $perms['global'];

                
$mod = array(
                    
'content_id' => $newNodeId,
                    
'user_id' => $newUserId,
                    
'moderator_permissions' => $perms['forum']
                );
                
$model->importNodeModerator($forumId$userId$mod);

                
$total++;
                
$inserted true;
            }

            if (
$inserted)
            {
                
$mod = array(
                    
'user_id' => $newUserId,
                    
'is_super_moderator' => $isSuperMod,
                    
'moderator_permissions' => $globalModPermissions
                
);
                
$model->importGlobalModerator($userId$mod);
            }
        }

        
$this->_session->incrementStepImportTotal($total);

        
XenForo_Db::commit();

        return 
true;
    }

    protected function 
_calculateModeratorPermissions($perms1$perms2)
    {
        
$global = array();
        
$forum = array();

        
$perms1 intval($perms1);
        
$perms2 intval($perms2);

        if (
$perms2 1)
        {
            
$global['profilePost']['editAny'] = true;
        }
        if (
$perms2 2)
        {
            
$global['profilePost']['deleteAny'] = true;
            
$global['profilePost']['undelete'] = true;

            if (
$perms2 4)
            {
                
$global['profilePost']['hardDeleteAny'] = true;
            }
        }
        if (
$perms2 8)
        {
            
$global['profilePost']['approveUnapprove'] = true;
            
$global['profilePost']['viewDeleted'] = true;
            
$global['profilePost']['viewModerated'] = true;
        }

        if (
$perms1 1)
        {
            
$forum['forum']['editAnyPost'] = true;
        }
        if (
$perms1 2)
        {
            
$forum['forum']['deleteAnyPost'] = true;
            
$forum['forum']['deleteAnyThread'] = true;
            
$forum['forum']['undelete'] = true;

            if (
$perms1 131072)
            {
                
$forum['forum']['hardDeleteAnyPost'] = true;
                
$forum['forum']['hardDeleteAnyThread'] = true;
            }

            
// these don't really fit. give them to mods that can delete stuff
            
$forum['general']['viewIps'] = true;
            
$forum['general']['cleanSpam'] = true;
            
$forum['general']['bypassUserPrivacy'] = true;
        }
        if (
$perms1 4)
        {
            
$forum['forum']['lockUnlockThread'] = true;
        }
        if (
$perms1 16)
        {
            
$forum['forum']['manageAnyThread'] = true;
            
$forum['forum']['stickUnstickThread'] = true;
        }
        if (
$perms1 64)
        {
            
$forum['forum']['approveUnapprove'] = true;
            
$forum['forum']['viewModerated'] = true;
        }

        
$forum['forum']['viewDeleted'] = true// this was given automatically to mods

        
return array(
            
'global' => $global,
            
'forum' => $forum
        
);
    }

    public function 
stepThreadPrefixes($start, array $options)
    {
        
$options array_merge(array(), $options);

        
$sDb $this->_sourceDb;
        
$tablePrefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        
$nodeMap $model->getImportContentMap('node');
        
$userGroupMap $model->getImportContentMap('userGroup');

        
$prefixSets $sDb->fetchAll("
            SELECT prefixset.*, phrase.text AS title
            FROM 
{$tablePrefix}prefixset AS prefixset
            LEFT JOIN 
{$tablePrefix}phrase AS phrase ON
                (phrase.languageid = 0 AND phrase.varname = CONCAT('prefixset_', prefixset.prefixsetid, '_title'))
            ORDER BY prefixset.displayorder
        "
);

        
$prefixUserGroups = array();
        try 
// vB 3.7 has no prefix permissions, so catch the error that will occur when we try to query them
        
{
            foreach (
$sDb->fetchAll('SELECT * FROM ' $tablePrefix 'prefixpermission') AS $pug)
            {
                
$prefixUserGroups[$pug['prefixid']][$pug['usergroupid']] = true;
            }
        }
        catch (
Exception $e) {}

        
$prefixSetForums = array();
        foreach (
$sDb->fetchAll('SELECT * FROM ' $tablePrefix 'forumprefixset') AS $psf)
        {
            
$prefixSetForums[$psf['prefixsetid']][$psf['forumid']] = $psf['forumid'];
        }

        
$prefixes $sDb->fetchAll("
            SELECT prefix.*, phrase.text AS title
            FROM 
{$tablePrefix}prefix AS prefix
            INNER JOIN 
{$tablePrefix}prefixset AS prefixset ON
                (prefixset.prefixsetid = prefix.prefixsetid)
            LEFT JOIN 
{$tablePrefix}phrase AS phrase ON
                (phrase.languageid = 0 AND phrase.varname = CONCAT('prefix_', prefix.prefixid, '_title_plain'))
            ORDER BY prefixset.displayorder, prefix.displayorder
        "
);

        
// get the list of nodes to which each prefix set applies
        
$prefixNodes = array();
        foreach (
$prefixes AS $prefix)
        {
            
$prefixSetId $prefix['prefixsetid'];

            if (empty(
$prefixNodes[$prefixSetId]))
            {
                
$prefixNodes[$prefixSetId] = array();

                if (isset(
$prefixSetForums[$prefixSetId]))
                {
                    foreach (
$prefixSetForums[$prefixSetId] AS $prefixSetForumId)
                    {
                        
$nodeId $this->_mapLookUp($nodeMap$prefixSetForumId);
                        if (
$nodeId)
                        {
                            
$prefixNodes[$prefixSetId][] = $nodeId;
                        }
                    }
                }
            }
        }

        
$total 0;

        
XenForo_Db::beginTransaction($this->_db);

        
$prefixGroupMap = array();
        foreach (
$prefixSets AS $prefixSet)
        {
            
$prefixSetId strtolower($prefixSet['prefixsetid']);

            
$import = array(
                
'display_order' => $prefixSet['displayorder'],
                
XenForo_Model_Import::EXTRA_DATA_KEY => array(
                    
XenForo_DataWriter_ThreadPrefixGroup::DATA_TITLE => $this->_convertToUtf8($prefixSet['title'])
                )
            );

            
$prefixGroupMap[$prefixSetId] = $model->importThreadPrefixGroup($prefixSetId$import);
        }

        foreach (
$prefixes AS $order => $prefix)
        {
            
$prefixId $prefix['prefixid'];
            
$prefixSetId $prefix['prefixsetid'];

            if (empty(
$prefixUserGroups[$prefixId]))
            {
                
$allowedUserGroupIds '-1';
            }
            else
            {
                
$allowedUserGroupIds = array();

                foreach (
$userGroupMap AS $oldUgId => $newUgId)
                {
                    if (!isset(
$prefixUserGroups[$prefixId][$oldUgId]))
                    {
                        
$allowedUserGroupIds[] = $newUgId;
                    }
                }

                
$allowedUserGroupIds implode(','$allowedUserGroupIds);
            }

            
$import = array(
                
'display_order' => $order 10,
                
'css_class' => 'prefix prefixPrimary',
                
'allowed_user_group_ids' => $allowedUserGroupIds,
                
'prefix_group_id' => $this->_mapLookUp($prefixGroupMap$prefixSetId0),
            );

            
$model->importThreadPrefix(strtolower($prefixId), $import,
                
$this->_convertToUtf8($prefix['title']),
                
$prefixNodes[$prefixSetId]);

            
$total++;
        }

        
// build the prefix caches
        
$prefixModel XenForo_Model::create('XenForo_Model_ThreadPrefix');
        
$prefixModel->rebuildPrefixMaterializedOrder();
        
$prefixModel->rebuildPrefixCache();

        
XenForo_Db::commit($this->_db);

        
$this->_session->incrementStepImportTotal($total);

        return 
true;
    }

    public function 
stepThreads($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 100,
            
'postDateStart' => 0,
            
'postLimit' => 800,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(threadid)
                FROM ' 
$prefix 'thread
            '
);
        }

        
// pull threads from things we actually imported as forums
        
$threads $sDb->fetchAll($sDb->limit(
            
'
                SELECT thread.*,
                    IF(user.username IS NULL, thread.postusername, user.username) AS postusername
                FROM ' 
$prefix 'thread AS thread FORCE INDEX (PRIMARY)
                LEFT JOIN ' 
$prefix 'user AS user ON (thread.postuserid = user.userid)
                INNER JOIN ' 
$prefix 'forum AS forum ON
                    (thread.forumid = forum.forumid AND forum.link = '' AND forum.options & 4)
                WHERE thread.threadid >= ' 
$sDb->quote($start) . '
                    AND thread.open <> 10
                ORDER BY thread.threadid
            '
$options['limit']
        ));
        if (!
$threads)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;
        
$totalPosts 0;

        
$nodeMap $model->getImportContentMap('node');
        
$threadPrefixMap $model->getImportContentMap('threadPrefix');

        
XenForo_Db::beginTransaction();

        foreach (
$threads AS $thread)
        {
            if (
trim($thread['title']) === '')
            {
                continue;
            }

            
$postDateStart $options['postDateStart'];

            
$next $thread['threadid'] + 1// uses >=, will be moved back down if need to continue
            
$options['postDateStart'] = 0;

            
$maxPosts $options['postLimit'] - $totalPosts;
            
$posts $sDb->fetchAll($sDb->limit(
                
'
                    SELECT post.*,
                        IF(user.username IS NULL, post.username, user.username) AS username,
                        editlog.dateline AS editdate, editlog.userid AS edituserid
                    FROM ' 
$prefix 'post AS post
                    LEFT JOIN ' 
$prefix 'user AS user ON (post.userid = user.userid)
                    LEFT JOIN ' 
$prefix 'editlog AS editlog ON (post.postid = editlog.postid)
                    WHERE post.threadid = ' 
$sDb->quote($thread['threadid']) . '
                        AND post.dateline > ' 
$sDb->quote($postDateStart) . '
                    ORDER BY post.dateline
                '
$maxPosts
            
));
            if (!
$posts)
            {
                if (
$postDateStart)
                {
                    
// continuing thread but it has no more posts
                    
$total++;
                }
                continue;
            }

            if (
$postDateStart)
            {
                
// continuing thread we already imported
                
$threadId $model->mapThreadId($thread['threadid']);

                
$position $this->_db->fetchOne('
                    SELECT MAX(position)
                    FROM xf_post
                    WHERE thread_id = ?
                '
$threadId);
            }
            else
            {
                
$forumId $this->_mapLookUp($nodeMap$thread['forumid']);
                if (!
$forumId)
                {
                    continue;
                }

                if (
trim($thread['postusername']) === '')
                {
                    
$thread['postusername'] = 'Guest';
                }

                
$import = array(
                    
'title' => $this->_convertToUtf8($thread['title'], true),
                    
'node_id' => $forumId,
                    
'user_id' => $model->mapUserId($thread['postuserid'], 0),
                    
'username' => $this->_convertToUtf8($thread['postusername'], true),
                    
'discussion_open' => $thread['open'],
                    
'post_date' => $thread['dateline'],
                    
'reply_count' => $thread['replycount'],
                    
'view_count' => $thread['views'],
                    
'sticky' => $thread['sticky'],
                    
'last_post_date' => $thread['lastpost'],
                    
'last_post_username' => $this->_convertToUtf8($thread['lastposter'], true),
                );
                if (isset(
$thread['prefixid']))
                {
                    
$import['prefix_id'] = $this->_mapLookUp($threadPrefixMap$thread['prefixid'], 0);
                }
                switch (
$thread['visible'])
                {
                    case 
0$import['discussion_state'] = 'moderated'; break;
                    case 
2$import['discussion_state'] = 'deleted'; break;
                    default: 
$import['discussion_state'] = 'visible'; break;
                }

                
$threadId $model->importThread($thread['threadid'], $import);
                if (!
$threadId)
                {
                    continue;
                }

                
$position = -1;

                
$subs $sDb->fetchPairs('
                    SELECT userid, emailupdate
                    FROM ' 
$prefix 'subscribethread
                    WHERE threadid = ' 
$sDb->quote($thread['threadid'])
                );
                if (
$subs)
                {
                    
$userIdMap $model->getImportContentMap('user'array_keys($subs));
                    foreach (
$subs AS $userId => $emailUpdate)
                    {
                        
$newUserId $this->_mapLookUp($userIdMap$userId);
                        if (!
$newUserId)
                        {
                            continue;
                        }

                        
$model->importThreadWatch($newUserId$threadId, ($emailUpdate 0));
                    }
                }
            }

            if (
$threadId)
            {
                
$quotedPostIds = array();

                
$threadTitleRegex '#^(re:s*)?' preg_quote($thread['title'], '#') . '$#i';

                
$userIdMap $model->getUserIdsMapFromArray($posts'userid');

                foreach (
$posts AS $i => $post)
                {
                    if (
$post['title'] !== '' && !preg_match($threadTitleRegex$post['title']))
                    {
                        
$post['pagetext'] = '[b]' htmlspecialchars_decode($post['title']) . "[/b]nn" ltrim($post['pagetext']);
                    }

                    if (
trim($post['username']) === '')
                    {
                        
$post['username'] = 'Guest';
                    }

                    
$post['pagetext'] = $this->_convertToUtf8($post['pagetext']);

                    
$import = array(
                        
'thread_id' => $threadId,
                        
'user_id' => $this->_mapLookUp($userIdMap$post['userid'], 0),
                        
'username' => $this->_convertToUtf8($post['username'], true),
                        
'post_date' => $post['dateline'],
                        
'message' => $post['pagetext'],
                        
'attach_count' => 0,
                        
'ip' => $post['ipaddress'],
                        
'last_edit_date' => !empty($post['editdate']) ? $post['editdate'] : 0,
                        
'last_edit_user_id' => !empty($post['editdate']) ? $post['edituserid'] : 0,
                        
'edit_count' => !empty($post['editdate']) ? 0
                    
);
                    switch (
$post['visible'])
                    {
                        case 
0$import['message_state'] = 'moderated'$import['position'] = $position; break;
                        case 
2$import['message_state'] = 'deleted'$import['position'] = $position; break;
                        default: 
$import['message_state'] = 'visible'$import['position'] = ++$position; break;
                    }

                    
$post['xf_post_id'] = $model->importPost($post['postid'], $import);

                    
$options['postDateStart'] = $post['dateline'];
                    
$totalPosts++;

                    if (
stripos($post['pagetext'], '[quote=') !== false)
                    {
                        if (
preg_match_all('/[quote=("|'|)(?P<username>[^;n]]*);s*(?P<postid>d+)s*1]/siU', $post['pagetext'], $quotes, PREG_SET_ORDER))
                        {
                            $post['
quotes'] = array();

                            foreach ($quotes AS $quote)
                            {
                                $quotedPostId = intval($quote['
postid']);

                                $quotedPostIds[] = $quotedPostId;

                                $post['
quotes'][$quote[0]] = array($quote['username'], $quotedPostId);
                            }
                        }
                    }

                    $posts[$i] = $post;
                }

                $postIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('
post', $quotedPostIds));

                $db = XenForo_Application::getDb();

                foreach ($posts AS $post)
                {
                    if (!empty($post['
quotes']))
                    {
                        $postQuotesRewrite = $this->_rewriteQuotes($post['
pagetext'], $post['quotes'], $postIdMap);

                        if ($post['
pagetext'] != $postQuotesRewrite)
                        {
                            $db->update('
xf_post', array('message' => $postQuotesRewrite), 'post_id ' . $db->quote($post['xf_post_id']));
                        }
                    }
                }
            }

            if (count($posts) < $maxPosts)
            {
                // done this thread
                $total++;
                $options['
postDateStart'] = 0;
            }
            else
            {
                // not necessarily done the thread; need to pick it up next page
                break;
            }
        }

        if ($options['
postDateStart'])
        {
            // not done this thread, need to continue with it
            $next--;
        }

        XenForo_Db::commit();

        $this->_session->incrementStepImportTotal($total);

        return array($next, $options, $this->_getProgressOutput($next - 1, $options['
max']));
    }

    protected function _rewriteQuotes($message, array $quotes, array $postIdMap)
    {
        foreach ($quotes AS $quote => &$replace)
        {
            list($username, $postId) = $replace;

            $replace = sprintf('
[quote="%s, post: %d"]', $username, $this->_mapLookUp($postIdMap, $postId));
        }

        return str_replace(array_keys($quotes), $quotes, $message);
    }

    public function stepPostEditHistory($start, array $options)
    {
        $options = array_merge(array(
            '
limit' => 100,
            '
max' => false
        ), $options);

        $sDb = $this->_sourceDb;
        $prefix = $this->_prefix;

        /* @var $model XenForo_Model_Import */
        $model = $this->_importModel;

        if ($options['
max'] === false)
        {
            $options['
max'] = $sDb->fetchOne('
                
SELECT MAX(postid)
                
FROM ' . $prefix . 'postedithistory
            
');
        }

        // fetch the next 100 posts
        $postIds = $sDb->fetchCol($sDb->limit(
            '
                
SELECT DISTINCT postid
                FROM 
' . $prefix . 'postedithistory
                WHERE postid 
' . $sDb->quote($start) . '
                
ORDER BY postid
            
', $options['limit']
        ));
        if (!$postIds)
        {
            return true;
        }

        $edits = $sDb->fetchAll(
            '
                
SELECT *
                
FROM ' . $prefix . 'postedithistory
                WHERE postid IN 
(' . $sDb->quote($postIds) . ')
                
ORDER BY postedithistoryid
            
'
        );
        if (!$edits)
        {
            return true;
        }

        $next = 0;
        $total = 0;

        $postIdMap = $model->getPostIdsMapFromArray($edits, '
postid');
        $userIdMap = $model->getUserIdsMapFromArray($edits, '
userid');

        // assemble an array
        $orderedEdits = array();
        foreach ($edits AS $edit)
        {
            $orderedEdits[$edit['
postid']][$edit['postedithistoryid']] = $edit;
        }
        unset($edits);

        XenForo_Db::beginTransaction();

        foreach ($orderedEdits AS $postId => $edits)
        {
            $pageText = false;
            $next = max($next, $postId);

            foreach ($edits AS $edit)
            {
                if ($pageText)
                {
                    $newPostId = $this->_mapLookUp($postIdMap, $edit['
postid']);
                    if (!$newPostId)
                    {
                        continue;
                    }

                    if ($pageText !== false)
                    {
                        $import = array(
                            '
content_type' => 'post',
                            '
content_id' => $newPostId,
                            '
edit_user_id' => $this->_mapLookUp($userIdMap, $edit['userid'], 0),
                            '
edit_date' => $edit['dateline'],
                            '
old_text' => $this->_convertToUtf8($pageText),
                        );

                        $model->importEditHistory($edit['
postedithistoryid'], $import);

                        $total++;
                    }
                }

                $pageText = $edit['
pagetext'];
            }
        }

        XenForo_Db::commit();

        $this->_session->incrementStepImportTotal($total);

        return array($next, $options, $this->_getProgressOutput($next, $options['
max']));
    }

    public function stepPolls($start, array $options)
    {
        $options = array_merge(array(
            '
limit' => 100,
            '
max' => false
        ), $options);

        $sDb = $this->_sourceDb;
        $prefix = $this->_prefix;

        /* @var $model XenForo_Model_Import */
        $model = $this->_importModel;

        if ($options['
max'] === false)
        {
            $options['
max'] = $sDb->fetchOne('
                
SELECT MAX(pollid)
                
FROM ' . $prefix . 'poll
            
');
        }

        $polls = $sDb->fetchAll($sDb->limit(
            '
                
SELECT poll.*, thread.threadid
                FROM 
' . $prefix . 'poll AS poll
                INNER JOIN 
' . $prefix . 'thread AS thread ON (thread.pollid poll.pollid AND thread.open <> 10)
                
WHERE poll.pollid ' . $sDb->quote($start) . '
                
ORDER BY poll.pollid
            
', $options['limit']
        ));
        if (!$polls)
        {
            return true;
        }

        $next = 0;
        $total = 0;

        $threadIdMap = $model->getThreadIdsMapFromArray($polls, '
threadid');
        $donePolls = array();

        XenForo_Db::beginTransaction();

        foreach ($polls AS $poll)
        {
            $next = $poll['
pollid'];

            $newThreadId = $this->_mapLookUp($threadIdMap, $poll['
threadid']);
            if (!$newThreadId)
            {
                continue;
            }

            if (isset($donePolls[$poll['
pollid']]))
            {
                // some times the pollid in the thread table isn'
t unique so it can try to import dupes
                
continue;
            }

            
$import = array(
                
'question' => $this->_convertToUtf8($poll['question'], true),
                
'public_votes' => $poll['public'],
                
'multiple' => $poll['multiple'],
                
'close_date' => ($poll['timeout'] ? $poll['dateline'] + 86400 $poll['timeout'] : 0)
            );
            
$responses explode('|||'$this->_convertToUtf8($poll['options'], true));

            
$newPollId $model->importThreadPoll($poll['pollid'], $newThreadId$import$responses$responseIds);
            if (
$newPollId)
            {
                
$donePolls[$poll['pollid']] = $newPollId;

                
$votes $sDb->fetchAll('
                    SELECT userid, votedate, voteoption
                    FROM ' 
$prefix 'pollvote
                    WHERE pollid = ' 
$sDb->quote($poll['pollid'])
                );

                
$userIdMap $model->getUserIdsMapFromArray($votes'userid');
                foreach (
$votes AS $vote)
                {
                    
$userId $this->_mapLookUp($userIdMap$vote['userid']);
                    if (!
$userId)
                    {
                        continue;
                    }

                    
$voteOption max(0$vote['voteoption'] - 1);

                    if (!isset(
$responseIds[$voteOption]))
                    {
                        continue;
                    }

                    
$model->importPollVote($newPollId$userId$responseIds[$voteOption], $vote['votedate']);
                }
            }

            
$total++;
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepAttachments($start, array $options)
    {
        
$options array_merge(array(
            
'path' => isset($this->_config['attachmentPath']) ? $this->_config['attachmentPath'] : '',
            
'limit' => 50,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(attachmentid)
                FROM ' 
$prefix 'attachment
            '
);
        }

        
$attachments $sDb->fetchAll($sDb->limit(
            
'
                SELECT attachmentid, userid, dateline, filename, counter, postid
                FROM ' 
$prefix 'attachment
                WHERE attachmentid > ' 
$sDb->quote($start) . '
                    AND visible = 1
                ORDER BY attachmentid
            '
$options['limit']
        ));
        if (!
$attachments)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;

        
$userIdMap $model->getUserIdsMapFromArray($attachments'userid');

        
$postIdMap $model->getPostIdsMapFromArray($attachments'postid');
        
$posts $model->getModelFromCache('XenForo_Model_Post')->getPostsByIds($postIdMap);

        foreach (
$attachments AS $attachment)
        {
            
$next $attachment['attachmentid'];

            
$newPostId $this->_mapLookUp($postIdMap$attachment['postid']);
            if (!
$newPostId)
            {
                continue;
            }

            if (!
$options['path'])
            {
                
$fData $sDb->fetchOne('
                    SELECT filedata
                    FROM ' 
$prefix 'attachment
                    WHERE attachmentid = ' 
$sDb->quote($attachment['attachmentid'])
                );
                if (
$fData === '')
                {
                    continue;
                }

                
$attachFile tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                if (!
$attachFile || !@file_put_contents($attachFile$fData))
                {
                    continue;
                }

                
$isTemp true;
            }
            else
            {
                
$attachFileOrig "$options[path]/" implode('/'str_split($attachment['userid'])) . "/$attachment[attachmentid].attach";
                if (!
file_exists($attachFileOrig))
                {
                    continue;
                }

                
$attachFile tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                
copy($attachFileOrig$attachFile);

                
$isTemp true;
            }

            
$success $model->importPostAttachment(
                
$attachment['attachmentid'],
                
$this->_convertToUtf8($attachment['filename']),
                
$attachFile,
                
$this->_mapLookUp($userIdMap$attachment['userid'], 0),
                
$newPostId,
                
$attachment['dateline'],
                array(
'view_count' => $attachment['counter']),
                array(
$this'processAttachmentTags'),
                
$posts[$newPostId]['message']
            );
            if (
$success)
            {
                
$total++;
            }

            if (
$isTemp)
            {
                @
unlink($attachFile);
            }
        }

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public static function 
processAttachmentTags($oldAttachmentId$newAttachmentId$messageText)
    {
        if (
stripos($messageText'[ATTACH') !== false)
        {
            
/**
             * Note: We use '$newAttachmentId.vB' as the attachment id in the XenForo replacement
             * to avoid it being replaced again when we come across an attachment whose source id
             * is the same as this one's imported id.
             *
             * @var string
             */
            
$newTag sprintf('[ATTACH]%d.vB[/ATTACH]'$newAttachmentId);

            
$messageText preg_replace("#[ATTACH[^]]*]{$oldAttachmentId}[/ATTACH]#siU"$newTag$messageText);
        }

        return 
$messageText;
    }

    public function 
configStepReputation(array $options)
    {
        if (
$options)
        {
            return 
false;
        }

        return 
$this->_controller->responseView('XenForo_ViewAdmin_Import_vBulletin_ConfigReputation''import_config_likes');
    }

    public function 
stepReputation($start, array $options)
    {
        
$options array_merge(array(
            
'fetchLikeUsers' => false,
            
'limit' => 100,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(reputationid)
                FROM ' 
$prefix 'reputation
                WHERE reputation > 0
            '
);
        }

        
$reputations $sDb->fetchAll($sDb->limit(
            
'
                SELECT *
                FROM ' 
$prefix 'reputation
                WHERE reputationid > ' 
$sDb->quote($start) . '
                    AND reputation > 0
                ORDER BY reputationid
            '
$options['limit']
        ));
        if (!
$reputations)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;

        
$userIds = array();
        foreach (
$reputations AS $rep)
        {
            
$userIds[] = $rep['userid'];
            
$userIds[] = $rep['whoadded'];
        }

        
$postIdMap $model->getPostIdsMapFromArray($reputations'postid');
        
$userIdMap $model->getImportContentMap('user'$userIds);

        
XenForo_Db::beginTransaction();

        foreach (
$reputations AS $rep)
        {
            
$next $rep['reputationid'];

            
$newPostId $this->_mapLookUp($postIdMap$rep['postid']);
            if (!
$newPostId)
            {
                continue;
            }

            
$model->importLike(
                
'post',
                
$newPostId,
                
$this->_mapLookUp($userIdMap$rep['userid']),
                
$this->_mapLookUp($userIdMap$rep['whoadded']),
                
$rep['dateline'],
                
$options['fetchLikeUsers']
            );

            
$total++;
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }

    public function 
stepInfractions($start, array $options)
    {
        
$options array_merge(array(
            
'limit' => 100,
            
'max' => false
        
), $options);

        
$sDb $this->_sourceDb;
        
$prefix $this->_prefix;

        
/* @var $model XenForo_Model_Import */
        
$model $this->_importModel;

        if (
$options['max'] === false)
        {
            
$options['max'] = $sDb->fetchOne('
                SELECT MAX(infractionid)
                FROM ' 
$prefix 'infraction
                WHERE infractionid > 0
            '
);
        }

        
$infractions $sDb->fetchAll($sDb->limit(
            
'
                SELECT infraction.*,
                    user.username AS username,
                    COALESCE(thread.title, '') AS thread_title,
                    COALESCE(phrase.text, '') AS title
                FROM ' 
$prefix 'infraction AS infraction
                INNER JOIN ' 
$prefix 'user AS user ON (user.userid = infraction.userid)
                LEFT JOIN ' 
$prefix 'post AS post ON (infraction.postid = post.postid)
                LEFT JOIN ' 
$prefix 'thread AS thread ON (post.threadid = thread.threadid)
                LEFT JOIN ' 
$prefix 'phrase AS phrase ON (phrase.varname = CONCAT('infractionlevel', infraction.infractionlevelid, '_title') AND phrase.languageid = 0)
                WHERE infractionid > ' 
$sDb->quote($start) . '
                ORDER BY infractionid
            '
$options['limit']
        ));
        if (!
$infractions)
        {
            return 
true;
        }

        
$next 0;
        
$total 0;

        
$userIds = array();
        foreach (
$infractions AS $infraction)
        {
            
$userIds[] = $infraction['userid'];
            
$userIds[] = $infraction['whoadded'];
        }

        
$postIdMap $model->getPostIdsMapFromArray($infractions'postid');
        
$userIdMap $model->getImportContentMap('user'$userIds);

        
XenForo_Db::beginTransaction();

        foreach (
$infractions AS $infraction)
        {
            
$next $infraction['infractionid'];

            if (
$infraction['postid'])
            {
                
$newPostId $this->_mapLookUp($postIdMap$infraction['postid']);
                if (!
$newPostId)
                {
                    continue;
                }
            }
            else
            {
                
$newPostId 0;
            }

            
$newUserId $this->_mapLookUp($userIdMap$infraction['userid']);
            if (!
$newUserId)
            {
                continue;
            }

            
$newWarnUserId $this->_mapLookUp($userIdMap$infraction['whoadded']);
            if (!
$newWarnUserId)
            {
                
$newWarnUserId 0;
            }

            
$import = array(
                
'content_type' => $infraction['postid'] ? 'post' 'user',
                
'content_id' => $infraction['postid'] ? $newPostId $newUserId,
                
'content_title' => $this->_convertToUtf8($infraction['postid'] ? $infraction['thread_title'] : $infraction['username'], true),
                
'user_id' => $newUserId,
                
'warning_date' => $infraction['dateline'],
                
'warning_user_id' => $newWarnUserId,
                
'warning_definition_id' => 0,
                
'title' => $this->_convertToUtf8($infraction['title']),
                
'notes' => $this->_convertToUtf8($infraction['note']),
                
'points' => $infraction['points'],
                
'expiry_date' => $infraction['action'] == $infraction['dateline'] : $infraction['expires'],
                
'is_expired' => !empty($infraction['action']) ? 0,
                
'extra_user_group_ids' => ''
            
);

            if (
$model->importWarning($infraction['infractionid'], $import))
            {
                
$total++;
            }
        }

        
XenForo_Db::commit();

        
$this->_session->incrementStepImportTotal($total);

        return array(
$next$options$this->_getProgressOutput($next$options['max']));
    }
}
Онлайн: 1
Реклама