Файл: library/XenForo/Importer/XenForo.php
Строк: 2024
<?php
class XenForo_Importer_XenForo extends XenForo_Importer_Abstract
{
/**
* Source database connection.
*
* @var Zend_Db_Adapter_Abstract
*/
protected $_sourceDb;
protected $_config;
protected $_groupMap = null;
protected $_userFieldMap = null;
protected $_nodeTypeIds = array('Category', 'Forum', 'LinkForum', 'Page');
protected $_pollContentTypes = array('thread');
public static function getName()
{
return 'XenForo 1.2';
}
public function configure(XenForo_ControllerAdmin_Abstract $controller, array &$config)
{
if ($config)
{
$errors = $this->validateConfiguration($config);
if ($errors)
{
return $controller->responseError($errors);
}
$this->_bootstrap($config);
return true;
}
else
{
$viewParams = array('input' => array(
'db' => array(
'host' => 'localhost',
'port' => '3306',
)
));
return $controller->responseView('XenForo_ViewAdmin_Import_XenForo_Config', 'import_xenforo_config', $viewParams);
}
}
public function validateConfiguration(array &$config)
{
$errors = array();
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' => 'utf8',
)
);
$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 user_id FROM xf_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['dir']['data']))
{
if (!file_exists($config['dir']['data']) || !is_dir($config['dir']['data']))
{
$errors[] = new XenForo_Phrase('data_directory_not_found');
}
}
if (!empty($config['dir']['internal_data']))
{
if (!file_exists($config['dir']['internal_data']) || !is_dir($config['dir']['internal_data']))
{
$errors[] = new XenForo_Phrase('internal_data_directory_not_found');
}
}
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')
),
'followIgnore' => array(
'title' => new XenForo_Phrase('import_follow_ignore_lists'),
'depends' => array('users')
),
'conversations' => array(
'title' => new XenForo_Phrase('import_conversations'),
'depends' => array('users')
),
'profilePosts' => array(
'title' => new XenForo_Phrase('import_profile_posts'),
'depends' => array('users')
),
'nodes' => array(
'title' => new XenForo_Phrase('import_nodes'),
'depends' => array('userGroups')
),
'moderators' => array(
'title' => new XenForo_Phrase('import_moderators'),
'depends' => array('nodes', 'users')
),
'threadPrefixes' => array(
'title' => new XenForo_Phrase('import_thread_prefixes'),
'depends' => array('nodes')
),
'threads' => array(
'title' => new XenForo_Phrase('import_threads_and_posts'),
'depends' => array('nodes', '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('conversations', 'threads')
),
'likes' => array(
'title' => new XenForo_Phrase('import_likes'),
'depends' => array('threads', 'profilePosts')
),
'warnings' => array(
'title' => new XenForo_Phrase('import_warnings'),
'depends' => array('threads', 'profilePosts')
),
'userUpgrades' => array(
'title' => new XenForo_Phrase('import_user_upgrades'),
'depends' => array('users')
)
);
}
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' => 'utf8',
)
);
}
public function stepUserGroups($start, array $options)
{
$groups = $this->_sourceDb->fetchAll('SELECT * FROM xf_user_group ORDER BY user_group_id');
$total = 0;
XenForo_Db::beginTransaction();
foreach ($groups AS $group)
{
if ($group['user_group_id'] <= 4)
{
// Group IDs 1-4 will not be imported, just logged, as we know they are default groups
$this->_importModel->logImportData('userGroup', $group['user_group_id'], $group['user_group_id']);
}
else
{
// Group IDs > 4 will be imported as usual with new keys attached.
$import = $this->_quickAssembleData($group, array(
'title',
'display_style_priority',
'username_css',
'user_title',
'banner_css_class',
'banner_text'
));
$this->_importModel->importUserGroup($group['user_group_id'], $import);
}
$total++;
}
XenForo_Model::create('XenForo_Model_UserGroup')->rebuildDisplayStyleCache();
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return true;
}
public function stepUserFields($start, array $options)
{
$model = $this->_importModel;
$existingFields = $model->getUserFieldDefinitions();
/*
* See XenForo_Model_UserField::getUserFieldTitlePhraseName(),
* getUserFieldDescriptionPhraseName(),
* getUserFieldChoicePhraseName()
*/
$userFields = $this->_sourceDb->fetchAll("
SELECT field.*,
ptitle.phrase_text AS title,
pdesc.phrase_text AS description
FROM xf_user_field AS field
INNER JOIN xf_phrase AS ptitle ON
(
ptitle.language_id = 0 AND
ptitle.title = CONCAT('user_field_', field.field_id)
)
INNER JOIN xf_phrase AS pdesc ON
(
pdesc.language_id = 0 AND
pdesc.title = CONCAT('user_field_', field.field_id, '_desc')
)
");
$total = 0;
XenForo_Db::beginTransaction();
foreach ($userFields AS $userField)
{
if (!empty($existingFields[$userField['field_id']]))
{
// don't import a field if we already have one called that... seems a reasonable decision?
$model->logImportData('userField', $userField['field_id'], $userField['field_id']);
}
else
{
$fieldChoices = @unserialize($userField['field_choices']);
if (!is_array($fieldChoices))
{
$fieldChoices = array();
}
$import = $this->_quickAssembleData($userField, array(
'field_id',
'display_group',
'display_order',
'field_type',
'field_choices' => $fieldChoices,
'match_type',
'match_regex',
'match_callback_class',
'match_callback_method',
'max_length',
'required',
'show_registration',
'user_editable',
'viewable_profile',
'viewable_message',
'display_template',
// pseudo-fields
'title',
'description',
));
$model->importUserField($userField['field_id'], $import);
}
$total++;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return true;
}
public function configStepUsers(array $options)
{
if ($options)
{
return false;
}
return $this->_controller->responseView('XenForo_ViewAdmin_Import_XenForo_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,
), $options);
$sDb = $this->_sourceDb;
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('SELECT MAX(user_id) FROM xf_user');
}
$users = $sDb->fetchAll(
$sDb->limit($this->_getSelectUserSql('xf_user.user_id > ' . $sDb->quote($start)), $options['limit'])
);
if (!$users)
{
return $this->_getNextUserStep();
}
XenForo_Db::beginTransaction();
$next = 0;
$total = 0;
foreach ($users AS $user)
{
$next = $user['user_id'];
$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 stepUsersMerge($start, array $options)
{
$sDb = $this->_sourceDb;
$manual = $this->_session->getExtraData('userMerge');
if ($manual)
{
$merge = $sDb->fetchAll($this->_getSelectUserSql('xf_user.user_id 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['user_id']] = $this->_quickAssembleData($user, array(
'username',
'email',
'message_count',
'register_date',
'conflict' => $manual[$user['user_id']]
));
}
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('xf_user.user_id 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']] = $this->_quickAssembleData($user, array(
'username',
'email',
'message_count',
'register_date',
'failure' => $manual[$user['user_id']]
));
}
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['user_id']]))
{
continue;
}
$info = $resolve[$user['user_id']];
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;
}
/**
* Returns SQL to fetch a complete user record
*
* @param string $where
*
* @return string
*/
protected function _getSelectUserSql($where)
{
return '
SELECT
xf_user.*,
xf_user_option.*,
xf_user_privacy.*,
xf_user_profile.*,
xf_user_authenticate.*
FROM xf_user
INNER JOIN xf_user_option ON
(xf_user_option.user_id = xf_user.user_id)
INNER JOIN xf_user_privacy ON
(xf_user_privacy.user_id = xf_user.user_id)
INNER JOIN xf_user_profile ON
(xf_user_profile.user_id = xf_user.user_id)
INNER JOIN xf_user_authenticate ON
(xf_user_authenticate.user_id = xf_user.user_id)
WHERE ' . $where . '
ORDER BY xf_user.user_id
';
}
/**
* Determines whether to import or merge the specified user
*
* @param array $user
* @param array $options
* @return boolean
*/
protected function _importOrMergeUser(array $user, array $options = array())
{
$im = $this->_importModel;
if ($user['email'] && $emailMatch = $im->getUserIdByEmail($user['email']))
{
if (!empty($options['mergeEmail']))
{
return $this->_mergeUser($user, $emailMatch);
}
else
{
if ($im->getUserIdByUserName($user['username']))
{
$this->_session->setExtraData('userMerge', $user['user_id'], 'both');
}
else
{
$this->_session->setExtraData('userMerge', $user['user_id'], 'email');
}
return false;
}
}
if ($nameMatch = $im->getUserIdByUserName($user['username']))
{
if (!empty($options['mergeName']))
{
return $this->_mergeUser($user, $nameMatch);
}
else
{
$this->_session->setExtraData('userMerge', $user['user_id'], 'name');
return false;
}
}
return $this->_importUser($user, $options);
}
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['message_count'], $user['register_date'], $user['register_date'], $targetUserId));
$this->_importModel->logImportData('user', $user['user_id'], $targetUserId);
return $targetUserId;
}
protected function _importUser(array $user, array $options = array())
{
if ($this->_groupMap === null)
{
$this->_groupMap = $this->_importModel->getImportContentMap('userGroup');
}
$import = $this->_quickAssembleData($user, array(
// xf_user
#'user_id',
'username',
'email',
'gender',
'custom_title',
#'language_id',
#'style_id',
'timezone',
'visible',
'user_group_id' => $this->_mapLookUp($this->_groupMap, $user['user_group_id'], XenForo_Model_User::$defaultRegisteredGroupId),
'secondary_group_ids' => $this->_translateUserGroupIdList($user['secondary_group_ids'], true),
'display_style_group_id' => $this->_mapLookUp($this->_groupMap, $user['display_style_group_id'], XenForo_Model_User::$defaultRegisteredGroupId),
#'permission_combination_id',
'message_count',
'conversations_unread',
'register_date',
'last_activity',
#'trophy_points',
'avatar_date',
'avatar_width',
'avatar_height',
'gravatar',
'user_state',
'is_moderator',
'is_admin',
'is_staff',
'is_banned',
'like_count',
'warning_points',
// xf_user_profile
'dob_day',
'dob_month',
'dob_year',
'status',
'status_date',
#'status_profile_post_id',
'signature',
'homepage',
'location',
'occupation',
#'following',
#'csrf_token',
'avatar_crop_x',
'avatar_crop_y',
'about',
#'custom_fields',
#'ignored',
// xf_user_option
'show_dob_year',
'show_dob_date',
'content_show_signature',
'receive_admin_email',
'email_on_conversation',
'is_discouraged',
'default_watch_state',
'alert_optout',
'enable_rte',
'enable_flash_uploader',
// xf_user_privacy
'allow_view_profile',
'allow_post_profile',
'allow_send_personal_conversation',
'allow_view_identities',
'allow_receive_news_feed',
// xf_user_authenticate
'scheme_class',
'data',
#'remember_key',
));
// custom user fields
if ($user['custom_fields'] = unserialize($user['custom_fields']))
{
if ($this->_userFieldMap === null)
{
$this->_userFieldMap = $this->_importModel->getImportContentMap('userField');
}
$userFieldDefinitions = $this->_importModel->getUserFieldDefinitions();
foreach ($user['custom_fields'] AS $oldFieldId => $customField)
{
$newFieldId = $this->_mapLookUp($this->_userFieldMap, $oldFieldId);
if (!$newFieldId)
{
continue;
}
$import[XenForo_Model_Import::USER_FIELD_KEY][$newFieldId] = $user['custom_fields'][$oldFieldId];
}
}
$importedUserId = $this->_importModel->importUser($user['user_id'], $import, $failedKey, false);
if ($importedUserId)
{
// banned users
if ($user['is_banned'])
{
if ($ban = $this->_sourceDb->fetchRow('SELECT * FROM xf_user_ban WHERE user_id = ?', $user['user_id']))
{
$this->_importModel->importBan($this->_quickAssembleData($ban, array(
'user_id' => $importedUserId,
'ban_user_id' => $this->_importModel->mapUserId($ban['ban_user_id'], 0),
'ban_date',
'end_date',
'user_reason',
'triggered',
)));
}
}
// handle admins in a different way from normal imports so that we get a complete data import
if ($user['is_admin'])
{
if ($admin = $this->_sourceDb->fetchRow('SELECT * FROM xf_admin WHERE user_id = ?', $user['user_id']))
{
$this->_importModel->importAdmin($this->_quickAssembleData($admin, array(
'user_id' => $importedUserId,
'extra_user_group_ids' => $this->_translateUserGroupIdList($admin['extra_user_group_ids']),
'last_login',
'permission_cache'
)));
}
}
// avatar
if ($user['avatar_date'])
{
/* @var $avatarModel XenForo_Model_Avatar */
$avatarModel = XenForo_Model::create('XenForo_Model_Avatar');
foreach (array('l', 'm', 's') AS $size)
{
$oldAvatar = $avatarModel->getAvatarFilePath($user['user_id'], $size, $this->_config['dir']['data']);
if (!file_exists($oldAvatar) || !is_readable($oldAvatar))
{
continue;
}
$newAvatar = $avatarModel->getAvatarFilePath($importedUserId, $size);
$directory = dirname($newAvatar);
if (XenForo_Helper_File::createDirectory($directory, true) && is_writable($directory))
{
copy($oldAvatar, $newAvatar);
}
}
}
}
else if ($failedKey)
{
$this->_session->setExtraData('userFailed', $user['user_id'], $failedKey);
}
return $importedUserId;
}
/**
* Translates xf_user.secondary_group_ids to new group IDs
*
* @param string $idString
* @param boolean If true, return an array instead of a string
*
* @return string|array
*/
protected function _translateUserGroupIdList($idString, $returnArray = false)
{
$groupIds = array();
if (!empty($idString))
{
if ($this->_groupMap === null)
{
$this->_groupMap = $this->_importModel->getImportContentMap('userGroup');
}
$oldGroupIds = preg_split('/,/', $idString, -1, PREG_SPLIT_NO_EMPTY);
foreach ($oldGroupIds AS $oldGroupId)
{
$gId = $this->_mapLookUp($this->_groupMap, $oldGroupId);
if ($gId)
{
$groupIds[] = $gId;
}
}
}
return ($returnArray ? $groupIds : implode(',', $groupIds));
}
public function stepFollowIgnore($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false,
), $options);
// fetch 100 users and insert following and ignoring records for each
$sDb = $this->_sourceDb;
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('SELECT MAX(user_id) FROM xf_user');
}
$userIds = $sDb->fetchCol($sDb->limit("
SELECT user_id
FROM xf_user_profile
WHERE user_id > ? AND
(following <> '' OR (ignored <> '' AND ignored <> 'a:0:{}'))
ORDER BY user_id
", $options['limit']
), $start);
if (!$userIds)
{
return true;
}
$searchUserIds = $userIds;
$users = array();
// collect user ids from follow and ignore tables
$follows = $sDb->fetchAll('SELECT * FROM xf_user_follow WHERE user_id IN(' . $sDb->quote($searchUserIds) . ')');
foreach ($follows AS $follow)
{
$userIds[] = $follow['follow_user_id'];
$users[$follow['user_id']]['following'][] = $follow['follow_user_id'];
}
$ignores = $sDb->fetchAll('SELECT * FROM xf_user_ignored WHERE user_id IN(' . $sDb->quote($searchUserIds) . ')');
foreach ($ignores AS $ignore)
{
$userIds[] = $ignore['ignored_user_id'];
$users[$ignore['user_id']]['ignoring'][] = $ignore['ignored_user_id'];
}
ksort($users);
// get a map for all referenced user ids
$userIdMap = $model->getImportContentMap('user', array_unique($userIds));
XenForo_Db::beginTransaction();
$next = 0;
$total = 0;
foreach ($users AS $userId => $user)
{
$next = $userId;
$importUserId = $this->_mapLookUp($userIdMap, $userId);
if (!$importUserId)
{
continue;
}
if (!empty($user['following']))
{
$followUserIds = array();
foreach ($user['following'] AS $followUserId)
{
if ($importFollowUserId = $this->_mapLookUp($userIdMap, $followUserId, 0))
{
$followUserIds[$followUserId] = $importFollowUserId;
}
}
if ($followUserIds && $model->importFollowing($importUserId, $followUserIds))
{
$total++;
}
}
if (!empty($user['ignoring']))
{
$ignoreUserIds = array();
foreach ($user['ignoring'] AS $ignoreUserId)
{
if ($importIgnoreUserId = $this->_mapLookUp($userIdMap, $ignoreUserId, 0))
{
$ignoreUserIds[$ignoreUserId] = $importIgnoreUserId;
}
}
if ($ignoreUserIds && $model->importIgnored($importUserId, $ignoreUserIds))
{
$total++;
}
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
public function stepConversations($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(conversation_id)
FROM xf_conversation_master
');
}
$conversations = $sDb->fetchAll($sDb->limit(
'
SELECT *
FROM xf_conversation_master
WHERE conversation_id > ' . $sDb->quote($start) . '
ORDER BY conversation_id
', $options['limit']
));
if (!$conversations)
{
return true;
}
$next = 0;
$total = 0;
XenForo_Db::beginTransaction();
foreach ($conversations AS $conversation)
{
$next = $conversation['conversation_id'];
$recipientRecords = $sDb->fetchAll('
SELECT *
FROM xf_conversation_recipient
WHERE conversation_id = ?
', $conversation['conversation_id']);
// build a user map
$userIds = array($conversation['user_id']);
foreach ($recipientRecords AS $recipient)
{
$userIds[] = $recipient['user_id'];
}
// get a map for all referenced user ids
$userIdMap = $model->getImportContentMap('user', $userIds);
$recipients = array();
foreach ($recipientRecords AS $recipient)
{
$recipientUserId = $this->_mapLookUp($userIdMap, $recipient['user_id'], 0);
$recipients[$recipientUserId] = $this->_quickAssembleData($recipient, array(
'recipient_state',
'last_read_date'
));
}
$messageRecords = $sDb->fetchAll('
SELECT *
FROM xf_conversation_message
WHERE conversation_id = ?
', $conversation['conversation_id']);
$messages = array();
foreach ($messageRecords AS $message)
{
$messages[$message['message_id']] = $this->_quickAssembleData($message, array(
'message_date',
'user_id' => $this->_mapLookUp($userIdMap, $message['user_id'], 0),
'username',
'message',
'attach_count'
));
}
$importConversation = $this->_quickAssembleData($conversation, array(
'title',
'user_id' => $this->_mapLookUp($userIdMap, $conversation['user_id'], 0),
'username',
'start_date',
'reply_count',
'recipient_count',
'open_invite',
'conversation_open',
'last_message_date',
'last_message_user_id' => $this->_mapLookUp($userIdMap, $conversation['last_message_user_id'], 0),
'last_message_username',
));
if ($model->importConversation($conversation['conversation_id'], $importConversation, $recipients, $messages))
{
$total++;
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
public function stepProfilePosts($start, array $options)
{
$options = array_merge(array(
'limit' => 200,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(profile_post_id)
FROM xf_profile_post
');
}
$profilePosts = $sDb->fetchAll($sDb->limit(
'
SELECT xf_profile_post.*, xf_ip.ip
FROM xf_profile_post
LEFT JOIN xf_ip ON (xf_ip.ip_id = xf_profile_post.ip_id)
WHERE xf_profile_post.profile_post_id > ' . $sDb->quote($start) . '
ORDER BY xf_profile_post.profile_post_id
', $options['limit']
));
if (!$profilePosts)
{
return true;
}
$next = 0;
$total = 0;
XenForo_Db::beginTransaction();
$db = XenForo_Application::getDb();
foreach ($profilePosts AS $profilePost)
{
$next = $profilePost['profile_post_id'];
$userIds = array($profilePost['user_id'], $profilePost['profile_user_id']);
if ($profilePost['comment_count'])
{
// fetch comments and insert
$comments = $sDb->fetchAll('
SELECT xf_profile_post_comment.*, xf_ip.ip
FROM xf_profile_post_comment
LEFT JOIN xf_ip ON (xf_ip.ip_id = xf_profile_post_comment.ip_id)
WHERE xf_profile_post_comment.profile_post_id = ?
', $profilePost['profile_post_id']);
foreach ($comments AS $comment)
{
$userIds[] = $comment['user_id'];
}
}
else
{
$comments = false;
}
$userIdMap = $model->getImportContentMap('user', $userIds);
$profileUserId = $this->_mapLookUp($userIdMap, $profilePost['profile_user_id']);
if (!$profileUserId)
{
continue;
}
$importProfilePost = $this->_quickAssembleData($profilePost, array(
'profile_user_id' => $profileUserId,
'user_id' => $this->_mapLookUp($userIdMap, $profilePost['user_id'], 0),
'username',
'post_date',
'message',
'ip' => XenForo_Helper_Ip::convertIpBinaryToString($profilePost['ip']),
'message_state',
#'attach_count',
#'likes',
#'like_users',
'comment_count',
'first_comment_date',
'last_comment_date',
#'latest_comment_ids',
#'warning_id',
#'warning_message',
));
if ($profilePostId = $model->importProfilePost($profilePost['profile_post_id'], $importProfilePost))
{
if (!empty($comments))
{
$lastCommentIds = array();
foreach ($comments AS $comment)
{
$importComment = $this->_quickAssembleData($comment, array(
'profile_post_id' => $profilePostId,
'user_id' => $this->_mapLookUp($userIdMap, $comment['user_id'], 0),
'username',
'comment_date',
'message',
//'ip' => XenForo_Helper_Ip::convertIpBinaryToString($comment['ip']),
));
$lastCommentId = $model->importProfilePostComment($comment['profile_post_comment_id'], $importComment);
if ($lastCommentId)
{
$lastCommentIds[] = $lastCommentId;
}
}
$db->update('xf_profile_post', array(
'latest_comment_ids' => implode(',', array_slice($lastCommentIds, -3))
), 'profile_post_id = ' . $sDb->quote($profilePostId));
}
$total++;
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
/**
* Currently handles categories, forums, link forums and pages
*
* @param integer $start
* @param array $options
*/
public function stepNodes($start, array $options)
{
$sDb = $this->_sourceDb;
/* @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;
}
$nodes = $sDb->fetchAll('
SELECT *
FROM xf_node
WHERE node_type_id IN (' . $sDb->quote($this->_nodeTypeIds) . ')
');
if (!$nodes)
{
return true;
}
// get data for all forums, link forums and pages
$nodeData = array();
foreach ($sDb->fetchAll('SELECT * FROM xf_forum') AS $forum)
{
$nodeData[$forum['node_id']] = $forum;
}
foreach ($sDb->fetchAll('SELECT * FROM xf_page') AS $page)
{
$nodeData[$page['node_id']] = $page;
}
foreach ($sDb->fetchAll('SELECT * FROM xf_link_forum') AS $linkForum)
{
$nodeData[$linkForum['node_id']] = $linkForum;
}
// build a tree of node data
$nodeTree = array();
foreach ($nodes AS $node)
{
if (isset($nodeData[$node['node_id']]))
{
$node = array_merge($node, $nodeData[$node['node_id']]);
}
$nodeTree[$node['parent_node_id']][$node['node_id']] = $node;
}
// fetch node permissions
$nodePermissions = array();
foreach ($sDb->fetchAll("SELECT * FROM xf_permission_entry_content WHERE content_type = 'node'") AS $nodePermission)
{
$nodePermissions[$nodePermission['content_id']][] = $nodePermission;
}
XenForo_Db::beginTransaction();
$total = $this->_importNodeTree(0, $nodeTree, $nodePermissions);
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array(1, array(), '');
}
/**
* Works with a tree of node data to recursively import nodes
*
* @param integer $parentId
* @param array $nodeTree
* @param array $nodePermissions
* @param array $nodeIdMap
*
* @return number
*/
protected function _importNodeTree($parentId, array $nodeTree, array $nodePermissions = array(), array $nodeIdMap = array())
{
if (!isset($nodeTree[$parentId]))
{
return 0;
}
XenForo_Db::beginTransaction();
$total = 0;
foreach ($nodeTree[$parentId] AS $node)
{
$import = $this->_quickAssembleData($node, array(
'title',
'description',
'node_type_id',
'display_order',
'display_in_list',
'parent_node_id' => $this->_mapLookUp($nodeIdMap, $node['parent_node_id'], 0),
));
// don't even set node_name if it's not specified in the source record
if ($node['node_name'])
{
$import['node_name'] = $node['node_name'];
}
switch ($node['node_type_id'])
{
case 'Forum':
{
$import = $this->_quickAssembleData($node, array(
'discussion_count',
'message_count',
'moderate_messages',
'allow_posting',
'count_messages',
'find_new',
'default_sort_order',
'default_sort_direction',
'require_prefix',
'allowed_watch_notifications',
), $import);
$nodeId = $this->_importModel->importForum($node['node_id'], $import);
}
break;
case 'LinkForum':
{
$import = $this->_quickAssembleData($node, array(
'link_url',
'redirect_count',
), $import);
$nodeId = $this->_importModel->importLinkForum($node['node_id'], $import);
}
break;
case 'Page':
{
$import = $this->_quickAssembleData($node, array(
'publish_date',
'modified_date',
'view_count',
'list_siblings',
'list_children',
'log_visits',
'callback_class',
'callback_method',
), $import);
/* @var $pageModel XenForo_Model_Page */
$pageModel = XenForo_Model::create('XenForo_Model_Page');
$template = $this->_sourceDb->fetchOne('
SELECT template
FROM xf_template
WHERE style_id = 0
AND title = ?', $pageModel->getTemplateTitle($node));
$nodeId = $this->_importModel->importPage($node['node_id'], $import, $template);
}
break;
default: // Category
{
// no additional data to import, so just grab the node info
$nodeId = $this->_importModel->importCategory($node['node_id'], $import);
}
}
if ($nodeId)
{
if (!empty($nodePermissions[$node['node_id']]))
{
$this->_importNodePermissions($nodeId, $nodePermissions[$node['node_id']]);
}
$nodeIdMap[$node['node_id']] = $nodeId;
$total++;
$total += $this->_importNodeTree($node['node_id'], $nodeTree, $nodePermissions, $nodeIdMap);
}
}
XenForo_Db::commit();
return $total;
}
protected function _importNodePermissions($nodeId, array $nodePerms)
{
if ($this->_groupMap === null)
{
$this->_groupMap = $this->_importModel->getImportContentMap('userGroup');
}
XenForo_Db::beginTransaction();
foreach ($nodePerms AS $nodeId => $nodePerm)
{
if (!empty($nodePerm['user_id']))
{
$userId = $this->_importModel->mapUserId($nodePerm['user_id'], 0);
$userGroupId = 0;
if (!$userId)
{
continue;
}
}
else
{
$userId = 0;
$userGroupId = $this->_mapLookUp($this->_groupMap, $nodePerm['user_group_id']);
if (!$userGroupId)
{
continue;
}
}
if ($nodePerm['permission_value'] == 'use_int')
{
$permValue = $nodePerm['permission_value_int'];
}
else
{
$permValue = $nodePerm['permission_value'];
}
$perms = array();
$perms[$nodePerm['permission_group_id']][$nodePerm['permission_id']] = $permValue;
$this->_importModel->insertNodePermissionEntries($nodeId, $userGroupId, $userId, $perms);
}
XenForo_Db::commit();
}
/**
* Currenty handles global and node moderators only
*
* @param integer $start
* @param array $options
*/
public function stepModerators($start, array $options)
{
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$moderators = $sDb->fetchAll('SELECT * FROM xf_moderator');
if (!$moderators)
{
return true;
}
$nodeModerators = $sDb->fetchAll("SELECT * FROM xf_moderator_content WHERE content_type = 'node'");
$modsGrouped = array();
foreach ($moderators AS $moderator)
{
$modsGrouped[$moderator['user_id']] = $moderator;
}
foreach ($nodeModerators AS $cm)
{
$modsGrouped[$cm['user_id']]['nodes'][$cm['content_id']] = $cm['moderator_permissions'];
}
$nodeMap = $model->getImportContentMap('node');
$userIdMap = $model->getImportContentMap('user', array_keys($modsGrouped));
$total = 0;
XenForo_Db::beginTransaction();
foreach ($modsGrouped AS $userId => $user)
{
$newUserId = $this->_mapLookUp($userIdMap, $userId);
if (!$newUserId)
{
continue;
}
if (isset($user['nodes']))
{
foreach ($user['nodes'] AS $nodeId => $permissions)
{
$newNodeId = $this->_mapLookUp($nodeMap, $nodeId);
if (!$newNodeId)
{
continue;
}
$mod = array(
'user_id' => $newUserId,
'content_id' => $newNodeId,
'moderator_permissions' => unserialize($permissions)
);
$model->importNodeModerator($nodeId, $userId, $mod);
$total++;
}
}
if ($user['extra_user_group_ids'])
{
$extraGroupIds = $this->_translateUserGroupIdList($user['extra_user_group_ids']);
}
else
{
$extraGroupIds = '';
}
$mod = array(
'user_id' => $newUserId,
'is_super_moderator' => $user['is_super_moderator'],
'extra_user_group_ids' => $extraGroupIds,
'moderator_permissions' => unserialize($user['moderator_permissions'])
);
$model->importGlobalModerator($userId, $mod);
$total++;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return true;
}
/**
* Assumes phrase names of thread_prefix_% and thread_prefix_group_%
*
* @param integer $start
* @param array $options
*/
public function stepThreadPrefixes($start, array $options)
{
$options = array_merge(array(), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$nodeMap = $model->getImportContentMap('node');
$userGroupMap = $model->getImportContentMap('userGroup');
$prefixes = $sDb->fetchAll("
SELECT tp.*,
p.phrase_text
FROM xf_thread_prefix AS tp
INNER JOIN xf_phrase AS p
ON (
p.language_id = 0 AND
p.title = CONCAT('thread_prefix_', tp.prefix_id)
)
");
if (!$prefixes)
{
return true;
}
$prefixGroups = $sDb->fetchAll("
SELECT tpg.*,
p.phrase_text
FROM xf_thread_prefix_group AS tpg
INNER JOIN xf_phrase AS p
ON (
p.language_id = 0 AND
p.title = CONCAT('thread_prefix_group_', tpg.prefix_group_id)
)
");
$prefixGroupMap = array();
foreach ($prefixGroups AS $prefixGroup)
{
$importPrefixGroup = array(
'display_order' => $prefixGroup['display_order'],
XenForo_Model_Import::EXTRA_DATA_KEY => array(
XenForo_DataWriter_ThreadPrefixGroup::DATA_TITLE => $prefixGroup['phrase_text']
)
);
$prefixGroupMap[$prefixGroup['prefix_group_id']] = $model->importThreadPrefixGroup($prefixGroup['prefix_group_id'], $importPrefixGroup);
}
$forumPrefixes = array();
foreach ($sDb->fetchAll('SELECT * FROM xf_forum_prefix') AS $forumPrefix)
{
$nodeId = $this->_mapLookUp($nodeMap, $forumPrefix['node_id']);
if ($nodeId)
{
$forumPrefixes[$forumPrefix['prefix_id']][] = $nodeId;
}
}
$total = 0;
foreach ($prefixes AS $prefix)
{
$prefixGroupId = $this->_mapLookUp($prefixGroupMap, $prefix['prefix_group_id'], 0);
if ($prefix['allowed_user_group_ids'] == '-1')
{
$allowedUserGroupIds = '-1';
}
else
{
$allowedUserGroupIds = $this->_translateUserGroupIdList($prefix['allowed_user_group_ids']);
}
$importPrefix = $this->_quickAssembleData($prefix, array(
'prefix_group_id' => $prefixGroupId,
'display_order',
'css_class',
'allowed_user_group_ids' => $allowedUserGroupIds,
));
if (isset($forumPrefixes[$prefix['prefix_id']]))
{
$nodeIds = $forumPrefixes[$prefix['prefix_id']];
}
else
{
$nodeIds = array();
}
$model->importThreadPrefix($prefix['prefix_id'], $importPrefix, $prefix['phrase_text'], $nodeIds);
$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;
}
/**
* Does not currently handle redirects
*
* @param integer $start
* @param array $options
*/
public function stepThreads($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'postDateStart' => 0,
'postLimit' => 800,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(thread_id)
FROM xf_thread
');
}
$threads = $sDb->fetchAll($sDb->limit(
"
SELECT thread.*,
IF (user.username IS NULL, thread.username, user.username) AS username
FROM xf_thread AS thread
LEFT JOIN xf_user AS user ON (user.user_id = thread.user_id)
WHERE thread.thread_id >= " . $sDb->quote($start) . "
AND thread.discussion_type <> 'redirect'
", $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)
{
$postDateStart = $options['postDateStart'];
$next = $thread['thread_id'] + 1;
$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,
xf_ip.ip
FROM xf_post AS post
LEFT JOIN xf_user AS user ON (user.user_id = post.user_id)
LEFT JOIN xf_ip ON (xf_ip.ip_id = post.ip_id)
WHERE post.thread_id = " . $sDb->quote($thread['thread_id']) . "
AND post.post_date > " . $sDb->quote($postDateStart) . "
ORDER BY post.post_date
", $maxPosts
));
if (!$posts)
{
if ($postDateStart)
{
// continuing thread but no remaining threads
$total++;
}
continue;
}
if ($postDateStart)
{
// continuing already-imported thread
$threadId = $model->mapThreadId($thread['thread_id']);
$position = $this->_db->fetchOne('
SELECT MAX(position)
FROM xf_post
WHERE thread_id = ?
', $threadId);
}
else
{
$forumId = $this->_mapLookUp($nodeMap, $thread['node_id']);
if (!$forumId)
{
continue;
}
$import = $this->_quickAssembleData($thread, array(
'node_id' => $forumId,
'title',
'reply_count',
'view_count',
'user_id' => $model->mapUserId($thread['user_id'], 0),
'username',
'post_date',
'sticky',
'discussion_state',
'discussion_open',
'discussion_type',
'prefix_id' => $this->_mapLookUp($threadPrefixMap, $thread['prefix_id'], 0)
));
$threadId = $model->importThread($thread['thread_id'], $import);
if (!$threadId)
{
continue;
}
$subscriptions = $sDb->fetchPairs('
SELECT user_id, email_subscribe
FROM xf_thread_watch
WHERE thread_id = ?
', $thread['thread_id']
);
if ($subscriptions)
{
$userIdMap = $model->getImportContentMap('user', array_keys($subscriptions));
foreach ($subscriptions AS $userId => $emailSubscribe)
{
if ($newUserId = $this->_mapLookUp($userIdMap, $userId))
{
$model->importThreadWatch($newUserId, $threadId, $emailSubscribe);
}
}
}
}
if ($threadId)
{
$quotedPostIds = array();
$quotedUserIds = array();
$userIdMap = $model->getUserIdsMapFromArray($posts, 'user_id');
foreach ($posts AS $i => $post)
{
$import = $this->_quickAssembleData($post, array(
'thread_id' => $threadId,
'user_id' => $this->_mapLookUp($userIdMap, $post['user_id'], 0),
'username',
'post_date',
'message',
'ip' => XenForo_Helper_Ip::convertIpBinaryToString($post['ip']),
'message_state',
'attach_count',
'position',
'likes',
'last_edit_date',
'edit_count',
));
$post['new_post_id'] = $model->importPost($post['post_id'], $import);
$options['postDateStart'] = $post['post_date'];
$totalPosts++;
// quotes
if (stripos($post['message'], '[quote=') !== false)
{
if (preg_match_all('/[quote=("|'|)(?P<username>[^,]*),post:s*(?P<post_id>d+)s*,s*member:s*(?P<user_id>d+)s*1]/siU', $post['message'], $quotes, PREG_SET_ORDER))
{
$post['quotes'] = array();
foreach ($quotes AS $quote)
{
$quotedPostId = intval($quote['post_id']);
$quotedPostIds[] = $quotedPostId;
$quotedUserId = intval($quote['user_id']);
$quotedUserIds[] = $quotedUserId;
$post['quotes'][$quote[0]] = array($quote['username'], $quotedPostId, $quotedUserId);
}
}
}
$posts[$i] = $post;
}
$postIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('post', $quotedPostIds));
$userIdMap = array_merge($userIdMap, (empty($quotedUserIds) ? array() : $model->getImportContentMap('user', $quotedUserIds)));
$db = XenForo_Application::getDb();
foreach ($posts AS $post)
{
if (!empty($post['quotes']))
{
$postQuotesRewrite = $this->_rewritePostQuotes($post['message'], $post['quotes'], $postIdMap, $userIdMap);
if ($post['message'] != $postQuotesRewrite)
{
$db->update('xf_post', array('message' => $postQuotesRewrite), 'post_id = ' . $db->quote($post['new_post_id']));
}
}
}
}
if (count($posts) < $maxPosts)
{
// this thread completed
$total++;
$options['postDateStart'] = 0;
}
else
{
// pick up the thread on the next go-around
break;
}
}
if ($options['postDateStart'])
{
// thread not yet completed
$next--;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next - 1, $options['max']));
}
/**
* Rewrites post quotes with imported user and post ids
*
* @param string $message
* @param array $quotes
* @param array $postMap
* @param array $userMap
*
* @return array
*/
protected function _rewritePostQuotes($message, array $quotes, array $postMap, array $userMap)
{
foreach ($quotes AS $quote => &$replace)
{
list($username, $postId, $userId) = $replace;
$replace = sprintf('[quote="%s, post: %d, member: %d"]',
$username,
$this->_mapLookUp($postMap, $postId, 0),
$this->_mapLookUp($userMap, $userId, 0)
);
}
return str_replace(array_keys($quotes), $quotes, $message);
}
/**
* Quick method to allow array data with specific keys to be added to an output array
*
* @param array Input data
* @param array Keys to copy
* @param array Existing output array, if it exists
*
* @return array
*/
protected function _quickAssembleData(array $info, array $keys, array $output = array())
{
foreach ($keys AS $key => $value)
{
if (is_string($key))
{
$output[$key] = $value;
}
else
{
$output[$value] = $info[$value];
}
}
return $output;
}
/**
* Currently handles edit history for posts only
*
* @param integer $start
* @param array $options
*/
public function stepPostEditHistory($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne("
SELECT MAX(content_id)
FROM xf_edit_history
WHERE content_type = 'post'
");
}
// fetch the next 100 posts
$postIds = $sDb->fetchCol($sDb->limit(
"
SELECT DISTINCT content_id
FROM xf_edit_history
WHERE content_id > " . $sDb->quote($start) . "
AND content_type = 'post'
ORDER BY content_id
", $options['limit']
));
if (!$postIds)
{
return true;
}
$edits = $sDb->fetchAll("
SELECT *
FROM xf_edit_history
WHERE content_id IN (" . $sDb->quote($postIds) . ")
AND content_type = 'post'
ORDER BY edit_date
");
if (!$edits)
{
return true;
}
$next = 0;
$total = 0;
$postIdMap = $model->getPostIdsMapFromArray($edits, 'content_id');
$userIdMap = $model->getUserIdsMapFromArray($edits, 'edit_user_id');
foreach ($edits AS $edit)
{
$next = $edit['content_id'];
$contentId = $this->_mapLookUp($postIdMap, $edit['content_id']);
if (!$contentId)
{
continue;
}
$import = $this->_quickAssembleData($edit, array(
'content_type',
'content_id' => $contentId,
'edit_user_id' => $this->_mapLookUp($userIdMap, $edit['edit_user_id'], 0),
'edit_date',
'old_text'
));
$model->importEditHistory($edit['edit_history_id'], $import);
$total++;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
/**
* Currently handles polls for threads only
*
* @param integer $start
* @param array $options
*/
public function stepPolls($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(poll_id)
FROM xf_poll
WHERE content_type IN (' . $sDb->quote($this->_pollContentTypes) . ')
');
}
$polls = $sDb->fetchAll($sDb->limit(
'
SELECT poll.*
FROM xf_poll AS poll
WHERE content_type IN (' . $sDb->quote($this->_pollContentTypes) . ')
AND poll.poll_id > ' . $sDb->quote($start) . '
ORDER BY poll.poll_id
', $options['limit']
));
if (!$polls)
{
return true;
}
$next = 0;
$total = 0;
$threadIdMap = $model->getThreadIdsMapFromArray($polls, 'content_id');
XenForo_Db::beginTransaction();
foreach ($polls AS $poll)
{
$next = $poll['poll_id'];
$newThreadId = $this->_mapLookUp($threadIdMap, $poll['content_id']);
if (!$newThreadId)
{
continue;
}
$import = $this->_quickAssembleData($poll, array(
'content_type',
'content_id' => $newThreadId,
'question',
'voter_count',
'public_votes',
'multiple',
'close_date'
));
$responses = array();
foreach (unserialize($poll['responses']) AS $responseId => $response)
{
$responses[$responseId] = $response['response'];
}
$newPollId = $model->importThreadPoll($poll['poll_id'], $newThreadId, $import, $responses, $responseIds);
$votes = $sDb->fetchAll('
SELECT user_id, poll_response_id, vote_date
FROM xf_poll_vote
WHERE poll_id = ?
', $poll['poll_id']);
if ($votes)
{
$userIdMap = $model->getUserIdsMapFromArray($votes, 'user_id');
foreach ($votes AS $vote)
{
$userId = $this->_mapLookUp($userIdMap, $vote['user_id']);
if (!$userId)
{
continue;
}
$model->importPollVote($newPollId,
$userId,
$this->_mapLookUp($responseIds, $vote['poll_response_id']),
$vote['vote_date']);
}
}
$total++;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
/**
* Currently handles attachments for posts and conversation messages only
*
* @param integer $start
* @param array $options
*/
public function stepAttachments($start, array $options)
{
$options = array_merge(array(
'data' => isset($this->_config['dir']['data']) ? $this->_config['dir']['data'] : '',
'internal_data' => isset($this->_config['dir']['internal_data']) ? $this->_config['dir']['internal_data'] : '',
'limit' => 50,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$attachmentSqlContentInfo = $model->getAttachmentContentSqlInfo();
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(attachment_id)
FROM xf_attachment
WHERE content_type IN (' . $sDb->quote(array_keys($attachmentSqlContentInfo)) . ')
');
}
$attachments = $sDb->fetchAll($sDb->limit(
'
SELECT *
FROM xf_attachment AS a
LEFT JOIN xf_attachment_data AS ad ON (ad.data_id = a.data_id)
WHERE a.content_type IN (' . $sDb->quote(array_keys($attachmentSqlContentInfo)) . ')
AND a.attachment_id > ' . $sDb->quote($start) . '
ORDER BY a.attachment_id
', $options['limit']
));
if (!$attachments)
{
return true;
}
$next = 0;
$total = 0;
$userIdMap = $model->getUserIdsMapFromArray($attachments, 'user_id');
$groupedAttachments = array();
foreach ($attachments AS $attachment)
{
$groupedAttachments[$attachment['content_type']][$attachment['attachment_id']] = $attachment;
}
$db = XenForo_Application::getDb();
/* @var $attachModel XenForo_Model_Attachment */
$attachModel = XenForo_Model::create('XenForo_Model_Attachment');
foreach ($groupedAttachments AS $contentType => $attachments)
{
list($sqlTableName, $sqlIdName) = $attachmentSqlContentInfo[$contentType];
$contentIdMap = $model->getImportContentMap($contentType, XenForo_Application::arrayColumn($attachments, 'content_id'));
if ($contentIdMap)
{
$contentItems = $db->fetchPairs("
SELECT $sqlIdName, message
FROM $sqlTableName
WHERE $sqlIdName IN (" . $db->quote($contentIdMap) . ")
");
}
else
{
$contentItems = array();
}
foreach ($attachments AS $attachment)
{
$next = max($next, $attachment['attachment_id']);
$contentId = $this->_mapLookUp($contentIdMap, $attachment['content_id']);
if (!$contentId || !isset($contentItems[$contentId]))
{
continue;
}
$attachFileOrig = $attachModel->getAttachmentDataFilePath($attachment, $options['internal_data']);
if (!file_exists($attachFileOrig))
{
continue;
}
$userId = $this->_mapLookUp($userIdMap, $attachment['user_id'], 0);
$attachFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
copy($attachFileOrig, $attachFile);
$success = $model->importAttachment(
$attachment['attachment_id'],
$attachment['filename'],
$attachFile,
$userId,
$contentType,
$contentId,
$attachment['upload_date'],
array('view_count' => $attachment['view_count']),
array($this, 'processAttachmentTags'),
$contentItems[$contentId]
);
if ($success)
{
$total++;
}
@unlink($attachFile);
}
}
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
/**
* Limited to likes for post and profile posts at present
*
* @param integer $start
* @param array $options
*/
public function stepLikes($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$likeTypes = $model->getSupportedLikeTypes();
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(like_id)
FROM xf_liked_content
WHERE content_type IN (' . $sDb->quote(array_keys($likeTypes)) . ')
');
}
$likes = $sDb->fetchAll($sDb->limit(
'
SELECT *
FROM xf_liked_content
WHERE content_type IN (' . $sDb->quote(array_keys($likeTypes)) . ')
AND like_id > ' . $sDb->quote($start) . '
ORDER BY like_id
', $options['limit']
));
if (!$likes)
{
return true;
}
$next = 0;
$total = 0;
$groupedLikes = array();
$userIds = array();
foreach ($likes AS $like)
{
$groupedLikes[$like['content_type']][$like['content_id']] = $like;
$userIds[] = $like['like_user_id'];
$userIds[] = $like['content_user_id'];
}
$userIdMap = $model->getImportContentMap('user', $userIds);
XenForo_Db::beginTransaction();
foreach ($groupedLikes AS $contentType => $likes)
{
$contentIdMap = $model->getImportContentMap($contentType, array_keys($likes));
foreach ($likes AS $contentId => $like)
{
$next = $like['like_id'];
$newContentId = $this->_mapLookUp($contentIdMap, $contentId);
if (!$newContentId)
{
continue;
}
$model->importLike(
$contentType,
$newContentId,
$this->_mapLookUp($userIdMap, $like['content_user_id'], 0),
$this->_mapLookUp($userIdMap, $like['like_user_id'], 0),
$like['like_date']
);
$total++;
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
/**
* Handles user, post and profile post warnings
*
* @param integer $start
* @param array $options
*/
public function stepWarnings($start, array $options)
{
$options = array_merge(array(
'limit' => 100,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$warningTypes = $model->getSupportedWarningTypes();
/*if ($start == 0)
{
// first time around, import warning definitions
// note: phrase relates to XenForo_Model_Warning::getWarningDefinitionTitlePhraseName()
$warningDefinitions = $sDb->fetchAll("
SELECT wd.*,
phrase.phrase_text
FROM xf_warning_definition AS wd
INNER JOIN xf_phrase AS phrase ON
(
phrase.language_id = 0 AND
phrase.title = CONCAT('warning_definition_', wd.warning_definition_id, '_title')
)
");
foreach ($warningDefinitions AS $warningDefinition)
{
$import = $this->_quickAssembleData($warningDefinition, array(
'points_default',
'expiry_type',
'expiry_default',
'extra_user_group_ids' => $this->_translateUserGroupIdList($warningDefinition['extra_user_group_ids']),
'is_editable',
XenForo_Model_Import::EXTRA_DATA_KEY => array(
XenForo_DataWriter_WarningDefinition::DATA_TITLE => $warning['title']
)
));
}
}*/
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne("
SELECT MAX(warning_id)
FROM xf_warning
WHERE content_type IN (" . $sDb->quote(array_keys($warningTypes)) . ", 'user')
");
}
$warnings = $sDb->fetchAll($sDb->limit(
"
SELECT *
FROM xf_warning
WHERE content_type IN (" . $sDb->quote(array_keys($warningTypes)) . ", 'user')
AND warning_id > " . $sDb->quote($start) . "
", $options['limit']
));
if (!$warnings)
{
return true;
}
$next = 0;
$total = 0;
$groupedWarnings = array();
foreach ($warnings AS $warning)
{
$groupedWarnings[$warning['content_type']][$warning['warning_id']] = $warning;
}
$userIdMap = $model->getUserIdsMapFromArray($warnings, array('user_id', 'warning_user_id'));
//$warningDefinitionMap = $model->getImportContentMap('warning_definition');
XenForo_Db::beginTransaction();
foreach ($groupedWarnings AS $contentType => $warnings)
{
if ($contentType == 'user')
{
// if we encounter a user warning, it will actually use the user id map
$contentMap = $userIdMap;
}
else
{
$contentMap = $model->getImportContentMapFromArray($contentType, $warnings, 'content_id');
}
foreach ($warnings AS $warningId => $warning)
{
$next = $warningId;
$userId = $this->_mapLookUp($userIdMap, $warning['user_id']);
if (!$userId)
{
continue;
}
$contentId = $this->_mapLookUp($contentMap, $warning['content_id']);
if (!$contentId)
{
continue;
}
/*$warningDefinitionId = $this->_mapLookUp($warningDefinitionMap, $warning['warning_definition_id']);
if (!$warningDefinitionId)
{
continue;
}*/
$warningDefinitionId = 0;
$import = $this->_quickAssembleData($warning, array(
'content_type',
'content_id' => $contentId,
'content_title',
'user_id' => $userId,
'warning_date',
'warning_user_id' => $this->_mapLookUp($userIdMap, $warning['warning_user_id'], 0),
'warning_definition_id' => $warningDefinitionId,
'title',
'notes',
'points',
'expiry_date',
'is_expired',
'extra_user_group_ids' => $this->_translateUserGroupIdList($warning['extra_user_group_ids'])
));
if ($model->importWarning($warningId, $import))
{
$total++;
}
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
public function stepUserUpgrades($start, array $options)
{
$options = array_merge(array(
'limit' => 200,
'max' => false
), $options);
$sDb = $this->_sourceDb;
/* @var $model XenForo_Model_Import */
$model = $this->_importModel;
$total = 0;
$next = 0;
// import user upgrade definitions
if ($start == 0)
{
$upgrades = $sDb->fetchAll('
SELECT *
FROM xf_user_upgrade
ORDER BY user_upgrade_id
');
if (!$upgrades)
{
return true;
}
$upgradeMap = array();
XenForo_Db::beginTransaction();
foreach ($upgrades AS $upgrade)
{
$import = $this->_quickAssembleData($upgrade, array(
'title',
'description',
'display_order',
'extra_group_ids' => $this->_translateUserGroupIdList($upgrade['extra_group_ids']),
'recurring',
'cost_amount',
'cost_currency',
'length_amount',
'length_unit',
'disabled_upgrade_ids' => $this->_mapDisabledUpgradeIds($upgradeMap, $upgrade['disabled_upgrade_ids']),
'can_purchase'
));
$newUpgradeId = $model->importUserUpgradeDefinition($upgrade['user_upgrade_id'], $import);
if ($newUpgradeId)
{
$upgradeMap[$upgrade['user_upgrade_id']] = $newUpgradeId;
$total++;
}
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
}
$total = 0;
// import user upgrades
if ($options['max'] === false)
{
$options['max'] = $sDb->fetchOne('
SELECT MAX(user_upgrade_record_id)
FROM xf_user_upgrade_active
');
}
$activeUpgrades = $sDb->fetchAll($sDb->limit(
'
SELECT uua.*,
uu.extra_group_ids
FROM xf_user_upgrade_active AS uua
INNER JOIN xf_user_upgrade AS uu ON
(uu.user_upgrade_id = uua.user_upgrade_id)
WHERE uua.user_upgrade_record_id > ' . $sDb->quote($start) . '
', $options['limit']
));
if (!$activeUpgrades)
{
return true;
}
$userIdMap = $model->getUserIdsMapFromArray($activeUpgrades, 'user_id');
if (empty($upgradeMap))
{
$upgradeMap = $model->getImportContentMap('user_upgrade');
}
XenForo_Db::beginTransaction();
$extraGroupIdsCache = array();
foreach ($activeUpgrades AS $activeUpgrade)
{
$next = $activeUpgrade['user_upgrade_record_id'];
$userId = $this->_mapLookUp($userIdMap, $activeUpgrade['user_id']);
if (!$userId)
{
continue;
}
$upgradeId = $this->_mapLookUp($upgradeMap, $activeUpgrade['user_upgrade_id']);
if (!$upgradeId)
{
continue;
}
$import = $this->_quickAssembleData($activeUpgrade, array(
'user_id' => $userId,
'user_upgrade_id' => $upgradeId,
'extra',
'start_date',
'end_date'
));
if (!isset($extraGroupIdsCache[$activeUpgrade['extra_group_ids']]))
{
$extraGroupIdsCache[$activeUpgrade['extra_group_ids']] = $this->_translateUserGroupIdList($activeUpgrade['extra_group_ids']);
}
$model->importActiveUserUpgrade($import, $extraGroupIdsCache[$activeUpgrade['extra_group_ids']]);
$total++;
}
XenForo_Db::commit();
$this->_session->incrementStepImportTotal($total);
return array($next, $options, $this->_getProgressOutput($next, $options['max']));
}
protected function _mapDisabledUpgradeIds($map, $idString)
{
$output = array();
foreach (preg_split('/s*,s*/si', $idString, -1, PREG_SPLIT_NO_EMPTY) AS $id)
{
if ($newId = $this->_mapLookUp($map, $id))
{
$output[] = $id;
}
}
return implode(',', $output);
}
/*
* drafts
* feeds
* news feed
* notices
* smilies
* trophies
* user alerts
* user group promotions
*/
}