/** * Maintenance function to move attachments from one directory to another */ public function action_transfer() { global $modSettings, $txt; checkSession(); // We will need the functions from here require_once SUBSDIR . '/Attachments.subs.php'; require_once SUBSDIR . '/ManageAttachments.subs.php'; // The list(s) of directory's that are available. $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); if (!empty($modSettings['attachment_basedirectories'])) { $modSettings['attachment_basedirectories'] = unserialize($modSettings['attachment_basedirectories']); } else { $modSettings['basedirectory_for_attachments'] = array(); } // Clean the inputs $_POST['from'] = (int) $_POST['from']; $_POST['auto'] = !empty($_POST['auto']) ? (int) $_POST['auto'] : 0; $_POST['to'] = (int) $_POST['to']; $start = !empty($_POST['empty_it']) ? 0 : $modSettings['attachmentDirFileLimit']; $_SESSION['checked'] = !empty($_POST['empty_it']) ? true : false; // Prepare for the moving $limit = 501; $results = array(); $dir_files = 0; $current_progress = 0; $total_moved = 0; $total_not_moved = 0; // Need to know where we are moving things from if (empty($_POST['from']) || empty($_POST['auto']) && empty($_POST['to'])) { $results[] = $txt['attachment_transfer_no_dir']; } // Same location, that's easy if ($_POST['from'] == $_POST['to']) { $results[] = $txt['attachment_transfer_same_dir']; } // No errors so determine how many we may have to move if (empty($results)) { // Get the total file count for the progress bar. $total_progress = getFolderAttachmentCount($_POST['from']); $total_progress -= $start; if ($total_progress < 1) { $results[] = $txt['attachment_transfer_no_find']; } } // Nothing to move (no files in source or below the max limit) if (empty($results)) { // Moving them automaticaly? if (!empty($_POST['auto'])) { $modSettings['automanage_attachments'] = 1; // Create sub directroys off the root or from an attachment directory? $modSettings['use_subdirectories_for_attachments'] = $_POST['auto'] == -1 ? 0 : 1; $modSettings['basedirectory_for_attachments'] = $_POST['auto'] > 0 ? $modSettings['attachmentUploadDir'][$_POST['auto']] : $modSettings['basedirectory_for_attachments']; // Finaly, where do they need to go automanage_attachments_check_directory(); $new_dir = $modSettings['currentAttachmentUploadDir']; } else { $new_dir = $_POST['to']; } $modSettings['currentAttachmentUploadDir'] = $new_dir; $break = false; while ($break === false) { @set_time_limit(300); if (function_exists('apache_reset_timeout')) { @apache_reset_timeout(); } // If limits are set, get the file count and size for the destination folder if ($dir_files <= 0 && (!empty($modSettings['attachmentDirSizeLimit']) || !empty($modSettings['attachmentDirFileLimit']))) { $current_dir = attachDirProperties($new_dir); $dir_files = $current_dir['files']; $dir_size = $current_dir['size']; } // Find some attachments to move list($tomove_count, $tomove) = findAttachmentsToMove($_POST['from'], $start, $limit); // Nothing found to move if ($tomove_count === 0) { if (empty($current_progress)) { $results[] = $txt['attachment_transfer_no_find']; } break; } // No more to move after this batch then set the finished flag. if ($tomove_count < $limit) { $break = true; } // Move them $moved = array(); foreach ($tomove as $row) { $source = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); $dest = $modSettings['attachmentUploadDir'][$new_dir] . '/' . basename($source); // Size and file count check if (!empty($modSettings['attachmentDirSizeLimit']) || !empty($modSettings['attachmentDirFileLimit'])) { $dir_files++; $dir_size += !empty($row['size']) ? $row['size'] : filesize($source); // If we've reached a directory limit. Do something if we are in auto mode, otherwise set an error. if (!empty($modSettings['attachmentDirSizeLimit']) && $dir_size > $modSettings['attachmentDirSizeLimit'] * 1024 || !empty($modSettings['attachmentDirFileLimit']) && $dir_files > $modSettings['attachmentDirFileLimit']) { // Since we're in auto mode. Create a new folder and reset the counters. if (!empty($_POST['auto'])) { automanage_attachments_by_space(); $results[] = sprintf($txt['attachments_transfered'], $total_moved, $modSettings['attachmentUploadDir'][$new_dir]); if (!empty($total_not_moved)) { $results[] = sprintf($txt['attachments_not_transfered'], $total_not_moved); } $dir_files = 0; $total_moved = 0; $total_not_moved = 0; $break = false; break; } else { $results[] = $txt['attachment_transfer_no_room']; $break = true; break; } } } // Actually move the file if (@rename($source, $dest)) { $total_moved++; $current_progress++; $moved[] = $row['id_attach']; } else { $total_not_moved++; } } // Update the database to reflect the new file location if (!empty($moved)) { moveAttachments($moved, $new_dir); } $new_dir = $modSettings['currentAttachmentUploadDir']; // Create / update the progress bar. // @todo why was this done this way? if (!$break) { $percent_done = min(round($current_progress / $total_progress * 100, 0), 100); $prog_bar = ' <div class="progress_bar"> <div class="full_bar">' . $percent_done . '%</div> <div class="green_percent" style="width: ' . $percent_done . '%;"> </div> </div>'; // Write it to a file so it can be displayed $fp = fopen(BOARDDIR . '/progress.php', 'w'); fwrite($fp, $prog_bar); fclose($fp); usleep(500000); } } $results[] = sprintf($txt['attachments_transfered'], $total_moved, $modSettings['attachmentUploadDir'][$new_dir]); if (!empty($total_not_moved)) { $results[] = sprintf($txt['attachments_not_transfered'], $total_not_moved); } } // All done, time to clean up $_SESSION['results'] = $results; if (file_exists(BOARDDIR . '/progress.php')) { unlink(BOARDDIR . '/progress.php'); } redirectexit('action=admin;area=manageattachments;sa=maintenance#transfer'); }
/** * Create an attachment, with the given array of parameters. * * What it does: * - Adds any addtional or missing parameters to $attachmentOptions. * - Renames the temporary file. * - Creates a thumbnail if the file is an image and the option enabled. * * @package Attachments * @param mixed[] $attachmentOptions associative array of options */ function createAttachment(&$attachmentOptions) { global $modSettings, $context; $db = database(); require_once SUBSDIR . '/Graphics.subs.php'; // These are the only valid image types. $validImageTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 5 => 'psd', 6 => 'bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpeg', 14 => 'iff'); // If this is an image we need to set a few additional parameters. $size = @getimagesize($attachmentOptions['tmp_name']); list($attachmentOptions['width'], $attachmentOptions['height']) = $size; // If it's an image get the mime type right. if (empty($attachmentOptions['mime_type']) && $attachmentOptions['width']) { // Got a proper mime type? if (!empty($size['mime'])) { $attachmentOptions['mime_type'] = $size['mime']; } elseif (isset($validImageTypes[$size[2]])) { $attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]]; } } // It is possible we might have a MIME type that isn't actually an image but still have a size. // For example, Shockwave files will be able to return size but be 'application/shockwave' or similar. if (!empty($attachmentOptions['mime_type']) && strpos($attachmentOptions['mime_type'], 'image/') !== 0) { $attachmentOptions['width'] = 0; $attachmentOptions['height'] = 0; } // Get the hash if no hash has been given yet. if (empty($attachmentOptions['file_hash'])) { $attachmentOptions['file_hash'] = getAttachmentFilename($attachmentOptions['name'], 0, null, true); } // Assuming no-one set the extension let's take a look at it. if (empty($attachmentOptions['fileext'])) { $attachmentOptions['fileext'] = strtolower(strrpos($attachmentOptions['name'], '.') !== false ? substr($attachmentOptions['name'], strrpos($attachmentOptions['name'], '.') + 1) : ''); if (strlen($attachmentOptions['fileext']) > 8 || '.' . $attachmentOptions['fileext'] == $attachmentOptions['name']) { $attachmentOptions['fileext'] = ''; } } $db->insert('', '{db_prefix}attachments', array('id_folder' => 'int', 'id_msg' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-40', 'fileext' => 'string-8', 'size' => 'int', 'width' => 'int', 'height' => 'int', 'mime_type' => 'string-20', 'approved' => 'int'), array((int) $attachmentOptions['id_folder'], (int) $attachmentOptions['post'], $attachmentOptions['name'], $attachmentOptions['file_hash'], $attachmentOptions['fileext'], (int) $attachmentOptions['size'], empty($attachmentOptions['width']) ? 0 : (int) $attachmentOptions['width'], empty($attachmentOptions['height']) ? '0' : (int) $attachmentOptions['height'], !empty($attachmentOptions['mime_type']) ? $attachmentOptions['mime_type'] : '', (int) $attachmentOptions['approved']), array('id_attach')); $attachmentOptions['id'] = $db->insert_id('{db_prefix}attachments', 'id_attach'); // @todo Add an error here maybe? if (empty($attachmentOptions['id'])) { return false; } // Now that we have the attach id, let's rename this and finish up. $attachmentOptions['destination'] = getAttachmentFilename(basename($attachmentOptions['name']), $attachmentOptions['id'], $attachmentOptions['id_folder'], false, $attachmentOptions['file_hash']); rename($attachmentOptions['tmp_name'], $attachmentOptions['destination']); // If it's not approved then add to the approval queue. if (!$attachmentOptions['approved']) { $db->insert('', '{db_prefix}approval_queue', array('id_attach' => 'int', 'id_msg' => 'int'), array($attachmentOptions['id'], (int) $attachmentOptions['post']), array()); } if (empty($modSettings['attachmentThumbnails']) || empty($attachmentOptions['width']) && empty($attachmentOptions['height'])) { return true; } // Like thumbnails, do we? if (!empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachmentOptions['width'] > $modSettings['attachmentThumbWidth'] || $attachmentOptions['height'] > $modSettings['attachmentThumbHeight'])) { if (createThumbnail($attachmentOptions['destination'], $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // Figure out how big we actually made it. $size = @getimagesize($attachmentOptions['destination'] . '_thumb'); list($thumb_width, $thumb_height) = $size; if (!empty($size['mime'])) { $thumb_mime = $size['mime']; } elseif (isset($validImageTypes[$size[2]])) { $thumb_mime = 'image/' . $validImageTypes[$size[2]]; } else { $thumb_mime = ''; } $thumb_filename = $attachmentOptions['name'] . '_thumb'; $thumb_size = filesize($attachmentOptions['destination'] . '_thumb'); $thumb_file_hash = getAttachmentFilename($thumb_filename, 0, null, true); $thumb_path = $attachmentOptions['destination'] . '_thumb'; // We should check the file size and count here since thumbs are added to the existing totals. if (!empty($modSettings['automanage_attachments']) && $modSettings['automanage_attachments'] == 1 && !empty($modSettings['attachmentDirSizeLimit']) || !empty($modSettings['attachmentDirFileLimit'])) { $context['dir_size'] = isset($context['dir_size']) ? $context['dir_size'] += $thumb_size : ($context['dir_size'] = 0); $context['dir_files'] = isset($context['dir_files']) ? $context['dir_files']++ : ($context['dir_files'] = 0); // If the folder is full, try to create a new one and move the thumb to it. if ($context['dir_size'] > $modSettings['attachmentDirSizeLimit'] * 1024 || $context['dir_files'] + 2 > $modSettings['attachmentDirFileLimit']) { if (automanage_attachments_by_space()) { rename($thumb_path, $context['attach_dir'] . '/' . $thumb_filename); $thumb_path = $context['attach_dir'] . '/' . $thumb_filename; $context['dir_size'] = 0; $context['dir_files'] = 0; } } } // If a new folder has been already created. Gotta move this thumb there then. if ($modSettings['currentAttachmentUploadDir'] != $attachmentOptions['id_folder']) { rename($thumb_path, $context['attach_dir'] . '/' . $thumb_filename); $thumb_path = $context['attach_dir'] . '/' . $thumb_filename; } // To the database we go! $db->insert('', '{db_prefix}attachments', array('id_folder' => 'int', 'id_msg' => 'int', 'attachment_type' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-40', 'fileext' => 'string-8', 'size' => 'int', 'width' => 'int', 'height' => 'int', 'mime_type' => 'string-20', 'approved' => 'int'), array($modSettings['currentAttachmentUploadDir'], (int) $attachmentOptions['post'], 3, $thumb_filename, $thumb_file_hash, $attachmentOptions['fileext'], $thumb_size, $thumb_width, $thumb_height, $thumb_mime, (int) $attachmentOptions['approved']), array('id_attach')); $attachmentOptions['thumb'] = $db->insert_id('{db_prefix}attachments', 'id_attach'); if (!empty($attachmentOptions['thumb'])) { $db->query('', ' UPDATE {db_prefix}attachments SET id_thumb = {int:id_thumb} WHERE id_attach = {int:id_attach}', array('id_thumb' => $attachmentOptions['thumb'], 'id_attach' => $attachmentOptions['id'])); rename($thumb_path, getAttachmentFilename($thumb_filename, $attachmentOptions['thumb'], $modSettings['currentAttachmentUploadDir'], false, $thumb_file_hash)); } } } return true; }