'ManageAttachmentSettings', 'avatars' => 'ManageAvatarSettings', 'browse' => 'BrowseFiles', 'byAge' => 'RemoveAttachmentByAge', 'bySize' => 'RemoveAttachmentBySize', 'maintenance' => 'MaintainFiles', 'moveAvatars' => 'MoveAvatars', 'repair' => 'RepairAttachments', 'remove' => 'RemoveAttachment', 'removeall' => 'RemoveAllAttachments' ); loadTemplate('ManageAttachments'); if (isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']])) $subActions[$_REQUEST['sa']](); else ManageAttachmentSettings(); } function ManageAttachmentSettings() { global $txt, $db_prefix, $modSettings, $scripturl, $context, $options, $sourcedir; require_once($sourcedir .'/ManagePermissions.php'); $context['page_title'] = $txt['smf201']; $context['description'] = $txt['smf202']; $context['selected'] = 'attachment_settings'; $context['sub_template'] = 'attachments'; if (!empty($_POST['attachmentSettings'])) { checkSession(); updateSettings(array( 'attachmentEnable' => (int) $_POST['attachmentEnable'], 'attachmentCheckExtensions' => empty($_POST['attachmentCheckExtensions']) ? '0' : '1', 'attachmentExtensions' => $_POST['attachmentExtensions'], 'attachmentShowImages' => empty($_POST['attachmentShowImages']) ? '0' : '1', 'attachmentUploadDir' => $_POST['attachmentUploadDir'], 'attachmentDirSizeLimit' => (int) $_POST['attachmentDirSizeLimit'], 'attachmentPostLimit' => (int) $_POST['attachmentPostLimit'], 'attachmentSizeLimit' => (int) $_POST['attachmentSizeLimit'], 'attachmentNumPerPostLimit' => (int) $_POST['attachmentNumPerPostLimit'], 'attachmentThumbnails' => empty($_POST['attachmentThumbnails']) ? '0' : '1', 'attachmentThumbWidth' => (int) $_POST['attachmentThumbWidth'], 'attachmentThumbHeight' => (int) $_POST['attachmentThumbHeight'], )); } $context['valid_upload_dir'] = is_dir($modSettings['attachmentUploadDir']) && is_writable($modSettings['attachmentUploadDir']); } function ManageAvatarSettings() { global $txt, $context, $db_prefix, $modSettings, $sourcedir; $context['page_title'] = $txt['smf201']; $context['description'] = $txt['smf202']; $context['selected'] = 'avatar_settings'; $context['sub_template'] = 'avatars'; // Perform a test to see if the GD module is installed. $testGD = get_extension_funcs('gd'); $context['gd_installed'] = !empty($testGD); // We need this file for the inline permission settings. require_once($sourcedir .'/ManagePermissions.php'); // Let's save the avatar settings. if (!empty($_POST['avatarSettings'])) { checkSession(); // Store the changed mod settings. updateSettings(array( 'avatar_directory' => $_POST['avatar_directory'], 'avatar_url' => $_POST['avatar_url'], 'avatar_download_external' => empty($_POST['avatar_download_external']) ? '0' : '1', 'avatar_max_width_upload' => (int) $_POST['avatar_max_width_upload'], 'avatar_max_height_upload' => (int) $_POST['avatar_max_height_upload'], 'avatar_resize_upload' => empty($_POST['avatar_resize_upload']) ? '0' : '1', 'avatar_download_png' => empty($_POST['avatar_download_png']) ? '0' : '1', 'custom_avatar_enabled' => empty($_POST['custom_avatar_enabled']) ? '0' : '1', )); // Only update these settings if they are not disabled by JavaScript. if (empty($_POST['avatar_download_external'])) updateSettings(array( 'avatar_max_width_external' => empty($_POST['avatar_max_width_external']) ? 0 : (int) $_POST['avatar_max_width_external'], 'avatar_max_height_external' => empty($_POST['avatar_max_height_external']) ? 0 : (int) $_POST['avatar_max_height_external'], 'avatar_action_too_large' => $_POST['avatar_action_too_large'], )); if (!empty($_POST['custom_avatar_enabled'])) updateSettings(array( 'custom_avatar_dir' => $_POST['custom_avatar_dir'], 'custom_avatar_url' => $_POST['custom_avatar_url'], )); // Save the adjusted permissions. save_inline_permissions(array('profile_server_avatar', 'profile_upload_avatar', 'profile_remote_avatar')); } init_inline_permissions(array('profile_server_avatar', 'profile_upload_avatar', 'profile_remote_avatar'), array(-1)); $context['valid_avatar_dir'] = is_dir($modSettings['avatar_directory']); $context['valid_custom_avatar_dir'] = empty($modSettings['custom_avatar_enabled']) || (is_dir($modSettings['custom_avatar_dir']) && is_writable($modSettings['custom_avatar_dir'])); } function BrowseFiles() { global $context, $db_prefix, $txt, $scripturl, $options, $modSettings; $context['page_title'] = $txt['smf201']; $context['description'] = $txt['smf202']; $context['selected'] = 'browse'; $context['sub_template'] = 'browse'; // Attachments or avatars? $context['browse_type'] = isset($_REQUEST['avatars']) ? 'avatars' : (isset($_REQUEST['thumbs']) ? 'thumbs' : 'attachments'); // Get the number of attachments. $context['num_attachments'] = 0; $context['num_thumbs'] = 0; $request = db_query(" SELECT attachmentType, COUNT(*) AS num_attach FROM {$db_prefix}attachments WHERE attachmentType IN (0, 3) AND ID_MEMBER = 0 GROUP BY attachmentType", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) $context[empty($row['attachmentType']) ? 'num_attachments' : 'num_thumbs'] = $row['num_attach']; mysql_free_result($request); // Also get the avatar amount. $request = db_query(" SELECT COUNT(*) FROM {$db_prefix}attachments WHERE ID_MEMBER != 0", __FILE__, __LINE__); list ($context['num_avatars']) = mysql_fetch_row($request); mysql_free_result($request); // Allow for sorting of each column... $sort_methods = array( 'name' => 'a.filename', 'date' => $context['browse_type'] == 'avatars' ? 'mem.lastLogin' : 'm.ID_MSG', 'size' => 'a.size', 'member' => 'mem.realName' ); // Set up the importantant sorting variables... if they picked one... if (!isset($_GET['sort']) || !isset($sort_methods[$_GET['sort']])) { $_GET['sort'] = 'date'; $descending = !empty($options['view_newest_first']); } // ... and if they didn't... else $descending = isset($_GET['desc']); $context['sort_by'] = $_GET['sort']; $_GET['sort'] = $sort_methods[$_GET['sort']]; $context['sort_direction'] = $descending ? 'down' : 'up'; // Get the page index ready...... if (!isset($_REQUEST['start']) || $_REQUEST['start'] < 0) $_REQUEST['start'] = 0; $context['page_index'] = constructPageIndex($scripturl . '?action=manageattachments;sa=' . $_REQUEST['sa'] . ($context['browse_type'] == 'attachments' ? '' : ';' . $context['browse_type']) . ';sort=' . $context['sort_by'] . ($context['sort_direction'] == 'down' ? ';desc' : ''), $_REQUEST['start'], $context['num_' . $context['browse_type']], $modSettings['defaultMaxMessages']); $context['start'] = $_REQUEST['start']; // Choose a query depending on what we are viewing. if ($context['browse_type'] == 'avatars') $request = db_query(" SELECT '' AS ID_MSG, IFNULL(mem.realName, '$txt[470]') AS posterName, mem.lastLogin AS posterTime, 0 AS ID_TOPIC, a.ID_MEMBER, a.ID_ATTACH, a.filename, a.attachmentType, a.size, a.width, a.height, a.downloads, '' AS subject, 0 AS ID_BOARD FROM {$db_prefix}attachments AS a LEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = a.ID_MEMBER) WHERE a.ID_MEMBER != 0 ORDER BY $_GET[sort] " . ($descending ? 'DESC' : 'ASC') . " LIMIT $context[start], $modSettings[defaultMaxMessages]", __FILE__, __LINE__); else $request = db_query(" SELECT m.ID_MSG, IFNULL(mem.realName, m.posterName) AS posterName, m.posterTime, m.ID_TOPIC, m.ID_MEMBER, a.ID_ATTACH, a.filename, a.attachmentType, a.size, a.width, a.height, a.downloads, mf.subject, t.ID_BOARD FROM ({$db_prefix}attachments AS a, {$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}messages AS mf) LEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = m.ID_MEMBER) WHERE a.ID_MSG = m.ID_MSG AND a.attachmentType = " . ($context['browse_type'] == 'attachments' ? '0' : '3') . " AND t.ID_TOPIC = m.ID_TOPIC AND mf.ID_MSG = t.ID_FIRST_MSG ORDER BY $_GET[sort] " . ($descending ? 'DESC' : 'ASC') . " LIMIT $context[start], $modSettings[defaultMaxMessages]", __FILE__, __LINE__); $context['posts'] = array(); while ($row = mysql_fetch_assoc($request)) $context['posts'][] = array( 'id' => $row['ID_MSG'], 'poster' => array( 'id' => $row['ID_MEMBER'], 'name' => $row['posterName'], 'href' => empty($row['ID_MEMBER']) ? '' : $scripturl . '?action=profile;u=' . $row['ID_MEMBER'], 'link' => empty($row['ID_MEMBER']) ? $row['posterName'] : '' . $row['posterName'] . '' ), 'time' => empty($row['posterTime']) ? $txt['never'] : timeformat($row['posterTime']), 'timestamp' => forum_time(true, $row['posterTime']), 'attachment' => array( 'id' => $row['ID_ATTACH'], 'size' => round($row['size'] / 1024, 2), 'width' => $row['width'], 'height' => $row['height'], 'name' => htmlspecialchars($row['filename']), 'downloads' => $row['downloads'], 'href' => $row['attachmentType'] == 1 ? $modSettings['custom_avatar_url'] . '/' . $row['filename'] : ($scripturl . '?action=dlattach;' . ($context['browse_type'] == 'avatars' ? 'type=avatar;' : 'topic=' . $row['ID_TOPIC'] . '.0;') . 'id=' . $row['ID_ATTACH']), 'link' => '' . htmlspecialchars($row['filename']) . '' ), 'topic' => $row['ID_TOPIC'], 'subject' => $row['subject'], 'link' => '' . $row['subject'] . '' ); mysql_free_result($request); } function MaintainFiles() { global $db_prefix, $context, $modSettings, $txt; $context['page_title'] = $txt['smf201']; $context['description'] = $txt['smf202']; $context['selected'] = 'maintenance'; $context['sub_template'] = 'maintenance'; // Get the number of attachments.... $request = db_query(" SELECT COUNT(*) FROM {$db_prefix}attachments WHERE attachmentType = 0 AND ID_MEMBER = 0", __FILE__, __LINE__); list ($context['num_attachments']) = mysql_fetch_row($request); mysql_free_result($request); // Also get the avatar amount.... $request = db_query(" SELECT COUNT(*) FROM {$db_prefix}attachments WHERE ID_MEMBER != 0", __FILE__, __LINE__); list ($context['num_avatars']) = mysql_fetch_row($request); mysql_free_result($request); // Find out how big the directory is. $attachmentDirSize = 0; $dir = @opendir($modSettings['attachmentUploadDir']) or fatal_lang_error('smf115b'); while ($file = readdir($dir)) { if (substr($file, 0, -1) == '.') continue; if (preg_match('~^post_tmp_\d+_\d+$~', $file) != 0) { // Temp file is more than 5 hours old! if (filemtime($modSettings['attachmentUploadDir'] . '/' . $file) < time() - 18000) @unlink($modSettings['attachmentUploadDir'] . '/' . $file); continue; } $attachmentDirSize += filesize($modSettings['attachmentUploadDir'] . '/' . $file); } closedir($dir); // Divide it into kilobytes. $attachmentDirSize /= 1024; // If they specified a limit only.... if (!empty($modSettings['attachmentDirSizeLimit'])) $context['attachment_space'] = max(round($modSettings['attachmentDirSizeLimit'] - $attachmentDirSize, 2), 0); $context['attachment_total_size'] = round($attachmentDirSize, 2); } // !!! Not implemented yet. function MoveAvatars() { global $db_prefix, $modSettings; // First make sure the custom avatar dir is writable. if (!is_writable($modSettings['custom_avatar_dir'])) { // Try to fix it. @chmod($modSettings['custom_avatar_dir'], 0777); // Guess that didn't work :/? if (!is_writable($modSettings['custom_avatar_dir'])) fatal_lang_error('attachments_no_write'); } $request = db_query(" SELECT ID_ATTACH, ID_MEMBER, filename, file_hash FROM {$db_prefix}attachments WHERE attachmentType = 0 AND ID_MEMBER > 0", __FILE__, __LINE__); $updatedAvatars = array(); while ($row = mysql_fetch_assoc($request)) { $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); if (rename($filename, $modSettings['custom_avatar_dir'] . '/' . $row['filename'])) $updatedAvatars[] = $row['ID_ATTACH']; } mysql_free_result($request); if (!empty($updatedAvatars)) db_query(" UPDATE {$db_prefix}attachments SET attachmentType = 1 WHERE ID_ATTACH IN (" . implode(', ', $updatedAvatars) . ')', __FILE__, __LINE__); redirectexit('action=manageattachments;sa=maintenance'); } function RemoveAttachmentByAge() { global $db_prefix, $modSettings; checkSession('post', 'manageattachments'); // !!! Ignore messages in topics that are stickied? // Deleting an attachment? if ($_REQUEST['type'] != 'avatars') { // Get all the old attachments. $messages = removeAttachments('a.attachmentType = 0 AND m.posterTime < ' . (time() - 24 * 60 * 60 * $_POST['age']), 'messages', true); // Update the messages to reflect the change. if (!empty($messages)) db_query(" UPDATE {$db_prefix}messages SET body = " . (!empty($_POST['notice']) ? "CONCAT(body, '

$_POST[notice]')" : '') . " WHERE ID_MSG IN (" . implode(', ', $messages) . ") LIMIT " . count($messages), __FILE__, __LINE__); } else { // Remove all the old avatars. removeAttachments('a.ID_MEMBER != 0 AND mem.lastLogin < ' . (time() - 24 * 60 * 60 * $_POST['age']), 'members'); } redirectexit('action=manageattachments' . (empty($_REQUEST['avatars']) ? '' : ';avatars')); } function RemoveAttachmentBySize() { global $db_prefix, $modSettings; checkSession('post', 'manageattachments'); // Find humungous attachments. $messages = removeAttachments('a.attachmentType = 0 AND a.size > ' . (1024 * $_POST['size']), 'messages', true); // And make a note on the post. if (!empty($messages)) db_query(" UPDATE {$db_prefix}messages SET body = " . (!empty($_POST['notice']) ? "CONCAT(body, '

$_POST[notice]')" : '') . " WHERE ID_MSG IN (" . implode(',', $messages) . ") LIMIT " . count($messages), __FILE__, __LINE__); redirectexit('action=manageattachments;sa=maintenance'); } function RemoveAttachment() { global $db_prefix, $modSettings, $txt; checkSession('post'); if (!empty($_POST['remove'])) { $attachments = array(); // There must be a quicker way to pass this safety test?? foreach ($_POST['remove'] as $removeID => $dummy) $attachments[] = (int) $removeID; if ($_REQUEST['type'] == 'avatars' && !empty($attachments)) removeAttachments('a.ID_ATTACH IN (' . implode(', ', $attachments) . ')'); else if (!empty($attachments)) { $messages = removeAttachments('a.ID_ATTACH IN (' . implode(', ', $attachments) . ')', 'messages', true); // And change the message to reflect this. if (!empty($messages)) db_query(" UPDATE {$db_prefix}messages SET body = CONCAT(body, '

" . addslashes($txt['smf216']) . "') WHERE ID_MSG IN (" . implode(', ', $messages) . ") LIMIT " . count($messages), __FILE__, __LINE__); } } $_GET['sort'] = isset($_GET['sort']) ? $_GET['sort'] : 'date'; redirectexit('action=manageattachments;sa=browse;' . $_REQUEST['type'] . ';sort=' . $_GET['sort'] . (isset($_GET['desc']) ? ';desc' : '') . ';start=' . $_REQUEST['start']); } // !!! Not implemented (yet?) function RemoveAllAttachments() { global $db_prefix, $txt; checkSession('get', 'manageattachments'); $messages = removeAttachments('a.attachmentType = 0', '', true); if (!isset($_POST['notice'])) $_POST['notice'] = $txt['smf216']; // Add the notice on the end of the changed messages. if (!empty($messages)) db_query(" UPDATE {$db_prefix}messages SET body = CONCAT(body, '

$_POST[notice]') WHERE ID_MSG IN (" . implode(',', $messages) . ") LIMIT " . count($messages), __FILE__, __LINE__); redirectexit('action=manageattachments;sa=maintenance'); } // Removes attachments - allowed query_types: '', 'messages', 'members' function removeAttachments($condition, $query_type = '', $return_affected_messages = false, $autoThumbRemoval = true) { global $db_prefix, $modSettings; // Delete it only if it exists... $msgs = array(); $attach = array(); $parents = array(); // Get all the attachment names and ID_MSGs. $request = db_query(" SELECT a.filename, a.file_hash, a.attachmentType, a.ID_ATTACH, a.ID_MEMBER" . ($query_type == 'messages' ? ', m.ID_MSG' : ', a.ID_MSG') . ", IFNULL(thumb.ID_ATTACH, 0) AS ID_THUMB, thumb.filename AS thumb_filename, thumb_parent.ID_ATTACH AS ID_PARENT FROM ({$db_prefix}attachments AS a" .($query_type == 'members' ? ", {$db_prefix}members AS mem" : ($query_type == 'messages' ? ", {$db_prefix}messages AS m" : '')) . ") LEFT JOIN {$db_prefix}attachments AS thumb ON (thumb.ID_ATTACH = a.ID_THUMB) LEFT JOIN {$db_prefix}attachments AS thumb_parent ON (a.attachmentType = 3 AND thumb_parent.ID_THUMB = a.ID_ATTACH) WHERE $condition" . ($query_type == 'messages' ? ' AND m.ID_MSG = a.ID_MSG' : '') . ($query_type == 'members' ? ' AND mem.ID_MEMBER = a.ID_MEMBER' : ''), __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) { // Figure out the "encrypted" filename and unlink it ;). if ($row['attachmentType'] == 1) @unlink($modSettings['custom_avatar_dir'] . '/' . $row['filename']); else { $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); @unlink($filename); // If this was a thumb, the parent attachment should know about it. if (!empty($row['ID_PARENT'])) $parents[] = $row['ID_PARENT']; // If this attachments has a thumb, remove it as well. if (!empty($row['ID_THUMB']) && $autoThumbRemoval) { $thumb_filename = getAttachmentFilename($row['thumb_filename'], $row['ID_THUMB'], false, $row['file_hash']); @unlink($thumb_filename); $attach[] = $row['ID_THUMB']; } } // Make a list. if ($return_affected_messages && empty($row['attachmentType'])) $msgs[] = $row['ID_MSG']; $attach[] = $row['ID_ATTACH']; } mysql_free_result($request); // Removed attachments don't have to be updated anymore. $parents = array_diff($parents, $attach); if (!empty($parents)) db_query(" UPDATE {$db_prefix}attachments SET ID_THUMB = 0 WHERE ID_ATTACH IN (" . implode(', ', $parents) . ") LIMIT " . count($parents), __FILE__, __LINE__); if (!empty($attach)) db_query(" DELETE FROM {$db_prefix}attachments WHERE ID_ATTACH IN (" . implode(', ', $attach) . ") LIMIT " . count($attach), __FILE__, __LINE__); if ($return_affected_messages) return array_unique($msgs); } // This function should find attachments in the database that no longer exist and clear them, and fix filesize issues. function RepairAttachments() { global $db_prefix, $modSettings, $context, $txt; $context['page_title'] = $txt['repair_attachments']; $context['description'] = $txt['smf202']; $context['selected'] = 'maintenance'; $context['sub_template'] = 'attachment_repair'; checkSession('get'); // If we choose cancel, redirect right back. if (isset($_POST['cancel'])) redirectexit('action=manageattachments;sa=maintenance'); // Try give us a while to sort this out... @set_time_limit(600); $_GET['step'] = empty($_GET['step']) ? 0 : (int) $_GET['step']; $_GET['substep'] = empty($_GET['substep']) ? 0 : (int) $_GET['substep']; // Don't recall the session just incase. if ($_GET['step'] == 0 && $_GET['substep'] == 0) { unset($_SESSION['attachments_to_fix']); unset($_SESSION['attachments_to_fix2']); // If we're actually fixing stuff - work out what. if (isset($_GET['fixErrors'])) { // Nothing? if (empty($_POST['to_fix'])) redirectexit('action=manageattachments;sa=maintenance'); $_SESSION['attachments_to_fix'] = array(); //!!! No need to do this I think. foreach ($_POST['to_fix'] as $key => $value) $_SESSION['attachments_to_fix'][] = $value; } } $to_fix = !empty($_SESSION['attachments_to_fix']) ? $_SESSION['attachments_to_fix'] : array(); $context['repair_errors'] = isset($_SESSION['attachments_to_fix2']) ? $_SESSION['attachments_to_fix2'] : array(); $fix_errors = isset($_GET['fixErrors']) ? true : false; // All the valid problems are here: $context['repair_errors'] = array( 'missing_thumbnail_parent' => 0, 'parent_missing_thumbnail' => 0, 'file_missing_on_disk' => 0, 'file_wrong_size' => 0, 'file_size_of_zero' => 0, 'attachment_no_msg' => 0, 'avatar_no_member' => 0, ); // Get stranded thumbnails. if ($_GET['step'] <= 0) { $result = db_query(" SELECT MAX(ID_ATTACH) FROM {$db_prefix}attachments WHERE attachmentType = 3", __FILE__, __LINE__); list ($thumbnails) = mysql_fetch_row($result); mysql_free_result($result); for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) { $to_remove = array(); $result = db_query(" SELECT thumb.ID_ATTACH, thumb.filename, thumb.file_hash FROM {$db_prefix}attachments AS thumb LEFT JOIN {$db_prefix}attachments AS tparent ON (tparent.ID_THUMB = thumb.ID_ATTACH) WHERE thumb.ID_ATTACH BETWEEN $_GET[substep] AND $_GET[substep] + 499 AND thumb.attachmentType = 3 AND tparent.ID_ATTACH IS NULL GROUP BY thumb.ID_ATTACH", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($result)) { $to_remove[] = $row['ID_ATTACH']; $context['repair_errors']['missing_thumbnail_parent']++; // If we are repairing remove the file from disk now. if ($fix_errors && in_array('missing_thumbnail_parent', $to_fix)) { $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); @unlink($filename); } } if (mysql_num_rows($result) != 0) $to_fix[] = 'missing_thumbnail_parent'; mysql_free_result($result); // Do we need to delete what we have? if ($fix_errors && !empty($to_remove) && in_array('missing_thumbnail_parent', $to_fix)) db_query(" DELETE FROM {$db_prefix}attachments WHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ") AND attachmentType = 3", __FILE__, __LINE__); pauseAttachmentMaintenance($to_fix, $thumbnails); } $_GET['step'] = 1; $_GET['substep'] = 0; pauseAttachmentMaintenance($to_fix); } // Find parents which think they have thumbnails, but actually, don't. if ($_GET['step'] <= 1) { $result = db_query(" SELECT MAX(ID_ATTACH) FROM {$db_prefix}attachments WHERE ID_THUMB != 0", __FILE__, __LINE__); list ($thumbnails) = mysql_fetch_row($result); mysql_free_result($result); for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) { $to_update = array(); $result = db_query(" SELECT a.ID_ATTACH FROM {$db_prefix}attachments AS a LEFT JOIN {$db_prefix}attachments AS thumb ON (thumb.ID_ATTACH = a.ID_THUMB) WHERE a.ID_ATTACH BETWEEN $_GET[substep] AND $_GET[substep] + 499 AND a.ID_THUMB != 0 AND thumb.ID_ATTACH IS NULL", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($result)) { $to_update[] = $row['ID_ATTACH']; $context['repair_errors']['parent_missing_thumbnail']++; } if (mysql_num_rows($result) != 0) $to_fix[] = 'parent_missing_thumbnail'; mysql_free_result($result); // Do we need to delete what we have? if ($fix_errors && !empty($to_update) && in_array('parent_missing_thumbnail', $to_fix)) db_query(" UPDATE {$db_prefix}attachments SET ID_THUMB = 0 WHERE ID_ATTACH IN (" . implode(', ', $to_update) . ")", __FILE__, __LINE__); pauseAttachmentMaintenance($to_fix, $thumbnails); } $_GET['step'] = 2; $_GET['substep'] = 0; pauseAttachmentMaintenance($to_fix); } // This may take forever I'm afraid, but life sucks... recount EVERY attachments! if ($_GET['step'] <= 2) { $result = db_query(" SELECT MAX(ID_ATTACH) FROM {$db_prefix}attachments", __FILE__, __LINE__); list ($thumbnails) = mysql_fetch_row($result); mysql_free_result($result); for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 250) { $to_remove = array(); $errors_found = array(); $result = db_query(" SELECT ID_ATTACH, filename, file_hash, size, attachmentType FROM {$db_prefix}attachments WHERE ID_ATTACH BETWEEN $_GET[substep] AND $_GET[substep] + 249", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($result)) { // Get the filename. if ($row['attachmentType'] == 1) $filename = $modSettings['custom_avatar_dir'] . '/' . $row['filename']; else $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); // File doesn't exist? if (!file_exists($filename)) { $to_remove[] = $row['ID_ATTACH']; $context['repair_errors']['file_missing_on_disk']++; $errors_found[] = 'file_missing_on_disk'; // Are we fixing this? if ($fix_errors && in_array('file_missing_on_disk', $to_fix)) $to_remove[] = $row['ID_ATTACH']; } elseif (filesize($filename) == 0) { $context['repair_errors']['file_size_of_zero']++; $errors_found[] = 'file_size_of_zero'; // Fixing? if ($fix_errors && in_array('file_size_of_zero', $to_fix)) { $to_remove[] = $row['ID_ATTACH']; @unlink($filename); } } elseif (filesize($filename) != $row['size']) { $context['repair_errors']['file_wrong_size']++; $errors_found[] = 'file_wrong_size'; // Fix it here? if ($fix_errors && in_array('file_wrong_size', $to_fix)) { db_query(" UPDATE {$db_prefix}attachments SET size = " . filesize($filename) . " WHERE ID_ATTACH = $row[ID_ATTACH] LIMIT 1", __FILE__, __LINE__); } } } if (in_array('file_missing_on_disk', $errors_found)) $to_fix[] = 'file_missing_on_disk'; if (in_array('file_size_of_zero', $errors_found)) $to_fix[] = 'file_size_of_zero'; if (in_array('file_wrong_size', $errors_found)) $to_fix[] = 'file_wrong_size'; mysql_free_result($result); // Do we need to delete what we have? if ($fix_errors && !empty($to_remove)) { db_query(" DELETE FROM {$db_prefix}attachments WHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ")", __FILE__, __LINE__); db_query(" UPDATE {$db_prefix}attachments SET ID_THUMB = 0 WHERE ID_THUMB IN (" . implode(', ', $to_remove) . ")", __FILE__, __LINE__); } pauseAttachmentMaintenance($to_fix, $thumbnails); } $_GET['step'] = 3; $_GET['substep'] = 0; pauseAttachmentMaintenance($to_fix); } // Get avatars with no members associated with them. if ($_GET['step'] <= 3) { $result = db_query(" SELECT MAX(ID_ATTACH) FROM {$db_prefix}attachments", __FILE__, __LINE__); list ($thumbnails) = mysql_fetch_row($result); mysql_free_result($result); for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) { $to_remove = array(); $result = db_query(" SELECT a.ID_ATTACH, a.filename, a.file_hash, a.attachmentType FROM {$db_prefix}attachments AS a LEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = a.ID_MEMBER) WHERE a.ID_ATTACH BETWEEN $_GET[substep] AND $_GET[substep] + 499 AND a.ID_MEMBER != 0 AND a.ID_MSG = 0 AND mem.ID_MEMBER IS NULL", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($result)) { $to_remove[] = $row['ID_ATTACH']; $context['repair_errors']['avatar_no_member']++; // If we are repairing remove the file from disk now. if ($fix_errors && in_array('avatar_no_member', $to_fix)) { if ($row['attachmentType'] == 1) $filename = $modSettings['custom_avatar_dir'] . '/' . $row['filename']; else $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); @unlink($filename); } } if (mysql_num_rows($result) != 0) $to_fix[] = 'avatar_no_member'; mysql_free_result($result); // Do we need to delete what we have? if ($fix_errors && !empty($to_remove) && in_array('avatar_no_member', $to_fix)) db_query(" DELETE FROM {$db_prefix}attachments WHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ") AND ID_MEMBER != 0 AND ID_MSG = 0", __FILE__, __LINE__); pauseAttachmentMaintenance($to_fix, $thumbnails); } $_GET['step'] = 4; $_GET['substep'] = 0; pauseAttachmentMaintenance($to_fix); } // What about attachments, who are missing a message :'( if ($_GET['step'] <= 4) { $result = db_query(" SELECT MAX(ID_ATTACH) FROM {$db_prefix}attachments", __FILE__, __LINE__); list ($thumbnails) = mysql_fetch_row($result); mysql_free_result($result); for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) { $to_remove = array(); $result = db_query(" SELECT a.ID_ATTACH, a.filename, a.file_hash FROM {$db_prefix}attachments AS a LEFT JOIN {$db_prefix}messages AS m ON (m.ID_MSG = a.ID_MSG) WHERE a.ID_ATTACH BETWEEN $_GET[substep] AND $_GET[substep] + 499 AND a.ID_MEMBER = 0 AND a.ID_MSG != 0 AND m.ID_MSG IS NULL", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($result)) { $to_remove[] = $row['ID_ATTACH']; $context['repair_errors']['attachment_no_msg']++; // If we are repairing remove the file from disk now. if ($fix_errors && in_array('attachment_no_msg', $to_fix)) { $filename = getAttachmentFilename($row['filename'], $row['ID_ATTACH'], false, $row['file_hash']); @unlink($filename); } } if (mysql_num_rows($result) != 0) $to_fix[] = 'attachment_no_msg'; mysql_free_result($result); // Do we need to delete what we have? if ($fix_errors && !empty($to_remove) && in_array('attachment_no_msg', $to_fix)) db_query(" DELETE FROM {$db_prefix}attachments WHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ") AND ID_MEMBER = 0 AND ID_MSG != 0", __FILE__, __LINE__); pauseAttachmentMaintenance($to_fix, $thumbnails); } $_GET['step'] = 5; $_GET['substep'] = 0; pauseAttachmentMaintenance($to_fix); } // Got here we must be doing well :D $context['completed'] = $fix_errors ? true : false; $context['errors_found'] = !empty($to_fix) ? true : false; } function pauseAttachmentMaintenance($to_fix, $max_substep = 0) { global $context, $txt, $time_start; // Try get more time... @set_time_limit(600); if (function_exists('apache_reset_timeout')) apache_reset_timeout(); // Have we already used our maximum time? if (time() - array_sum(explode(' ', $time_start)) < 3) return; // Specific stuff to not break this template! $context['page_title'] = $txt['not_done_title']; $context['sub_template'] = 'not_done'; $context['description'] = $txt['smf202']; $context['selected'] = 'maintenance'; $context['continue_get_data'] = '?action=manageattachments;sa=repair' . (isset($_GET['fixErrors']) ? ';fixErrors' : '') . ';step=' . $_GET['step'] . ';substep=' . $_GET['substep'] . ';sesc=' . $context['session_id']; $context['continue_post_data'] = ''; $context['continue_countdown'] = '2'; // Change these two if more steps are added! if (empty($max_substep)) $context['continue_percent'] = round(($_GET['step'] * 100) / 25); else $context['continue_percent'] = round(($_GET['step'] * 100 + ($_GET['substep'] * 100) / $max_substep) / 25); // Never more than 100%! $context['continue_percent'] = min($context['continue_percent'], 100); $_SESSION['attachments_to_fix'] = $to_fix; $_SESSION['attachments_to_fix2'] = $context['repair_errors']; obExit(); } ?>