/** * Export each table one at a time. * * @param ExportModel $Ex */ protected function ForumExport($Ex) { // Allow limited export of 1 category via ?forumid=ID $ForumID = $this->Param('forumid'); if ($ForumID) { $ForumWhere = ' and t.forumid ' . (strpos($ForumID, ', ') === false ? "= {$ForumID}" : "in ({$ForumID})"); } else { $ForumWhere = ''; } // Determine the character set $CharacterSet = $Ex->GetCharacterSet('post'); if ($CharacterSet) { $Ex->CharacterSet = $CharacterSet; } // Begin $Ex->BeginExport('', 'vBulletin 3.* and 4.*'); $this->ExportBlobs($this->Param('files'), $this->Param('avatars'), $ForumWhere); if ($this->Param('noexport')) { $Ex->Comment('Skipping the export.'); $Ex->EndExport(); return; } // Check to see if there is a max date. $MinDate = $this->Param('mindate'); if ($MinDate) { $MinDate = strtotime($MinDate); $Ex->Comment("Min topic date ({$MinDate}): " . date('c', $MinDate)); } $Now = time(); $cdn = $this->Param('cdn', ''); // Grab all of the ranks. $Ranks = $Ex->Get("select * from :_usertitle order by minposts desc", 'usertitleid'); // Users $User_Map = array('userid' => 'UserID', 'username' => 'Name', 'password2' => 'Password', 'email' => 'Email', 'referrerid' => 'InviteUserID', 'timezoneoffset' => 'HourOffset', 'ipaddress' => 'LastIPAddress', 'ipaddress2' => 'InsertIPAddress', 'usertitle' => array('Column' => 'Title', 'Filter' => function ($Value) { return trim(strip_tags(str_replace(' ', ' ', $Value))); }), 'posts' => array('Column' => 'RankID', 'Filter' => function ($Value) use($Ranks) { // Look up the posts in the ranks table. foreach ($Ranks as $RankID => $Row) { if ($Value >= $Row['minposts']) { return $RankID; } } return null; })); // Use file avatar or the result of our blob export? if ($this->GetConfig('usefileavatar')) { $User_Map['filephoto'] = 'Photo'; } else { $User_Map['customphoto'] = 'Photo'; } $Ex->ExportTable('User', "select u.*,\n ipaddress as ipaddress2,\n concat(`password`, salt) as password2,\n DATE_FORMAT(birthday_search,GET_FORMAT(DATE,'ISO')) as DateOfBirth,\n FROM_UNIXTIME(joindate) as DateFirstVisit,\n FROM_UNIXTIME(lastvisit) as DateLastActive,\n FROM_UNIXTIME(joindate) as DateInserted,\n FROM_UNIXTIME(lastactivity) as DateUpdated,\n case when avatarrevision > 0 then concat('{$cdn}', 'userpics/avatar', u.userid, '_', avatarrevision, '.gif')\n when av.avatarpath is not null then av.avatarpath\n else null\n end as filephoto,\n {$this->AvatarSelect},\n case when ub.userid is not null then 1 else 0 end as Banned,\n 'vbulletin' as HashMethod\n from :_user u\n left join :_customavatar a\n on u.userid = a.userid\n left join :_avatar av\n on u.avatarid = av.avatarid\n left join :_userban ub\n on u.userid = ub.userid and ub.liftdate <= now() ", $User_Map); // ":_" will be replace by database prefix // Roles $Role_Map = array('usergroupid' => 'RoleID', 'title' => 'Name', 'description' => 'Description'); $Ex->ExportTable('Role', 'select * from :_usergroup', $Role_Map); // UserRoles $UserRole_Map = array('userid' => 'UserID', 'usergroupid' => 'RoleID'); $Ex->Query("CREATE TEMPORARY TABLE VbulletinRoles (userid INT UNSIGNED NOT NULL, usergroupid INT UNSIGNED NOT NULL)"); # Put primary groups into tmp table $Ex->Query("insert into VbulletinRoles (userid, usergroupid) select userid, usergroupid from :_user"); # Put stupid CSV column into tmp table $SecondaryRoles = $Ex->Query("select userid, usergroupid, membergroupids from :_user", true); if (is_resource($SecondaryRoles)) { while (($Row = @mysql_fetch_assoc($SecondaryRoles)) !== false) { if ($Row['membergroupids'] != '') { $Groups = explode(',', $Row['membergroupids']); foreach ($Groups as $GroupID) { if (!$GroupID) { continue; } $Ex->Query("insert into VbulletinRoles (userid, usergroupid) values({$Row['userid']},{$GroupID})", true); } } } } # Export from our tmp table and drop $Ex->ExportTable('UserRole', 'select distinct userid, usergroupid from VbulletinRoles', $UserRole_Map); $Ex->Query("DROP TABLE IF EXISTS VbulletinRoles"); // Permissions. $Permissions_Map = array('usergroupid' => 'RoleID', 'title' => array('Column' => 'Garden.SignIn.Allow', 'Filter' => array($this, 'SignInPermission')), 'genericpermissions' => array('Column' => 'GenericPermissions', 'type' => 'int'), 'forumpermissions' => array('Column' => 'ForumPermissions', 'type' => 'int')); $this->AddPermissionColumns(self::$Permissions, $Permissions_Map); $Ex->ExportTable('Permission', 'select * from :_usergroup', $Permissions_Map); // $Ex->EndExport(); // return; // UserMeta $Ex->Query("CREATE TEMPORARY TABLE VbulletinUserMeta (`UserID` INT NOT NULL ,`Name` VARCHAR( 255 ) NOT NULL ,`Value` text NOT NULL)"); # Standard vB user data $UserFields = array('usertitle' => 'Title', 'homepage' => 'Website', 'skype' => 'Skype', 'styleid' => 'StyleID'); foreach ($UserFields as $Field => $InsertAs) { $Ex->Query("insert into VbulletinUserMeta (UserID, Name, Value) select userid, 'Profile.{$InsertAs}', {$Field} from :_user where {$Field} != ''"); } # Dynamic vB user data (userfield) $ProfileFields = $Ex->Query("select varname, text from :_phrase where product='vbulletin' and fieldname='cprofilefield' and varname like 'field%_title'"); if (is_resource($ProfileFields)) { $ProfileQueries = array(); while ($Field = @mysql_fetch_assoc($ProfileFields)) { $Column = str_replace('_title', '', $Field['varname']); $Name = preg_replace('/[^a-zA-Z0-9\\s_-]/', '', $Field['text']); $ProfileQueries[] = "insert into VbulletinUserMeta (UserID, Name, Value)\n select userid, 'Profile." . $Name . "', " . $Column . " from :_userfield where " . $Column . " != ''"; } foreach ($ProfileQueries as $Query) { $Ex->Query($Query); } } // Signatures $Sql = "\n select\n userid as UserID,\n 'Plugin.Signatures.Sig' as Name,\n signature as Value\n from :_usertextfield\n where nullif(signature, '') is not null\n\n union\n\n select\n userid,\n 'Plugin.Signatures.Format',\n 'BBCode'\n from :_usertextfield\n where nullif(signature, '') is not null"; $Ex->ExportTable('UserMeta', $Sql); // Ranks $Rank_Map = array('usertitleid' => 'RankID', 'title' => 'Name', 'title2' => 'Label', 'minposts' => array('Column' => 'Attributes', 'Filter' => function ($Value) { $Result = array('Criteria' => array('CountPosts' => $Value)); return serialize($Result); }), 'level' => array('Column' => 'Level', 'Filter' => function ($Value) { static $Level = 1; return $Level++; })); $Ex->ExportTable('Rank', "\n select ut.*, ut.title as title2, 0 as level\n from :_usertitle ut\n order by ut.minposts", $Rank_Map); // Categories $Category_Map = array('forumid' => 'CategoryID', 'description' => 'Description', 'Name2' => array('Column' => 'Name', 'Filter' => 'HTMLDecoder'), 'displayorder' => array('Column' => 'Sort', 'Type' => 'int'), 'parentid' => 'ParentCategoryID'); $Ex->ExportTable('Category', "select f.*, title as Name2\n from :_forum f\n where 1 = 1 {$ForumWhere}", $Category_Map); $MinDiscussionID = false; $MinDiscussionWhere = false; if ($MinDate) { $MinDiscussionID = $Ex->GetValue("\n select max(threadid)\n from :_thread\n where dateline < {$MinDate}\n ", false); $MinDiscussionID2 = $Ex->GetValue("\n select min(threadid)\n from :_thread\n where dateline >= {$MinDate}\n ", false); // The two discussion IDs should be the same, but let's average them. $MinDiscussionID = floor(($MinDiscussionID + $MinDiscussionID2) / 2); $Ex->Comment('Min topic id: ' . $MinDiscussionID); } // Discussions $Discussion_Map = array('threadid' => 'DiscussionID', 'forumid' => 'CategoryID', 'postuserid' => 'InsertUserID', 'postuserid2' => 'UpdateUserID', 'title' => array('Column' => 'Name', 'Filter' => 'HTMLDecoder'), 'Format' => 'Format', 'views' => 'CountViews', 'ipaddress' => 'InsertIPAddress'); if ($Ex->Destination == 'database') { // Remove the filter from the title so that this doesn't take too long. $Ex->HTMLDecoderDb('thread', 'title', 'threadid'); unset($Discussion_Map['title']['Filter']); } if ($MinDiscussionID) { $MinDiscussionWhere = "and t.threadid > {$MinDiscussionID}"; } $Ex->ExportTable('Discussion', "select t.*,\n t.postuserid as postuserid2,\n p.ipaddress,\n p.pagetext as Body,\n 'BBCode' as Format,\n replycount+1 as CountComments,\n convert(ABS(open-1),char(1)) as Closed,\n if(convert(sticky,char(1))>0,2,0) as Announce,\n FROM_UNIXTIME(t.dateline) as DateInserted,\n FROM_UNIXTIME(lastpost) as DateUpdated,\n FROM_UNIXTIME(lastpost) as DateLastComment\n from :_thread t\n left join :_deletionlog d on (d.type='thread' and d.primaryid=t.threadid)\n left join :_post p on p.postid = t.firstpostid\n where d.primaryid is null\n and t.visible = 1\n {$MinDiscussionWhere}\n {$ForumWhere}", $Discussion_Map); // Comments $Comment_Map = array('postid' => 'CommentID', 'threadid' => 'DiscussionID', 'pagetext' => 'Body', 'Format' => 'Format', 'ipaddress' => 'InsertIPAddress'); if ($MinDiscussionID) { $MinDiscussionWhere = "and p.threadid > {$MinDiscussionID}"; } $Ex->ExportTable('Comment', "select p.*,\n 'BBCode' as Format,\n p.userid as InsertUserID,\n p.userid as UpdateUserID,\n FROM_UNIXTIME(p.dateline) as DateInserted,\n FROM_UNIXTIME(p.dateline) as DateUpdated\n from :_post p\n inner join :_thread t\n on p.threadid = t.threadid\n left join :_deletionlog d\n on (d.type='post' and d.primaryid=p.postid)\n where p.postid <> t.firstpostid\n and d.primaryid is null\n and p.visible = 1\n {$MinDiscussionWhere}\n {$ForumWhere}", $Comment_Map); // UserDiscussion if ($MinDiscussionID) { $MinDiscussionWhere = "where st.threadid > {$MinDiscussionID}"; } $Ex->ExportTable('UserDiscussion', "select\n st.userid as UserID,\n st.threadid as DiscussionID,\n '1' as Bookmarked,\n FROM_UNIXTIME(tr.readtime) as DateLastViewed\n from :_subscribethread st\n left join :_threadread tr on tr.userid = st.userid and tr.threadid = st.threadid\n {$MinDiscussionWhere}"); /*$Ex->ExportTable('UserDiscussion', "select tr.userid as UserID, tr.threadid as DiscussionID, FROM_UNIXTIME(tr.readtime) as DateLastViewed, case when st.threadid is not null then 1 else 0 end as Bookmarked from :_threadread tr left join :_subscribethread st on tr.userid = st.userid and tr.threadid = st.threadid");*/ // Activity (from visitor messages in vBulletin 3.8+) if ($Ex->Exists('visitormessage')) { if ($MinDiscussionID) { $MinDiscussionWhere = "and dateline > {$MinDiscussionID}"; } $Activity_Map = array('postuserid' => 'RegardingUserID', 'userid' => 'ActivityUserID', 'pagetext' => 'Story', 'NotifyUserID' => 'NotifyUserID', 'Format' => 'Format'); $Ex->ExportTable('Activity', "select *,\n '{RegardingUserID,you} → {ActivityUserID,you}' as HeadlineFormat,\n FROM_UNIXTIME(dateline) as DateInserted,\n FROM_UNIXTIME(dateline) as DateUpdated,\n INET_NTOA(ipaddress) as InsertIPAddress,\n postuserid as InsertUserID,\n -1 as NotifyUserID,\n 'BBCode' as Format,\n 'WallPost' as ActivityType\n from :_visitormessage\n where state='visible'\n {$MinDiscussionWhere}", $Activity_Map); } $this->_ExportConversations($MinDate); $this->_ExportPolls(); // Media if ($Ex->Exists('attachment')) { $this->ExportMedia($MinDiscussionID); } // IP Ban list $IpBanlist = $this->Param('ipbanlist'); if ($IpBanlist) { $Ex->Query("DROP TABLE IF EXISTS `z_ipbanlist` "); $Ex->Query("CREATE TABLE `z_ipbanlist` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n `ipaddress` varchar(50) DEFAULT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `ipaddress` (`ipaddress`)\n\n ) ENGINE=InnoDB DEFAULT CHARSET=utf8"); $Result = $Ex->Query("select value from :_setting where varname = 'banip'"); $Row = mysql_fetch_assoc($Result); if ($Row) { $InsertSql = 'INSERT IGNORE INTO `z_ipbanlist` (`ipaddress`) values '; $IpString = str_replace("\r", "", $Row['value']); $IPs = explode("\n", $IpString); foreach ($IPs as $IP) { $IP = trim($IP); if (empty($IP)) { continue; } $InsertSql .= '(\'' . mysql_real_escape_string($IP) . '\'), '; } $InsertSql = substr($InsertSql, 0, -2); $Ex->Query($InsertSql); $Ban_Map = array(); $Ex->ExportTable('Ban', "select 'IPAddress' as BanType, ipaddress as BanValue, 'Imported ban' as Notes, NOW() as DateInserted\n FROM `z_ipbanlist`", $Ban_Map); $Ex->Query('DROP table if exists `z_ipbanlist` '); } } // End $Ex->EndExport(); }