/** * 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) { $filteredData = $this->filterThumbnailData($value, $field, $row); if ($filteredData) { return $instance->buildMediaPath($value, $field, $row); } else { return null; } }), 'thumb_width' => array('Column' => 'ThumbWidth', 'Filter' => array($this, 'filterThumbnailData')), '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 = "\n select\n case\n when t.threadid is not null then 'discussion'\n when ct.class = 'Post' then 'comment'\n when ct.class = 'Thread' then 'discussion'\n else ct.class\n end as ForeignTable,\n case\n when t.threadid is not null then t.threadid\n else a.contentid\n end as ForeignID,\n FROM_UNIXTIME(a.dateline) as DateInserted,\n a.*,\n f.extension,\n f.filesize/*,*/\n {$attachColumnsString},\n f.width,\n f.height,\n 'mock_value' as filethumb,\n 128 as thumb_width\n from :_attachment a\n join :_contenttype ct on a.contenttypeid = ct.contenttypeid\n join :_filedata f on f.filedataid = a.filedataid\n left join :_thread t on t.firstpostid = a.contentid and a.contenttypeid = 1\n where a.contentid > 0\n {$discussionWhere}\n "; $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 = "\n select\n a.attachmentid,\n a.filename,\n {$extension} as extension/*,*/\n {$attachColumnsString},\n a.userid,\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 'mock_value' as filethumb,\n 128 as thumb_width\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\n a.attachmentid,\n a.filename,\n {$extension} as extension/*,*/\n {$attachColumnsString},\n a.userid,\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 'mock_value' as filethumb,\n 128 as thumb_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)); } } }