/** * Export the attachments as Media. * * In vBulletin 4.x, the filedata table was introduced. */ public function ExportMedia($MinDiscussionID = false) { $Ex = $this->Ex; $instance = $this; if ($MinDiscussionID) { $DiscussionWhere = "and t.threadid > {$MinDiscussionID}"; } else { $DiscussionWhere = ''; } $Media_Map = array('attachmentid' => 'MediaID', 'filename' => 'Name', 'filesize' => 'Size', 'userid' => 'InsertUserID', 'extension' => array('Column' => 'Type', 'Filter' => array($this, 'BuildMimeType')), 'filehash' => array('Column' => 'Path', 'Filter' => array($this, 'BuildMediaPath')), 'filethumb' => array('Column' => 'ThumbPath', 'Filter' => function ($Value, $Field, $Row) use($instance) { $MimeType = $instance->BuildMimeType($Row['extension'], $Field, $Row); if (substr($MimeType, 0, 6) == 'image/') { return $instance->BuildMediaPath($Value, $Field, $Row); } else { return null; } }), 'height' => array('Column' => 'ImageHeight', 'Filter' => array($this, 'BuildMediaDimension')), 'width' => array('Column' => 'ImageWidth', 'Filter' => array($this, 'BuildMediaDimension'))); // Add hash fields if they exist (from 2.x) $AttachColumns = array('hash', 'filehash'); $Missing = $Ex->Exists('attachment', $AttachColumns); $AttachColumnsString = ''; foreach ($AttachColumns as $ColumnName) { if (in_array($ColumnName, $Missing)) { $AttachColumnsString .= ", null as {$ColumnName}"; } else { $AttachColumnsString .= ", a.{$ColumnName}"; } } // Do the export if ($Ex->Exists('attachment', array('contenttypeid', 'contentid')) === true) { // Exporting 4.x with 'filedata' table. // Build an index to join on. $Result = $Ex->Query('show index from :_thread where Key_name = "ix_thread_firstpostid"'); if (!$Result) { $Ex->Query('create index ix_thread_firstpostid on :_thread (firstpostid)'); } $MediaSql = "select\n case when t.threadid is not null then 'discussion' when ct.class = 'Post' then 'comment' when ct.class = 'Thread' then 'discussion' else ct.class end as ForeignTable,\n case when t.threadid is not null then t.threadid else a.contentid end as ForeignID,\n FROM_UNIXTIME(a.dateline) as DateInserted,\n 'local' as StorageMethod,\n a.*,\n f.extension, f.filesize {$AttachColumnsString},\n f.width, f.height, null as filethumb\n from :_attachment a\n join :_contenttype ct\n on a.contenttypeid = ct.contenttypeid\n join :_filedata f\n on f.filedataid = a.filedataid\n left join :_thread t\n on t.firstpostid = a.contentid and a.contenttypeid = 1\n where a.contentid > 0\n {$DiscussionWhere}"; $Ex->ExportTable('Media', $MediaSql, $Media_Map); } else { // Exporting 3.x without 'filedata' table. // Do NOT grab every field to avoid 'filedata' blob in 3.x. // Left join 'attachment' because we can't left join 'thread' on firstpostid (not an index). // Lie about the height & width to spoof FileUpload serving generic thumbnail if they aren't set. $Extension = ExportModel::FileExtension('a.filename'); $MediaSql = "select a.attachmentid, a.filename, {$Extension} as extension {$AttachColumnsString}, a.userid,\n 'local' as StorageMethod,\n 'discussion' as ForeignTable,\n t.threadid as ForeignID,\n FROM_UNIXTIME(a.dateline) as DateInserted,\n '1' as height,\n '1' as width,\n null as filethumb\n from :_thread t\n left join :_attachment a ON a.postid = t.firstpostid\n where a.attachmentid > 0\n\n union all\n\n select a.attachmentid, a.filename, {$Extension} as extension {$AttachColumnsString}, a.userid,\n 'local' as StorageMethod,\n 'comment' as ForeignTable,\n a.postid as ForeignID,\n FROM_UNIXTIME(a.dateline) as DateInserted,\n '1' as height,\n '1' as width\n from :_post p\n inner join :_thread t ON p.threadid = t.threadid\n left join :_attachment a ON a.postid = p.postid\n where p.postid <> t.firstpostid and a.attachmentid > 0\n "; $Ex->ExportTable('Media', $MediaSql, $Media_Map); } // files named .attach need to be named properly. // file needs to be renamed and db updated. // if its an images; we need to include .thumb $attachmentPath = $this->Param('filepath'); if ($attachmentPath) { $missingFiles = array(); if (is_dir($attachmentPath)) { $Ex->Comment("Checking files"); $Result = $Ex->Query($MediaSql); while ($row = mysql_fetch_assoc($Result)) { $filePath = $this->BuildMediaPath('', '', $row); $cdn = $this->Param('cdn', ''); if (!empty($cdn)) { $filePath = str_replace($cdn, '', $filePath); } $fullPath = $attachmentPath . $filePath; if (file_exists($fullPath)) { continue; } //check if named .attach $p = explode('.', $fullPath); $attachFilename = str_replace(end($p), 'attach', $fullPath); if (file_exists($attachFilename)) { // rename file rename($attachFilename, $fullPath); continue; } //check if md5 hash in root if (GetValue('hash', $row)) { $md5Filename = $attachmentPath . $row['hash'] . '.' . $row['extension']; if (file_exists($md5Filename)) { // rename file rename($md5Filename, $fullPath); continue; } } $missingFiles[] = $filePath; } } else { $Ex->Comment('Attachment Path not found'); } $totalMissingFiles = count($missingFiles); if ($totalMissingFiles > 0) { $Ex->Comment('Missing files detected. See ./missing_files.txt for full list.'); $Ex->Comment(sprintf('Total missing files %d', $totalMissingFiles)); file_put_contents('missing-files.txt', implode("\n", $missingFiles)); } } }