function RepairAttachments()
{
    global $modSettings, $context, $txt, $smcFunc;
    checkSession('get');
    // If we choose cancel, redirect right back.
    if (isset($_POST['cancel'])) {
        redirectexit('action=admin;area=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 in case.
    if ($_GET['step'] == 0 && $_GET['substep'] == 0) {
        unset($_SESSION['attachments_to_fix'], $_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=admin;area=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;
            }
        }
    }
    // 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, 'wrong_folder' => 0);
    $to_fix = !empty($_SESSION['attachments_to_fix']) ? $_SESSION['attachments_to_fix'] : array();
    $context['repair_errors'] = isset($_SESSION['attachments_to_fix2']) ? $_SESSION['attachments_to_fix2'] : $context['repair_errors'];
    $fix_errors = isset($_GET['fixErrors']) ? true : false;
    // Get stranded thumbnails.
    if ($_GET['step'] <= 0) {
        $result = $smcFunc['db_query']('', '
			SELECT MAX(id_attach)
			FROM {db_prefix}attachments
			WHERE attachment_type = {int:thumbnail}', array('thumbnail' => 3));
        list($thumbnails) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
            $to_remove = array();
            $result = $smcFunc['db_query']('', '
				SELECT thumb.id_attach, thumb.id_folder, 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 {int:substep} AND {int:substep} + 499
					AND thumb.attachment_type = {int:thumbnail}
					AND tparent.id_attach IS NULL', array('thumbnail' => 3, 'substep' => $_GET['substep']));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                // Only do anything once... just in case
                if (!isset($to_remove[$row['id_attach']])) {
                    $to_remove[$row['id_attach']] = $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'], $row['id_folder'], false, $row['file_hash']);
                        @unlink($filename);
                    }
                }
            }
            if ($smcFunc['db_num_rows']($result) != 0) {
                $to_fix[] = 'missing_thumbnail_parent';
            }
            $smcFunc['db_free_result']($result);
            // Do we need to delete what we have?
            if ($fix_errors && !empty($to_remove) && in_array('missing_thumbnail_parent', $to_fix)) {
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}attachments
					WHERE id_attach IN ({array_int:to_remove})
						AND attachment_type = {int:attachment_type}', array('to_remove' => $to_remove, 'attachment_type' => 3));
            }
            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 = $smcFunc['db_query']('', '
			SELECT MAX(id_attach)
			FROM {db_prefix}attachments
			WHERE id_thumb != {int:no_thumb}', array('no_thumb' => 0));
        list($thumbnails) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
            $to_update = array();
            $result = $smcFunc['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 {int:substep} AND {int:substep} + 499
					AND a.id_thumb != {int:no_thumb}
					AND thumb.id_attach IS NULL', array('no_thumb' => 0, 'substep' => $_GET['substep']));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                $to_update[] = $row['id_attach'];
                $context['repair_errors']['parent_missing_thumbnail']++;
            }
            if ($smcFunc['db_num_rows']($result) != 0) {
                $to_fix[] = 'parent_missing_thumbnail';
            }
            $smcFunc['db_free_result']($result);
            // Do we need to delete what we have?
            if ($fix_errors && !empty($to_update) && in_array('parent_missing_thumbnail', $to_fix)) {
                $smcFunc['db_query']('', '
					UPDATE {db_prefix}attachments
					SET id_thumb = {int:no_thumb}
					WHERE id_attach IN ({array_int:to_update})', array('to_update' => $to_update, 'no_thumb' => 0));
            }
            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 = $smcFunc['db_query']('', '
			SELECT MAX(id_attach)
			FROM {db_prefix}attachments', array());
        list($thumbnails) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 250) {
            $to_remove = array();
            $errors_found = array();
            $result = $smcFunc['db_query']('', '
				SELECT id_attach, id_folder, filename, file_hash, size, attachment_type
				FROM {db_prefix}attachments
				WHERE id_attach BETWEEN {int:substep} AND {int:substep} + 249', array('substep' => $_GET['substep']));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                // Get the filename.
                if ($row['attachment_type'] == 1) {
                    $filename = $modSettings['custom_avatar_dir'] . '/' . $row['filename'];
                } else {
                    $filename = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']);
                }
                // File doesn't exist?
                if (!file_exists($filename)) {
                    // If we're lucky it might just be in a different folder.
                    if (!empty($modSettings['currentAttachmentUploadDir'])) {
                        // Get the attachment name with out the folder.
                        $attachment_name = !empty($row['file_hash']) ? $row['id_attach'] . '_' . $row['file_hash'] : getLegacyAttachmentFilename($row['filename'], $row['id_attach'], null, true);
                        if (!is_array($modSettings['attachmentUploadDir'])) {
                            $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
                        }
                        // Loop through the other folders.
                        foreach ($modSettings['attachmentUploadDir'] as $id => $dir) {
                            if (file_exists($dir . '/' . $attachment_name)) {
                                $context['repair_errors']['wrong_folder']++;
                                $errors_found[] = 'wrong_folder';
                                // Are we going to fix this now?
                                if ($fix_errors && in_array('wrong_folder', $to_fix)) {
                                    $smcFunc['db_query']('', '
										UPDATE {db_prefix}attachments
										SET id_folder = {int:new_folder}
										WHERE id_attach = {int:id_attach}', array('new_folder' => $id, 'id_attach' => $row['id_attach']));
                                }
                                continue 2;
                            }
                        }
                    }
                    $to_remove[] = $row['id_attach'];
                    $context['repair_errors']['file_missing_on_disk']++;
                    $errors_found[] = 'file_missing_on_disk';
                } 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)) {
                        $smcFunc['db_query']('', '
							UPDATE {db_prefix}attachments
							SET size = {int:filesize}
							WHERE id_attach = {int:id_attach}', array('filesize' => filesize($filename), 'id_attach' => $row['id_attach']));
                    }
                }
            }
            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';
            }
            if (in_array('wrong_folder', $errors_found)) {
                $to_fix[] = 'wrong_folder';
            }
            $smcFunc['db_free_result']($result);
            // Do we need to delete what we have?
            if ($fix_errors && !empty($to_remove)) {
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}attachments
					WHERE id_attach IN ({array_int:to_remove})', array('to_remove' => $to_remove));
                $smcFunc['db_query']('', '
					UPDATE {db_prefix}attachments
					SET id_thumb = {int:no_thumb}
					WHERE id_thumb IN ({array_int:to_remove})', array('to_remove' => $to_remove, 'no_thumb' => 0));
            }
            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 = $smcFunc['db_query']('', '
			SELECT MAX(id_attach)
			FROM {db_prefix}attachments', array());
        list($thumbnails) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
            $to_remove = array();
            $result = $smcFunc['db_query']('', '
				SELECT a.id_attach, a.id_folder, a.filename, a.file_hash, a.attachment_type
				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 {int:substep} AND {int:substep} + 499
					AND a.id_member != {int:no_member}
					AND a.id_msg = {int:no_msg}
					AND mem.id_member IS NULL', array('no_member' => 0, 'no_msg' => 0, 'substep' => $_GET['substep']));
            while ($row = $smcFunc['db_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['attachment_type'] == 1) {
                        $filename = $modSettings['custom_avatar_dir'] . '/' . $row['filename'];
                    } else {
                        $filename = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']);
                    }
                    @unlink($filename);
                }
            }
            if ($smcFunc['db_num_rows']($result) != 0) {
                $to_fix[] = 'avatar_no_member';
            }
            $smcFunc['db_free_result']($result);
            // Do we need to delete what we have?
            if ($fix_errors && !empty($to_remove) && in_array('avatar_no_member', $to_fix)) {
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}attachments
					WHERE id_attach IN ({array_int:to_remove})
						AND id_member != {int:no_member}
						AND id_msg = {int:no_msg}', array('to_remove' => $to_remove, 'no_member' => 0, 'no_msg' => 0));
            }
            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 = $smcFunc['db_query']('', '
			SELECT MAX(id_attach)
			FROM {db_prefix}attachments', array());
        list($thumbnails) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
            $to_remove = array();
            $result = $smcFunc['db_query']('', '
				SELECT a.id_attach, a.id_folder, 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 {int:substep} AND {int:substep} + 499
					AND a.id_member = {int:no_member}
					AND a.id_msg != {int:no_msg}
					AND m.id_msg IS NULL', array('no_member' => 0, 'no_msg' => 0, 'substep' => $_GET['substep']));
            while ($row = $smcFunc['db_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'], $row['id_folder'], false, $row['file_hash']);
                    @unlink($filename);
                }
            }
            if ($smcFunc['db_num_rows']($result) != 0) {
                $to_fix[] = 'attachment_no_msg';
            }
            $smcFunc['db_free_result']($result);
            // Do we need to delete what we have?
            if ($fix_errors && !empty($to_remove) && in_array('attachment_no_msg', $to_fix)) {
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}attachments
					WHERE id_attach IN ({array_int:to_remove})
						AND id_member = {int:no_member}
						AND id_msg != {int:no_msg}', array('to_remove' => $to_remove, 'no_member' => 0, 'no_msg' => 0));
            }
            pauseAttachmentMaintenance($to_fix, $thumbnails);
        }
        $_GET['step'] = 5;
        $_GET['substep'] = 0;
        pauseAttachmentMaintenance($to_fix);
    }
    // Got here we must be doing well - just the template! :D
    $context['page_title'] = $txt['repair_attachments'];
    $context[$context['admin_menu_name']]['current_subsection'] = 'maintenance';
    $context['sub_template'] = 'attachment_repair';
    // What stage are we at?
    $context['completed'] = $fix_errors ? true : false;
    $context['errors_found'] = !empty($to_fix) ? true : false;
}
Esempio n. 2
0
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("\n\t\t\tSELECT MAX(ID_ATTACH)\n\t\t\tFROM {$db_prefix}attachments\n\t\t\tWHERE 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("\n\t\t\t\tSELECT thumb.ID_ATTACH, thumb.filename, thumb.file_hash\n\t\t\t\tFROM {$db_prefix}attachments AS thumb\n\t\t\t\t\tLEFT JOIN {$db_prefix}attachments AS tparent ON (tparent.ID_THUMB = thumb.ID_ATTACH)\n\t\t\t\tWHERE thumb.ID_ATTACH BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND thumb.attachmentType = 3\n\t\t\t\t\tAND tparent.ID_ATTACH IS NULL\n\t\t\t\tGROUP 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("\n\t\t\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\t\t\tWHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ")\n\t\t\t\t\t\tAND 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("\n\t\t\tSELECT MAX(ID_ATTACH)\n\t\t\tFROM {$db_prefix}attachments\n\t\t\tWHERE 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("\n\t\t\t\tSELECT a.ID_ATTACH\n\t\t\t\tFROM {$db_prefix}attachments AS a\n\t\t\t\t\tLEFT JOIN {$db_prefix}attachments AS thumb ON (thumb.ID_ATTACH = a.ID_THUMB)\n\t\t\t\tWHERE a.ID_ATTACH BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND a.ID_THUMB != 0\n\t\t\t\t\tAND 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("\n\t\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\t\tSET ID_THUMB = 0\n\t\t\t\t\tWHERE 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("\n\t\t\tSELECT MAX(ID_ATTACH)\n\t\t\tFROM {$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("\n\t\t\t\tSELECT ID_ATTACH, filename, file_hash, size, attachmentType\n\t\t\t\tFROM {$db_prefix}attachments\n\t\t\t\tWHERE 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("\n\t\t\t\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\t\t\t\tSET size = " . filesize($filename) . "\n\t\t\t\t\t\t\tWHERE ID_ATTACH = {$row['ID_ATTACH']}\n\t\t\t\t\t\t\tLIMIT 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("\n\t\t\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\t\t\tWHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ")", __FILE__, __LINE__);
                db_query("\n\t\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\t\tSET ID_THUMB = 0\n\t\t\t\t\tWHERE 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("\n\t\t\tSELECT MAX(ID_ATTACH)\n\t\t\tFROM {$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("\n\t\t\t\tSELECT a.ID_ATTACH, a.filename, a.file_hash, a.attachmentType\n\t\t\t\tFROM {$db_prefix}attachments AS a\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = a.ID_MEMBER)\n\t\t\t\tWHERE a.ID_ATTACH BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND a.ID_MEMBER != 0\n\t\t\t\t\tAND a.ID_MSG = 0\n\t\t\t\t\tAND 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("\n\t\t\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\t\t\tWHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ")\n\t\t\t\t\t\tAND ID_MEMBER != 0\n\t\t\t\t\t\tAND 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("\n\t\t\tSELECT MAX(ID_ATTACH)\n\t\t\tFROM {$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("\n\t\t\t\tSELECT a.ID_ATTACH, a.filename, a.file_hash\n\t\t\t\tFROM {$db_prefix}attachments AS a\n\t\t\t\t\tLEFT JOIN {$db_prefix}messages AS m ON (m.ID_MSG = a.ID_MSG)\n\t\t\t\tWHERE a.ID_ATTACH BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND a.ID_MEMBER = 0\n\t\t\t\t\tAND a.ID_MSG != 0\n\t\t\t\t\tAND 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("\n\t\t\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\t\t\tWHERE ID_ATTACH IN (" . implode(', ', $to_remove) . ")\n\t\t\t\t\t\tAND ID_MEMBER = 0\n\t\t\t\t\t\tAND 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;
}
 /**
  * This function will performs many attachment checks and provides ways to fix them
  *
  * What it does:
  * - Checks for the following common issues
  * - Orphan Thumbnails
  * - Attachments that have no thumbnails
  * - Attachments that list thumbnails, but actually, don't have any
  * - Attachments list in the wrong_folder
  * - Attachments that don't exists on disk any longer
  * - Attachments that are zero size
  * - Attachments that file size does not match the DB size
  * - Attachments that no longer have a message
  * - Avatars with no members associated with them.
  * - Attachments that are in the attachment folder, but not listed in the DB
  */
 public function action_repair()
 {
     global $modSettings, $context, $txt;
     checkSession('get');
     // If we choose cancel, redirect right back.
     if (isset($_POST['cancel'])) {
         redirectexit('action=admin;area=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'];
     $context['starting_substep'] = $_GET['substep'] = empty($_GET['substep']) ? 0 : (int) $_GET['substep'];
     // Don't recall the session just in case.
     if ($_GET['step'] == 0 && $_GET['substep'] == 0) {
         unset($_SESSION['attachments_to_fix'], $_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=admin;area=manageattachments;sa=maintenance');
             }
             foreach ($_POST['to_fix'] as $key => $value) {
                 $_SESSION['attachments_to_fix'][] = $value;
             }
         }
     }
     // We will work hard with attachments.
     require_once SUBSDIR . '/ManageAttachments.subs.php';
     // 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, 'wrong_folder' => 0, 'missing_extension' => 0, 'files_without_attachment' => 0);
     $to_fix = !empty($_SESSION['attachments_to_fix']) ? $_SESSION['attachments_to_fix'] : array();
     $context['repair_errors'] = isset($_SESSION['attachments_to_fix2']) ? $_SESSION['attachments_to_fix2'] : $context['repair_errors'];
     $fix_errors = isset($_GET['fixErrors']) ? true : false;
     // Get stranded thumbnails.
     if ($_GET['step'] <= 0) {
         $thumbnails = getMaxThumbnail();
         for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
             $removed = findOrphanThumbnails($_GET['substep'], $fix_errors, $to_fix);
             $context['repair_errors']['missing_thumbnail_parent'] += count($removed);
             pauseAttachmentMaintenance($to_fix, $thumbnails);
         }
         // Done here, on to the next
         $_GET['step'] = 1;
         $_GET['substep'] = 0;
         pauseAttachmentMaintenance($to_fix);
     }
     // Find parents which think they have thumbnails, but actually, don't.
     if ($_GET['step'] <= 1) {
         $thumbnails = maxNoThumb();
         for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
             $to_update = findParentsOrphanThumbnails($_GET['substep'], $fix_errors, $to_fix);
             $context['repair_errors']['parent_missing_thumbnail'] += count($to_update);
             pauseAttachmentMaintenance($to_fix, $thumbnails);
         }
         // Another step done, but many to go
         $_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) {
         $thumbnails = maxAttachment();
         for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 250) {
             $repair_errors = repairAttachmentData($_GET['substep'], $fix_errors, $to_fix);
             foreach ($repair_errors as $key => $value) {
                 $context['repair_errors'][$key] += $value;
             }
             pauseAttachmentMaintenance($to_fix, $thumbnails);
         }
         // And onward we go
         $_GET['step'] = 3;
         $_GET['substep'] = 0;
         pauseAttachmentMaintenance($to_fix);
     }
     // Get avatars with no members associated with them.
     if ($_GET['step'] <= 3) {
         $thumbnails = maxAttachment();
         for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
             $to_remove = findOrphanAvatars($_GET['substep'], $fix_errors, $to_fix);
             $context['repair_errors']['avatar_no_member'] += count($to_remove);
             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) {
         $thumbnails = maxAttachment();
         for (; $_GET['substep'] < $thumbnails; $_GET['substep'] += 500) {
             $to_remove = findOrphanAttachments($_GET['substep'], $fix_errors, $to_fix);
             $context['repair_errors']['attachment_no_msg'] += count($to_remove);
             pauseAttachmentMaintenance($to_fix, $thumbnails);
         }
         $_GET['step'] = 5;
         $_GET['substep'] = 0;
         pauseAttachmentMaintenance($to_fix);
     }
     // What about files who are not recorded in the database?
     if ($_GET['step'] <= 5) {
         // Just use the current path for temp files.
         if (!is_array($modSettings['attachmentUploadDir'])) {
             $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
         }
         $attach_dirs = $modSettings['attachmentUploadDir'];
         $current_check = 0;
         $max_checks = 500;
         $files_checked = empty($_GET['substep']) ? 0 : $_GET['substep'];
         foreach ($attach_dirs as $attach_dir) {
             if ($dir = @opendir($attach_dir)) {
                 while ($file = readdir($dir)) {
                     if ($file == '.' || $file == '..' || $file == '.htaccess') {
                         continue;
                     }
                     if ($files_checked <= $current_check) {
                         // Temporary file, get rid of it!
                         if (strpos($file, 'post_tmp_') !== false) {
                             // Temp file is more than 5 hours old!
                             if (filemtime($attach_dir . '/' . $file) < time() - 18000) {
                                 @unlink($attach_dir . '/' . $file);
                             }
                         } elseif (strpos($file, '_') !== false) {
                             $attachID = (int) substr($file, 0, strpos($file, '_'));
                             if (!empty($attachID)) {
                                 if (!validateAttachID($attachID)) {
                                     if ($fix_errors && in_array('files_without_attachment', $to_fix)) {
                                         @unlink($attach_dir . '/' . $file);
                                     } else {
                                         $context['repair_errors']['files_without_attachment']++;
                                     }
                                 }
                             }
                         } elseif ($file != 'index.php' && !is_dir($attach_dir . '/' . $file)) {
                             if ($fix_errors && in_array('files_without_attachment', $to_fix)) {
                                 @unlink($attach_dir . '/' . $file);
                             } else {
                                 $context['repair_errors']['files_without_attachment']++;
                             }
                         }
                     }
                     $current_check++;
                     $_GET['substep'] = $current_check;
                     if ($current_check - $files_checked >= $max_checks) {
                         pauseAttachmentMaintenance($to_fix);
                     }
                 }
                 closedir($dir);
             }
         }
         $_GET['step'] = 5;
         $_GET['substep'] = 0;
         pauseAttachmentMaintenance($to_fix);
     }
     // Got here we must be doing well - just the template! :D
     $context['page_title'] = $txt['repair_attachments'];
     $context[$context['admin_menu_name']]['current_subsection'] = 'maintenance';
     $context['sub_template'] = 'attachment_repair';
     // What stage are we at?
     $context['completed'] = $fix_errors ? true : false;
     $context['errors_found'] = false;
     foreach ($context['repair_errors'] as $number) {
         if (!empty($number)) {
             $context['errors_found'] = true;
             break;
         }
     }
 }