/** * downloads a file from a url and stores it locally for avatar use by id_member. * - supports GIF, JPG, PNG, BMP and WBMP formats. * - detects if GD2 is available. * - uses resizeImageFile() to resize to max_width by max_height, and saves the result to a file. * - updates the database info for the member's avatar. * - returns whether the download and resize was successful. * * @param string $temporary_path, the full path to the temporary file * @param int $memID, member ID * @param int $max_width * @param int $max_height * @return bool, whether the download and resize was successful. * */ function downloadAvatar($url, $memID, $max_width, $max_height) { global $modSettings, $sourcedir, $smcFunc; $ext = !empty($modSettings['avatar_download_png']) ? 'png' : 'jpeg'; $destName = 'avatar_' . $memID . '_' . time() . '.' . $ext; // Just making sure there is a non-zero member. if (empty($memID)) { return false; } require_once $sourcedir . '/ManageAttachments.php'; removeAttachments(array('id_member' => $memID)); $id_folder = !empty($modSettings['currentAttachmentUploadDir']) ? $modSettings['currentAttachmentUploadDir'] : 1; $avatar_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, null, true) : ''; $smcFunc['db_insert']('', '{db_prefix}attachments', array('id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-255', 'fileext' => 'string-8', 'size' => 'int', 'id_folder' => 'int'), array($memID, empty($modSettings['custom_avatar_enabled']) ? 0 : 1, $destName, $avatar_hash, $ext, 1, $id_folder), array('id_attach')); $attachID = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); // Retain this globally in case the script wants it. $modSettings['new_avatar_data'] = array('id' => $attachID, 'filename' => $destName, 'type' => empty($modSettings['custom_avatar_enabled']) ? 0 : 1); $destName = (empty($modSettings['custom_avatar_enabled']) ? is_array($modSettings['attachmentUploadDir']) ? $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']] : $modSettings['attachmentUploadDir'] : $modSettings['custom_avatar_dir']) . '/' . $destName . '.tmp'; // Resize it. if (!empty($modSettings['avatar_download_png'])) { $success = resizeImageFile($url, $destName, $max_width, $max_height, 3); } else { $success = resizeImageFile($url, $destName, $max_width, $max_height); } // Remove the .tmp extension. $destName = substr($destName, 0, -4); if ($success) { // Walk the right path. if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } $path = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; } else { $path = $modSettings['attachmentUploadDir']; } // Remove the .tmp extension from the attachment. if (rename($destName . '.tmp', empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash)) { $destName = empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash; list($width, $height) = getimagesize($destName); $mime_type = 'image/' . $ext; // Write filesize in the database. $smcFunc['db_query']('', ' UPDATE {db_prefix}attachments SET size = {int:filesize}, width = {int:width}, height = {int:height}, mime_type = {string:mime_type} WHERE id_attach = {int:current_attachment}', array('filesize' => filesize($destName), 'width' => (int) $width, 'height' => (int) $height, 'current_attachment' => $attachID, 'mime_type' => $mime_type)); return true; } else { return false; } } else { $smcFunc['db_query']('', ' DELETE FROM {db_prefix}attachments WHERE id_attach = {int:current_attachment}', array('current_attachment' => $attachID)); @unlink($destName . '.tmp'); return false; } }
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; }
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; }
/** * Load message image attachments for use in the print page function * Returns array of file attachment name along with width/height properties * Will only return approved attachments * * @param int[] $id_messages */ function messagesAttachments($id_messages) { global $modSettings; $db = database(); $request = $db->query('', ' SELECT a.id_attach, a.id_msg, a.approved, a.width, a.height, a.file_hash, a.filename, a.id_folder, a.mime_type FROM {db_prefix}attachments AS a WHERE a.id_msg IN ({array_int:message_list}) AND a.attachment_type = {int:attachment_type}', array('message_list' => $id_messages, 'attachment_type' => 0, 'is_approved' => 1)); $temp = array(); $printattach = array(); while ($row = $db->fetch_assoc($request)) { $temp[$row['id_attach']] = $row; if (!isset($printattach[$row['id_msg']])) { $printattach[$row['id_msg']] = array(); } } $db->free_result($request); ksort($temp); // Load them into $context so the template can use them foreach ($temp as $row) { if (!empty($row['width']) && !empty($row['height'])) { if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $row['height'] * ($modSettings['max_image_width'] / $row['width']) <= $modSettings['max_image_height'])) { if ($row['width'] > $modSettings['max_image_width']) { $row['height'] = floor($row['height'] * ($modSettings['max_image_width'] / $row['width'])); $row['width'] = $modSettings['max_image_width']; } } elseif (!empty($modSettings['max_image_width'])) { if ($row['height'] > $modSettings['max_image_height']) { $row['width'] = floor($row['width'] * $modSettings['max_image_height'] / $row['height']); $row['height'] = $modSettings['max_image_height']; } } $row['filename'] = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); // save for the template $printattach[$row['id_msg']][] = $row; } } return $printattach; }
function makeAvatarChanges($memID, &$post_errors) { global $modSettings, $sourcedir, $db_prefix; if (!isset($_POST['avatar_choice']) || empty($memID)) { return; } require_once $sourcedir . '/ManageAttachments.php'; $uploadDir = empty($modSettings['custom_avatar_enabled']) ? $modSettings['attachmentUploadDir'] : $modSettings['custom_avatar_dir']; $downloadedExternalAvatar = false; if ($_POST['avatar_choice'] == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && strlen($_POST['userpicpersonal']) > 7 && !empty($modSettings['avatar_download_external'])) { if (!is_writable($uploadDir)) { fatal_lang_error('attachments_no_write'); } require_once $sourcedir . '/Subs-Package.php'; $url = parse_url($_POST['userpicpersonal']); $contents = fetch_web_data('http://' . $url['host'] . (empty($url['port']) ? '' : ':' . $url['port']) . $url['path']); if ($contents != false && ($tmpAvatar = fopen($uploadDir . '/avatar_tmp_' . $memID, 'wb'))) { fwrite($tmpAvatar, $contents); fclose($tmpAvatar); $downloadedExternalAvatar = true; $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; } } if ($_POST['avatar_choice'] == 'server_stored' && allowedTo('profile_server_avatar')) { $_POST['avatar'] = strtr(empty($_POST['file']) ? empty($_POST['cat']) ? '' : $_POST['cat'] : $_POST['file'], array('&' => '&')); $_POST['avatar'] = preg_match('~^([\\w _!@%*=\\-#()\\[\\]&.,]+/)?[\\w _!@%*=\\-#()\\[\\]&.,]+$~', $_POST['avatar']) != 0 && preg_match('/\\.\\./', $_POST['avatar']) == 0 && file_exists($modSettings['avatar_directory'] . '/' . $_POST['avatar']) ? $_POST['avatar'] == 'blank.gif' ? '' : $_POST['avatar'] : ''; // Get rid of their old avatar. (if uploaded.) removeAttachments('a.ID_MEMBER = ' . $memID); } elseif ($_POST['avatar_choice'] == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && empty($modSettings['avatar_download_external'])) { // Remove any attached avatar... removeAttachments('a.ID_MEMBER = ' . $memID); $_POST['avatar'] = preg_replace('~action(=|%3d)(?!dlattach)~i', 'action-', $_POST['userpicpersonal']); if ($_POST['avatar'] == 'http://' || $_POST['avatar'] == 'http:///') { $_POST['avatar'] = ''; } elseif (substr($_POST['avatar'], 0, 7) != 'http://') { $post_errors[] = 'bad_avatar'; } elseif (!empty($modSettings['avatar_max_height_external']) || !empty($modSettings['avatar_max_width_external'])) { // Now let's validate the avatar. $sizes = url_image_size($_POST['avatar']); if (is_array($sizes) && ($sizes[0] > $modSettings['avatar_max_width_external'] && !empty($modSettings['avatar_max_width_external']) || $sizes[1] > $modSettings['avatar_max_height_external'] && !empty($modSettings['avatar_max_height_external']))) { // Houston, we have a problem. The avatar is too large!! if ($modSettings['avatar_action_too_large'] == 'option_refuse') { $post_errors[] = 'bad_avatar'; } elseif ($modSettings['avatar_action_too_large'] == 'option_download_and_resize') { require_once $sourcedir . '/Subs-Graphics.php'; if (downloadAvatar($_POST['avatar'], $memID, $modSettings['avatar_max_width_external'], $modSettings['avatar_max_height_external'])) { $_POST['avatar'] = ''; } else { $post_errors[] = 'bad_avatar'; } } } } } elseif ($_POST['avatar_choice'] == 'upload' && allowedTo('profile_upload_avatar') || $downloadedExternalAvatar) { if (isset($_FILES['attachment']['name']) && $_FILES['attachment']['name'] != '' || $downloadedExternalAvatar) { // Get the dimensions of the image. if (!$downloadedExternalAvatar) { if (!is_writable($uploadDir)) { fatal_lang_error('attachments_no_write'); } if (!move_uploaded_file($_FILES['attachment']['tmp_name'], $uploadDir . '/avatar_tmp_' . $memID)) { fatal_lang_error('smf124'); } $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; } $sizes = @getimagesize($_FILES['attachment']['tmp_name']); // No size, then it's probably not a valid pic. if ($sizes === false) { $post_errors[] = 'bad_avatar'; } elseif (!empty($modSettings['avatar_max_width_upload']) && $sizes[0] > $modSettings['avatar_max_width_upload'] || !empty($modSettings['avatar_max_height_upload']) && $sizes[1] > $modSettings['avatar_max_height_upload']) { if (!empty($modSettings['avatar_resize_upload'])) { // Attempt to chmod it. @chmod($uploadDir . '/avatar_tmp_' . $memID, 0644); require_once $sourcedir . '/Subs-Graphics.php'; downloadAvatar($uploadDir . '/avatar_tmp_' . $memID, $memID, $modSettings['avatar_max_width_upload'], $modSettings['avatar_max_height_upload']); } else { $post_errors[] = 'bad_avatar'; } } elseif (is_array($sizes)) { // Though not an exhaustive list, better safe than sorry. $fp = fopen($_FILES['attachment']['tmp_name'], 'rb'); if (!$fp) { fatal_lang_error('smf124'); } // Now try to find an infection. while (!feof($fp)) { if (preg_match('~(iframe|\\<\\?php|\\<\\?[\\s=]|\\<%[\\s=]|html|eval|body|script\\W)~', fgets($fp, 4096)) === 1) { if (file_exists($uploadDir . '/avatar_tmp_' . $memID)) { @unlink($uploadDir . '/avatar_tmp_' . $memID); } fatal_lang_error('smf124'); } } fclose($fp); $extensions = array('1' => '.gif', '2' => '.jpg', '3' => '.png', '6' => '.bmp'); $extension = isset($extensions[$sizes[2]]) ? $extensions[$sizes[2]] : '.bmp'; $destName = 'avatar_' . $memID . $extension; list($width, $height) = getimagesize($_FILES['attachment']['tmp_name']); // Remove previous attachments this member might have had. removeAttachments('a.ID_MEMBER = ' . $memID); $file_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, true) : ''; db_query("\n\t\t\t\t\tINSERT INTO {$db_prefix}attachments\n\t\t\t\t\t\t(ID_MEMBER, attachmentType, filename, file_hash, size, width, height)\n\t\t\t\t\tVALUES ({$memID}, " . (empty($modSettings['custom_avatar_enabled']) ? '0' : '1') . ", '{$destName}', '" . (empty($file_hash) ? "" : "{$file_hash}") . "', " . filesize($_FILES['attachment']['tmp_name']) . ", " . (int) $width . ", " . (int) $height . ")", __FILE__, __LINE__); $attachID = db_insert_id(); // Try to move this avatar. $destinationPath = $uploadDir . '/' . (empty($file_hash) ? $destName : $attachID . '_' . $file_hash); if (!rename($_FILES['attachment']['tmp_name'], $destinationPath)) { // The move failed, get rid of it and die. db_query("\n\t\t\t\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\t\t\t\tWHERE ID_ATTACH = {$attachID}", __FILE__, __LINE__); fatal_lang_error('smf124'); } // Attempt to chmod it. @chmod($destinationPath, 0644); } $_POST['avatar'] = ''; // Delete any temporary file. if (file_exists($uploadDir . '/avatar_tmp_' . $memID)) { @unlink($uploadDir . '/avatar_tmp_' . $memID); } } else { $_POST['avatar'] = ''; } } else { $_POST['avatar'] = ''; } }
function shd_attachment_info($attach_info) { global $scripturl, $context, $modSettings, $txt, $sourcedir, $smcFunc; $filename = preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($attach_info['filename'])); $deleteable = shd_allowed_to('shd_delete_attachment', $context['ticket']['dept']); $attach = array('id' => $attach_info['id_attach'], 'name' => $filename, 'size' => round($attach_info['filesize'] / 1024, 2) . ' ' . $txt['kilobyte'], 'byte_size' => $attach_info['filesize'], 'href' => $scripturl . '?action=dlattach;ticket=' . $context['ticket_id'] . '.0;attach=' . $attach_info['id_attach'], 'link' => shd_attach_icon($filename) . ' <a href="' . $scripturl . '?action=dlattach;ticket=' . $context['ticket_id'] . '.0;attach=' . $attach_info['id_attach'] . '">' . htmlspecialchars($attach_info['filename']) . '</a>', 'is_image' => !empty($modSettings['attachmentShowImages']) && !empty($attach_info['width']) && !empty($attach_info['height']), 'can_delete' => $deleteable); if ($attach['is_image']) { $attach += array('real_width' => $attach_info['width'], 'width' => $attach_info['width'], 'real_height' => $attach_info['height'], 'height' => $attach_info['height']); // Let's see, do we want thumbs? if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attach_info['width'] > $modSettings['attachmentThumbWidth'] || $attach_info['height'] > $modSettings['attachmentThumbHeight']) && strlen($attach_info['filename']) < 249) { // A proper thumb doesn't exist yet? Create one! if (empty($attach_info['id_thumb']) || $attach_info['thumb_width'] > $modSettings['attachmentThumbWidth'] || $attach_info['thumb_height'] > $modSettings['attachmentThumbHeight'] || $attach_info['thumb_width'] < $modSettings['attachmentThumbWidth'] && $attach_info['thumb_height'] < $modSettings['attachmentThumbHeight']) { $filename = getAttachmentFilename($attach_info['filename'], $attach_info['id_attach'], $attach_info['id_folder']); require_once $sourcedir . '/Subs-Graphics.php'; if (createThumbnail($filename, $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // So what folder are we putting this image in? if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = json_decode($modSettings['attachmentUploadDir'], true); } $path = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; $id_folder_thumb = $modSettings['currentAttachmentUploadDir']; } else { $path = $modSettings['attachmentUploadDir']; $id_folder_thumb = 1; } // Calculate the size of the created thumbnail. $size = @getimagesize($filename . '_thumb'); list($attach_info['thumb_width'], $attach_info['thumb_height']) = $size; $thumb_size = filesize($filename . '_thumb'); // These are the only valid image types for SMF. $validImageTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 5 => 'psd', 6 => 'bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpeg', 14 => 'iff'); // What about the extension? $thumb_ext = isset($validImageTypes[$size[2]]) ? $validImageTypes[$size[2]] : ''; // Figure out the mime type. if (!empty($size['mime'])) { $thumb_mime = $size['mime']; } else { $thumb_mime = 'image/' . $thumb_ext; } $thumb_filename = $attach_info['filename'] . '_thumb'; $thumb_hash = getAttachmentFilename($thumb_filename, false, null, true); // Add this beauty to the database. $smcFunc['db_insert']('', '{db_prefix}attachments', array('id_folder' => 'int', 'id_msg' => 'int', 'attachment_type' => 'int', 'filename' => 'string', 'file_hash' => 'string', 'size' => 'int', 'width' => 'int', 'height' => 'int', 'fileext' => 'string', 'mime_type' => 'string'), array($id_folder_thumb, 0, 3, $thumb_filename, $thumb_hash, (int) $thumb_size, (int) $attach_info['thumb_width'], (int) $attach_info['thumb_height'], $thumb_ext, $thumb_mime), array('id_attach')); $old_id_thumb = $attach_info['id_thumb']; $attach_info['id_thumb'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); if (!empty($attach_info['id_thumb'])) { // Update the tables to notify that we has us a thumbnail $smcFunc['db_query']('', ' UPDATE {db_prefix}attachments SET id_thumb = {int:id_thumb} WHERE id_attach = {int:id_attach}', array('id_thumb' => $attach_info['id_thumb'], 'id_attach' => $attach_info['id_attach'])); $smcFunc['db_insert']('replace', '{db_prefix}helpdesk_attachments', array('id_attach' => 'int', 'id_ticket' => 'int', 'id_msg' => 'int'), array($attach_info['id_thumb'], $attach_info['id_ticket'], $attach_info['id_msg']), array('id_attach')); $thumb_realname = getAttachmentFilename($thumb_filename, $attach_info['id_thumb'], $id_folder_thumb, false, $thumb_hash); rename($filename . '_thumb', $thumb_realname); // Do we need to remove an old thumbnail? if (!empty($old_id_thumb)) { require_once $sourcedir . '/ManageAttachments.php'; removeAttachments(array('id_attach' => $old_id_thumb), '', false, false); } } } } // Only adjust dimensions on successful thumbnail creation. if (!empty($attach_info['thumb_width']) && !empty($attach_info['thumb_height'])) { $attach['width'] = $attach_info['thumb_width']; $attach['height'] = $attach_info['thumb_height']; } } if (!empty($attach_info['id_thumb'])) { $attach['thumbnail'] = array('id' => $attach_info['id_thumb'], 'href' => $scripturl . '?action=dlattach;ticket=' . $context['ticket_id'] . '.0;attach=' . $attach_info['id_thumb'] . ';image'); } $attach['thumbnail']['has_thumb'] = !empty($attach_info['id_thumb']); // If thumbnails are disabled, check the maximum size of the image. if (!$attach['thumbnail']['has_thumb'] && (!empty($modSettings['max_image_width']) && $attach_info['width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attach_info['height'] > $modSettings['max_image_height'])) { if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $attach_info['height'] * $modSettings['max_image_width'] / $attach_info['width'] <= $modSettings['max_image_height'])) { $attach['width'] = $modSettings['max_image_width']; $attach['height'] = floor($attach_info['height'] * $modSettings['max_image_width'] / $attach_info['width']); } elseif (!empty($modSettings['max_image_width'])) { $attach['width'] = floor($attach['width'] * $modSettings['max_image_height'] / $attach['height']); $attach['height'] = $modSettings['max_image_height']; } } elseif ($attach['thumbnail']['has_thumb']) { // Make it a popup (since invariably it'll break the layout otherwise) $attach['thumbnail']['javascript'] = 'return reqWin(\'' . $attach['href'] . ';image\', ' . ($attach_info['width'] + 20) . ', ' . ($attach_info['height'] + 20) . ', true);'; } } return $attach; }
function createAttachment(&$attachmentOptions) { global $db_prefix, $modSettings, $sourcedir; $attachmentOptions['errors'] = array(); if (!isset($attachmentOptions['post'])) { $attachmentOptions['post'] = 0; } $already_uploaded = preg_match('~^post_tmp_' . $attachmentOptions['poster'] . '_\\d+$~', $attachmentOptions['tmp_name']) != 0; $file_restricted = @ini_get('open_basedir') != '' && !$already_uploaded; if ($already_uploaded) { $attachmentOptions['tmp_name'] = $modSettings['attachmentUploadDir'] . '/' . $attachmentOptions['tmp_name']; } // Make sure the file actually exists... sometimes it doesn't. if (!$file_restricted && !file_exists($attachmentOptions['tmp_name']) || !$already_uploaded && !is_uploaded_file($attachmentOptions['tmp_name'])) { $attachmentOptions['errors'] = array('could_not_upload'); return false; } if (!$file_restricted || $already_uploaded) { list($attachmentOptions['width'], $attachmentOptions['height']) = @getimagesize($attachmentOptions['tmp_name']); } // Get the hash if no hash has been given yet. if (empty($attachmentOptions['file_hash'])) { $attachmentOptions['file_hash'] = getAttachmentFilename($attachmentOptions['name'], false, true); } // Is the file too big? if (!empty($modSettings['attachmentSizeLimit']) && $attachmentOptions['size'] > $modSettings['attachmentSizeLimit'] * 1024) { $attachmentOptions['errors'][] = 'too_large'; } if (!empty($modSettings['attachmentCheckExtensions'])) { $allowed = explode(',', strtolower($modSettings['attachmentExtensions'])); foreach ($allowed as $k => $dummy) { $allowed[$k] = trim($dummy); } if (!in_array(strtolower(substr(strrchr($attachmentOptions['name'], '.'), 1)), $allowed)) { $attachmentOptions['errors'][] = 'bad_extension'; } } if (!empty($modSettings['attachmentDirSizeLimit'])) { // Make sure the directory isn't full. $dirSize = 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; } $dirSize += filesize($modSettings['attachmentUploadDir'] . '/' . $file); } closedir($dir); // Too big! Maybe you could zip it or something... if ($attachmentOptions['size'] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024) { $attachmentOptions['errors'][] = 'directory_full'; } } // Check if the file already exists.... (for those who do not encrypt their filenames...) if (empty($modSettings['attachmentEncryptFilenames'])) { // Make sure they aren't trying to upload a nasty file. $disabledFiles = array('con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php'); if (in_array(strtolower(basename($attachmentOptions['name'])), $disabledFiles)) { $attachmentOptions['errors'][] = 'bad_filename'; } // Check if there's another file with that name... $request = db_query("\n\t\t\tSELECT ID_ATTACH\n\t\t\tFROM {$db_prefix}attachments\n\t\t\tWHERE filename = '" . strtolower($attachmentOptions['name']) . "'\n\t\t\tLIMIT 1", __FILE__, __LINE__); if (mysql_num_rows($request) > 0) { $attachmentOptions['errors'][] = 'taken_filename'; } mysql_free_result($request); } if (!empty($attachmentOptions['errors'])) { return false; } if (!is_writable($modSettings['attachmentUploadDir'])) { fatal_lang_error('attachments_no_write'); } db_query("\n\t\tINSERT INTO {$db_prefix}attachments\n\t\t\t(ID_MSG, filename, file_hash, size, width, height)\n\t\tVALUES (" . (int) $attachmentOptions['post'] . ", SUBSTRING('" . $attachmentOptions['name'] . "', 1, 255), '{$attachmentOptions['file_hash']}', " . (int) $attachmentOptions['size'] . ', ' . (empty($attachmentOptions['width']) ? '0' : (int) $attachmentOptions['width']) . ', ' . (empty($attachmentOptions['height']) ? '0' : (int) $attachmentOptions['height']) . ')', __FILE__, __LINE__); $attachmentOptions['id'] = db_insert_id(); if (empty($attachmentOptions['id'])) { return false; } $attachmentOptions['destination'] = getAttachmentFilename(basename($attachmentOptions['name']), $attachmentOptions['id'], false, $attachmentOptions['file_hash']); if ($already_uploaded) { rename($attachmentOptions['tmp_name'], $attachmentOptions['destination']); } elseif (!move_uploaded_file($attachmentOptions['tmp_name'], $attachmentOptions['destination'])) { fatal_lang_error('smf124'); } elseif ($file_restricted) { list($attachmentOptions['width'], $attachmentOptions['height']) = @getimagesize($attachmentOptions['destination']); if (!empty($attachmentOptions['width']) && !empty($attachmentOptions['height'])) { db_query("\n\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\tSET\n\t\t\t\t\twidth = " . (int) $attachmentOptions['width'] . ",\n\t\t\t\t\theight = " . (int) $attachmentOptions['height'] . "\n\t\t\t\tWHERE ID_ATTACH = {$attachmentOptions['id']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); } } // Attempt to chmod it. @chmod($attachmentOptions['destination'], 0644); if (!empty($attachmentOptions['skip_thumbnail']) || empty($attachmentOptions['width']) && empty($attachmentOptions['height'])) { return true; } // Like thumbnails, do we? if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachmentOptions['width'] > $modSettings['attachmentThumbWidth'] || $attachmentOptions['height'] > $modSettings['attachmentThumbHeight'])) { require_once $sourcedir . '/Subs-Graphics.php'; if (createThumbnail($attachmentOptions['destination'], $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // Figure out how big we actually made it. list($thumb_width, $thumb_height) = @getimagesize($attachmentOptions['destination'] . '_thumb'); $thumb_filename = addslashes($attachmentOptions['name'] . '_thumb'); $thumb_size = filesize($attachmentOptions['destination'] . '_thumb'); // To the database we go! $thumb_file_hash = getAttachmentFilename($thumb_filename, false, true); db_query("\n\t\t\t\tINSERT INTO {$db_prefix}attachments\n\t\t\t\t\t(ID_MSG, attachmentType, filename, file_hash, size, width, height)\n\t\t\t\tVALUES (" . (int) $attachmentOptions['post'] . ", 3, SUBSTRING('{$thumb_filename}', 1, 255), '{$thumb_file_hash}', " . (int) $thumb_size . ", " . (int) $thumb_width . ", " . (int) $thumb_height . ")", __FILE__, __LINE__); $attachmentOptions['thumb'] = db_insert_id(); if (!empty($attachmentOptions['thumb'])) { db_query("\n\t\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\t\tSET ID_THUMB = {$attachmentOptions['thumb']}\n\t\t\t\t\tWHERE ID_ATTACH = {$attachmentOptions['id']}\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__); rename($attachmentOptions['destination'] . '_thumb', getAttachmentFilename($thumb_filename, $attachmentOptions['thumb'], false, $thumb_file_hash)); } } } return true; }
function createAttachment(&$attachmentOptions) { global $modSettings, $sourcedir, $backend_subdir; require_once $sourcedir . '/lib/Subs-Graphics.php'; // We need to know where this thing is going. if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } // Just use the current path for temp files. $attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; $id_folder = $modSettings['currentAttachmentUploadDir']; } else { $attach_dir = $modSettings['attachmentUploadDir']; $id_folder = 1; } $attachmentOptions['errors'] = array(); if (!isset($attachmentOptions['post'])) { $attachmentOptions['post'] = 0; } if (!isset($attachmentOptions['approved'])) { $attachmentOptions['approved'] = 1; } $already_uploaded = preg_match('~^post_tmp_' . $attachmentOptions['poster'] . '_\\d+$~', $attachmentOptions['tmp_name']) != 0; $file_restricted = @ini_get('open_basedir') != '' && !$already_uploaded; if ($already_uploaded) { $attachmentOptions['tmp_name'] = $attach_dir . '/' . $attachmentOptions['tmp_name']; } // Make sure the file actually exists... sometimes it doesn't. if (!$file_restricted && !file_exists($attachmentOptions['tmp_name']) || !$already_uploaded && !is_uploaded_file($attachmentOptions['tmp_name'])) { $attachmentOptions['errors'] = array('could_not_upload'); return false; } // These are the only valid image types for SMF. $validImageTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 5 => 'psd', 6 => 'bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpeg', 14 => 'iff'); if (!$file_restricted || $already_uploaded) { $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]]; } } } // Get the hash if no hash has been given yet. if (empty($attachmentOptions['file_hash'])) { $attachmentOptions['file_hash'] = getAttachmentFilename($attachmentOptions['name'], false, null, true); } // Is the file too big? if (!empty($modSettings['attachmentSizeLimit']) && $attachmentOptions['size'] > $modSettings['attachmentSizeLimit'] * 1024) { $attachmentOptions['errors'][] = 'too_large'; } if (!empty($modSettings['attachmentCheckExtensions'])) { $allowed = explode(',', strtolower($modSettings['attachmentExtensions'])); foreach ($allowed as $k => $dummy) { $allowed[$k] = trim($dummy); } if (!in_array(strtolower(substr(strrchr($attachmentOptions['name'], '.'), 1)), $allowed)) { $attachmentOptions['errors'][] = 'bad_extension'; } } if (!empty($modSettings['attachmentDirSizeLimit'])) { // This is a really expensive operation for big numbers of // attachments, which is also very easy to cache. Only do it // every ten minutes. if (empty($modSettings['attachment_dirsize']) || empty($modSettings['attachment_dirsize_time']) || $modSettings['attachment_dirsize_time'] < time() - 600) { // It has been cached - just work with this value for now! $dirSize = $modSettings['attachment_dirsize']; } else { // Make sure the directory isn't full. $dirSize = 0; $dir = @opendir($attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical'); while ($file = readdir($dir)) { if ($file == '.' || $file == '..') { continue; } if (preg_match('~^post_tmp_\\d+_\\d+$~', $file) != 0) { // Temp file is more than 5 hours old! if (filemtime($attach_dir . '/' . $file) < time() - 18000) { @unlink($attach_dir . '/' . $file); } continue; } $dirSize += filesize($attach_dir . '/' . $file); } closedir($dir); updateSettings(array('attachment_dirsize' => $dirSize, 'attachment_dirsize_time' => time())); } // Too big! Maybe you could zip it or something... if ($attachmentOptions['size'] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024) { $attachmentOptions['errors'][] = 'directory_full'; } elseif (!isset($modSettings['attachment_full_notified']) && $modSettings['attachmentDirSizeLimit'] > 4000 && $attachmentOptions['size'] + $dirSize > ($modSettings['attachmentDirSizeLimit'] - 2000) * 1024) { require_once $sourcedir . '/lib/Subs-Admin.php'; emailAdmins('admin_attachments_full'); updateSettings(array('attachment_full_notified' => 1)); } } // Check if the file already exists.... (for those who do not encrypt their filenames...) if (empty($modSettings['attachmentEncryptFilenames'])) { // Make sure they aren't trying to upload a nasty file. $disabledFiles = array('con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php'); if (in_array(strtolower(basename($attachmentOptions['name'])), $disabledFiles)) { $attachmentOptions['errors'][] = 'bad_filename'; } // Check if there's another file with that name... $request = smf_db_query(' SELECT id_attach FROM {db_prefix}attachments WHERE filename = {string:filename} LIMIT 1', array('filename' => strtolower($attachmentOptions['name']))); if (mysql_num_rows($request) > 0) { $attachmentOptions['errors'][] = 'taken_filename'; } mysql_free_result($request); } if (!empty($attachmentOptions['errors'])) { return false; } if (!is_writable($attach_dir)) { fatal_lang_error('attachments_no_write', 'critical'); } // 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'] = ''; } } smf_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($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'] = smf_db_insert_id('{db_prefix}attachments', 'id_attach'); if (empty($attachmentOptions['id'])) { return false; } // If it's not approved add to the approval queue. if (!$attachmentOptions['approved']) { smf_db_insert('', '{db_prefix}approval_queue', array('id_attach' => 'int', 'id_msg' => 'int'), array($attachmentOptions['id'], (int) $attachmentOptions['post']), array()); } $attachmentOptions['destination'] = getAttachmentFilename(basename($attachmentOptions['name']), $attachmentOptions['id'], $id_folder, false, $attachmentOptions['file_hash']); if ($already_uploaded) { rename($attachmentOptions['tmp_name'], $attachmentOptions['destination']); } elseif (!move_uploaded_file($attachmentOptions['tmp_name'], $attachmentOptions['destination'])) { fatal_lang_error('attach_timeout', 'critical'); } // Udate the cached directory size, if we care for it. if (!empty($modSettings['attachmentDirSizeLimit'])) { updateSettings(array('attachment_dirsize' => $modSettings['attachment_dirsize'] + $attachmentOptions['size'], 'attachment_dirsize_time' => time())); } // Attempt to chmod it. @chmod($attachmentOptions['destination'], 0644); $size = @getimagesize($attachmentOptions['destination']); list($attachmentOptions['width'], $attachmentOptions['height']) = empty($size) ? array(null, null, null) : $size; // We couldn't access the file before... if ($file_restricted) { // Have a go at getting the right mime type. if (empty($attachmentOptions['mime_type']) && $attachmentOptions['width']) { if (!empty($size['mime'])) { $attachmentOptions['mime_type'] = $size['mime']; } elseif (isset($validImageTypes[$size[2]])) { $attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]]; } } if (!empty($attachmentOptions['width']) && !empty($attachmentOptions['height'])) { smf_db_query(' UPDATE {db_prefix}attachments SET width = {int:width}, height = {int:height}, mime_type = {string:mime_type} WHERE id_attach = {int:id_attach}', array('width' => (int) $attachmentOptions['width'], 'height' => (int) $attachmentOptions['height'], 'id_attach' => $attachmentOptions['id'], 'mime_type' => empty($attachmentOptions['mime_type']) ? '' : $attachmentOptions['mime_type'])); } } // Security checks for images // Do we have an image? If yes, we need to check it out! if (isset($validImageTypes[$size[2]])) { if (!checkImageContents($attachmentOptions['destination'], !empty($modSettings['attachment_image_paranoid']))) { // It's bad. Last chance, maybe we can re-encode it? if (empty($modSettings['attachment_image_reencode']) || !reencodeImage($attachmentOptions['destination'], $size[2])) { // Nothing to do: not allowed or not successful re-encoding it. require_once $sourcedir . '/lib/Subs-ManageAttachments.php'; removeAttachments(array('id_attach' => $attachmentOptions['id'])); $attachmentOptions['id'] = null; $attachmentOptions['errors'][] = 'bad_attachment'; return false; } // Success! However, successes usually come for a price: // we might get a new format for our image... $old_format = $size[2]; $size = @getimagesize($attachmentOptions['destination']); if (!empty($size) && $size[2] != $old_format) { // Let's update the image information // !!! This is becoming a mess: we keep coming back and update the database, // instead of getting it right the first time. if (isset($validImageTypes[$size[2]])) { $attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]]; smf_db_query(' UPDATE {db_prefix}attachments SET mime_type = {string:mime_type} WHERE id_attach = {int:id_attach}', array('id_attach' => $attachmentOptions['id'], 'mime_type' => $attachmentOptions['mime_type'])); } } } } if (!empty($attachmentOptions['skip_thumbnail']) || empty($attachmentOptions['width']) && empty($attachmentOptions['height'])) { return true; } // Like thumbnails, do we? if (!empty($modSettings['attachmentThumbnails']) && !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, false, null, true); // To the database we go! smf_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($id_folder, (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'] = smf_db_insert_id('{db_prefix}attachments', 'id_attach'); if (!empty($attachmentOptions['thumb'])) { smf_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($attachmentOptions['destination'] . '_thumb', getAttachmentFilename($thumb_filename, $attachmentOptions['thumb'], $id_folder, false, $thumb_file_hash)); } } } return true; }
function removeAllAttachments() { global $to_prefix, $smcFunc; $result = convert_query("\n\t\tSELECT value\n\t\tFROM {$to_prefix}settings\n\t\tWHERE variable = 'attachmentUploadDir'\n\t\tLIMIT 1"); list($attachmentUploadDir) = $smcFunc['db_fetch_row']($result); $smcFunc['db_free_result']($result); // !!! This should probably be done in chunks too. $result = convert_query("\n\t\tSELECT id_attach, filename\n\t\tFROM {$to_prefix}attachments"); while ($row = $smcFunc['db_fetch_assoc']($result)) { $filename = $row['filename']; $id_attach = $row['id_attach']; $physical_filename = getAttachmentFilename($filename, $id_attach); if (file_exists($physical_filename)) { @unlink($physical_filename); } } $smcFunc['db_free_result']($result); }
function downloadAvatar($url, $memID, $max_width, $max_height) { global $modSettings, $db_prefix, $sourcedir, $gd2; $destName = 'avatar_' . $memID . '.' . (!empty($modSettings['avatar_download_png']) ? 'png' : 'jpeg'); $default_formats = array('1' => 'gif', '2' => 'jpeg', '3' => 'png', '6' => 'bmp', '15' => 'wbmp'); // Check to see if GD is installed and what version. $testGD = get_extension_funcs('gd'); // If GD is not installed, this function is pointless. if (empty($testGD)) { return false; } // Just making sure there is a non-zero member. if (empty($memID)) { return false; } // GD 2 maybe? $gd2 = in_array('imagecreatetruecolor', $testGD) && function_exists('imagecreatetruecolor'); unset($testGD); require_once $sourcedir . '/ManageAttachments.php'; removeAttachments('a.ID_MEMBER = ' . $memID); $avatar_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, true) : ''; db_query("\n\t\tINSERT INTO {$db_prefix}attachments\n\t\t\t(ID_MEMBER, attachmentType, filename, file_hash, size)\n\t\tVALUES ({$memID}, " . (empty($modSettings['custom_avatar_enabled']) ? '0' : '1') . ", '{$destName}', '" . (empty($avatar_hash) ? "" : "{$avatar_hash}") . "', 1)", __FILE__, __LINE__); $attachID = db_insert_id(); $destName = (empty($modSettings['custom_avatar_enabled']) ? $modSettings['attachmentUploadDir'] : $modSettings['custom_avatar_dir']) . '/' . $destName . '.tmp'; $success = false; $sizes = url_image_size($url); require_once $sourcedir . '/Subs-Package.php'; $fp = fopen($destName, 'wb'); if ($fp && substr($url, 0, 7) == 'http://') { $fileContents = fetch_web_data($url); // Though not an exhaustive list, better safe than sorry. if (preg_match('~(iframe|\\<\\?php|\\<\\?[\\s=]|\\<%[\\s=]|html|eval|body|script\\W)~', $fileContents) === 1) { fclose($fp); return false; } fwrite($fp, $fileContents); fclose($fp); } elseif ($fp) { $fp2 = fopen($url, 'rb'); $prev_chunk = ''; while (!feof($fp2)) { $cur_chunk = fread($fp2, 8192); // Make sure nothing odd came through. if (preg_match('~(iframe|\\<\\?php|\\<\\?[\\s=]|\\<%[\\s=]|html|eval|body|script\\W)~', $prev_chunk . $cur_chunk) === 1) { fclose($fp2); fclose($fp); unlink($destName); return false; } fwrite($fp, $cur_chunk); $prev_chunk = $cur_chunk; } fclose($fp2); fclose($fp); } else { $sizes = array(-1, -1, -1); } // Gif? That might mean trouble if gif support is not available. if ($sizes[2] == 1 && !function_exists('imagecreatefromgif') && function_exists('imagecreatefrompng')) { // Download it to the temporary file... use the special gif library... and save as png. if ($img = @gif_loadFile($destName) && gif_outputAsPng($img, $destName)) { $sizes[2] = 3; } } // A known and supported format? if (isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]])) { $imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]]; if ($src_img = @$imagecreatefrom($destName)) { resizeImage($src_img, $destName, imagesx($src_img), imagesy($src_img), $max_width, $max_height); $success = true; } } // Remove the .tmp extension. $destName = substr($destName, 0, -4); if ($success) { // Remove the .tmp extension from the attachment. if (rename($destName . '.tmp', empty($avatar_hash) ? $destName : $modSettings['attachmentUploadDir'] . '/' . $attachID . '_' . $avatar_hash)) { $destName = empty($avatar_hash) ? $destName : $modSettings['attachmentUploadDir'] . '/' . $attachID . '_' . $avatar_hash; list($width, $height) = getimagesize($destName); // Write filesize in the database. db_query("\n\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\tSET size = " . filesize($destName) . ", width = " . (int) $width . ", height = " . (int) $height . "\n\t\t\t\tWHERE ID_ATTACH = {$attachID}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); return true; } else { return false; } } else { db_query("\n\t\t\tDELETE FROM {$db_prefix}attachments\n\t\t\tWHERE ID_ATTACH = {$attachID}\n\t\t\tLIMIT 1", __FILE__, __LINE__); @unlink($destName . '.tmp'); return false; } }
/** * 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'); }
/** * This loads an attachment's contextual data including, most importantly, its size if it is an image. * * What it does: * - Pre-condition: $attachments array to have been filled with the proper attachment data, as Display() does. * - It requires the view_attachments permission to calculate image size. * - It attempts to keep the "aspect ratio" of the posted image in line, even if it has to be resized by * the max_image_width and max_image_height settings. * * @todo change this pre-condition, too fragile and error-prone. * * @package Attachments * @param int $id_msg message number to load attachments for * @return array of attachments */ function loadAttachmentContext($id_msg) { global $attachments, $modSettings, $txt, $scripturl, $topic; // Set up the attachment info - based on code by Meriadoc. $attachmentData = array(); $have_unapproved = false; if (isset($attachments[$id_msg]) && !empty($modSettings['attachmentEnable'])) { foreach ($attachments[$id_msg] as $i => $attachment) { $attachmentData[$i] = array('id' => $attachment['id_attach'], 'name' => preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($attachment['filename'], ENT_COMPAT, 'UTF-8')), 'downloads' => $attachment['downloads'], 'size' => $attachment['filesize'] < 1024000 ? round($attachment['filesize'] / 1024, 2) . ' ' . $txt['kilobyte'] : round($attachment['filesize'] / 1024 / 1024, 2) . ' ' . $txt['megabyte'], 'byte_size' => $attachment['filesize'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_attach'], 'link' => '<a href="' . $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_attach'] . '">' . htmlspecialchars($attachment['filename'], ENT_COMPAT, 'UTF-8') . '</a>', 'is_image' => !empty($attachment['width']) && !empty($attachment['height']) && !empty($modSettings['attachmentShowImages']), 'is_approved' => $attachment['approved'], 'file_hash' => $attachment['file_hash']); // If something is unapproved we'll note it so we can sort them. if (!$attachment['approved']) { $have_unapproved = true; } if (!$attachmentData[$i]['is_image']) { continue; } $attachmentData[$i]['real_width'] = $attachment['width']; $attachmentData[$i]['width'] = $attachment['width']; $attachmentData[$i]['real_height'] = $attachment['height']; $attachmentData[$i]['height'] = $attachment['height']; // Let's see, do we want thumbs? if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachment['width'] > $modSettings['attachmentThumbWidth'] || $attachment['height'] > $modSettings['attachmentThumbHeight']) && strlen($attachment['filename']) < 249) { // A proper thumb doesn't exist yet? Create one! Or, it needs update. if (empty($attachment['id_thumb']) || $attachment['thumb_width'] > $modSettings['attachmentThumbWidth'] || $attachment['thumb_height'] > $modSettings['attachmentThumbHeight'] || $attachment['thumb_width'] < $modSettings['attachmentThumbWidth'] && $attachment['thumb_height'] < $modSettings['attachmentThumbHeight']) { $filename = getAttachmentFilename($attachment['filename'], $attachment['id_attach'], $attachment['id_folder'], false, $attachment['file_hash']); $attachment = array_merge($attachment, updateAttachmentThumbnail($filename, $attachment['id_attach'], $id_msg, $attachment['id_thumb'])); } // Only adjust dimensions on successful thumbnail creation. if (!empty($attachment['thumb_width']) && !empty($attachment['thumb_height'])) { $attachmentData[$i]['width'] = $attachment['thumb_width']; $attachmentData[$i]['height'] = $attachment['thumb_height']; } } if (!empty($attachment['id_thumb'])) { $attachmentData[$i]['thumbnail'] = array('id' => $attachment['id_thumb'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_thumb'] . ';image'); } $attachmentData[$i]['thumbnail']['has_thumb'] = !empty($attachment['id_thumb']); // If thumbnails are disabled, check the maximum size of the image. if (!$attachmentData[$i]['thumbnail']['has_thumb'] && (!empty($modSettings['max_image_width']) && $attachment['width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachment['height'] > $modSettings['max_image_height'])) { if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $attachment['height'] * $modSettings['max_image_width'] / $attachment['width'] <= $modSettings['max_image_height'])) { $attachmentData[$i]['width'] = $modSettings['max_image_width']; $attachmentData[$i]['height'] = floor($attachment['height'] * $modSettings['max_image_width'] / $attachment['width']); } elseif (!empty($modSettings['max_image_width'])) { $attachmentData[$i]['width'] = floor($attachment['width'] * $modSettings['max_image_height'] / $attachment['height']); $attachmentData[$i]['height'] = $modSettings['max_image_height']; } } elseif ($attachmentData[$i]['thumbnail']['has_thumb']) { // If the image is too large to show inline, make it a popup. if (!empty($modSettings['max_image_width']) && $attachmentData[$i]['real_width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachmentData[$i]['real_height'] > $modSettings['max_image_height']) { $attachmentData[$i]['thumbnail']['javascript'] = 'return reqWin(\'' . $attachmentData[$i]['href'] . ';image\', ' . ($attachment['width'] + 20) . ', ' . ($attachment['height'] + 20) . ', true);'; } else { $attachmentData[$i]['thumbnail']['javascript'] = 'return expandThumb(' . $attachment['id_attach'] . ');'; } } if (!$attachmentData[$i]['thumbnail']['has_thumb']) { $attachmentData[$i]['downloads']++; } } } // Do we need to instigate a sort? if ($have_unapproved) { usort($attachmentData, 'approved_attach_sort'); } return $attachmentData; }
/** * Create an attachment, with the given array of parameters. * - 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. * * @param array $attachmentOptions */ function createAttachment(&$attachmentOptions) { global $modSettings, $sourcedir, $smcFunc, $context; global $txt, $boarddir; require_once $sourcedir . '/Subs-Graphics.php'; // These are the only valid image types for SMF. $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]]; } } // Get the hash if no hash has been given yet. if (empty($attachmentOptions['file_hash'])) { $attachmentOptions['file_hash'] = getAttachmentFilename($attachmentOptions['name'], false, 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'] = ''; } } $smcFunc['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'] = $smcFunc['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 sucker 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']) { $smcFunc['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, false, 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'] = $thumb_size; $context['dir_files'] = 1; } } } // 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! $smcFunc['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'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); if (!empty($attachmentOptions['thumb'])) { $smcFunc['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; }
/** * Move avatars to their new directory. * * @package Attachments */ function moveAvatars() { global $modSettings; $db = database(); $request = $db->query('', ' SELECT id_attach, id_folder, id_member, filename, file_hash FROM {db_prefix}attachments WHERE attachment_type = {int:attachment_type} AND id_member > {int:guest_id_member}', array('attachment_type' => 0, 'guest_id_member' => 0)); $updatedAvatars = array(); while ($row = $db->fetch_assoc($request)) { $filename = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); if (rename($filename, $modSettings['custom_avatar_dir'] . '/' . $row['filename'])) { $updatedAvatars[] = $row['id_attach']; } } $db->free_result($request); if (!empty($updatedAvatars)) { $db->query('', ' UPDATE {db_prefix}attachments SET attachment_type = {int:attachment_type} WHERE id_attach IN ({array_int:updated_avatars})', array('updated_avatars' => $updatedAvatars, 'attachment_type' => 1)); } }
function Post() { global $txt, $scripturl, $topic, $db_prefix, $modSettings, $board, $ID_MEMBER; global $user_info, $sc, $board_info, $context, $settings, $sourcedir; global $options, $func, $language; loadLanguage('Post'); $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new'); // You can't reply with a poll... hacker. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg'])) { unset($_REQUEST['poll']); } // Posting an event? $context['make_event'] = isset($_REQUEST['calendar']); // You must be posting to *some* board. if (empty($board) && !$context['make_event']) { fatal_lang_error('smf232', false); } require_once $sourcedir . '/Subs-Post.php'; if (isset($_REQUEST['xml'])) { $context['sub_template'] = 'post'; // Just in case of an earlier error... $context['preview_message'] = ''; $context['preview_subject'] = ''; } // Check if it's locked. It isn't locked if no topic is specified. if (!empty($topic)) { $request = db_query("\n\t\t\tSELECT\n\t\t\t\tt.locked, IFNULL(ln.ID_TOPIC, 0) AS notify, t.isSticky, t.ID_POLL, t.numReplies, mf.ID_MEMBER,\n\t\t\t\tt.ID_FIRST_MSG, mf.subject, GREATEST(ml.posterTime, ml.modifiedTime) AS lastPostTime\n\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\tLEFT JOIN {$db_prefix}log_notify AS ln ON (ln.ID_TOPIC = t.ID_TOPIC AND ln.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tLEFT JOIN {$db_prefix}messages AS mf ON (mf.ID_MSG = t.ID_FIRST_MSG)\n\t\t\t\tLEFT JOIN {$db_prefix}messages AS ml ON (ml.ID_MSG = t.ID_LAST_MSG)\n\t\t\tWHERE t.ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__); list($locked, $context['notify'], $sticky, $pollID, $context['num_replies'], $ID_MEMBER_POSTER, $ID_FIRST_MSG, $first_subject, $lastPostTime) = mysql_fetch_row($request); mysql_free_result($request); // If this topic already has a poll, they sure can't add another. if (isset($_REQUEST['poll']) && $pollID > 0) { unset($_REQUEST['poll']); } if (empty($_REQUEST['msg'])) { if ($user_info['is_guest'] && !allowedTo('post_reply_any')) { is_not_guest(); } if ($ID_MEMBER_POSTER != $ID_MEMBER) { isAllowedTo('post_reply_any'); } elseif (!allowedTo('post_reply_any')) { isAllowedTo('post_reply_own'); } } $context['can_lock'] = allowedTo('lock_any') || $ID_MEMBER == $ID_MEMBER_POSTER && allowedTo('lock_own'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky; } else { if ((!$context['make_event'] || !empty($board)) && (!isset($_REQUEST['poll']) || $modSettings['pollMode'] != '1')) { isAllowedTo('post_new'); } $locked = 0; // !!! These won't work if you're making an event. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own')); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = !empty($_REQUEST['sticky']); } // !!! These won't work if you're posting an event! $context['can_notify'] = allowedTo('mark_any_notify'); $context['can_move'] = allowedTo('move_any'); $context['can_announce'] = allowedTo('announce_topic'); $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']); // An array to hold all the attachments for this topic. $context['current_attachments'] = array(); // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) { fatal_lang_error(90, false); } // Check the users permissions - is the user allowed to add or post a poll? if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') { // New topic, new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($ID_MEMBER == $ID_MEMBER_POSTER && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } // Set up the poll options. $context['poll_options'] = array('max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']), 'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'], 'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'], 'change_vote' => isset($_POST['poll_change_vote'])); // Make all five poll choices empty. $context['choices'] = array(array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false), array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false), array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false), array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false), array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)); } if ($context['make_event']) { // They might want to pick a board. if (!isset($context['current_board'])) { $context['current_board'] = 0; } // Start loading up the event info. $context['event'] = array(); $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle'])) : ''; $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1; $context['event']['new'] = $context['event']['id'] == -1; // Permissions check! isAllowedTo('calendar_post'); // Editing an event? (but NOT previewing!?) if (!$context['event']['new'] && !isset($_REQUEST['subject'])) { // If the user doesn't have permission to edit the post in this topic, redirect them. if ($ID_MEMBER_POSTER != $ID_MEMBER || !allowedTo('modify_own') && !allowedTo('modify_any')) { require_once $sourcedir . '/Calendar.php'; return CalendarPost(); } // Get the current event information. $request = db_query("\n\t\t\t\tSELECT\n\t\t\t\t\tID_MEMBER, title, MONTH(startDate) AS month, DAYOFMONTH(startDate) AS day,\n\t\t\t\t\tYEAR(startDate) AS year, (TO_DAYS(endDate) - TO_DAYS(startDate)) AS span\n\t\t\t\tFROM {$db_prefix}calendar\n\t\t\t\tWHERE ID_EVENT = " . $context['event']['id'] . "\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); $row = mysql_fetch_assoc($request); mysql_free_result($request); // Make sure the user is allowed to edit this event. if ($row['ID_MEMBER'] != $ID_MEMBER) { isAllowedTo('calendar_edit_any'); } elseif (!allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_own'); } $context['event']['month'] = $row['month']; $context['event']['day'] = $row['day']; $context['event']['year'] = $row['year']; $context['event']['title'] = $row['title']; $context['event']['span'] = $row['span'] + 1; } else { $today = getdate(); // You must have a month and year specified! if (!isset($_REQUEST['month'])) { $_REQUEST['month'] = $today['mon']; } if (!isset($_REQUEST['year'])) { $_REQUEST['year'] = $today['year']; } $context['event']['month'] = (int) $_REQUEST['month']; $context['event']['year'] = (int) $_REQUEST['year']; $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0); $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1; // Make sure the year and month are in the valid range. if ($context['event']['month'] < 1 || $context['event']['month'] > 12) { fatal_lang_error('calendar1', false); } if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear']) { fatal_lang_error('calendar2', false); } // Get a list of boards they can post in. $boards = boardsAllowedTo('post_new'); if (empty($boards)) { fatal_lang_error('cannot_post_new'); } $request = db_query("\n\t\t\t\tSELECT c.name AS catName, c.ID_CAT, b.ID_BOARD, b.name AS boardName, b.childLevel\n\t\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\t\tLEFT JOIN {$db_prefix}categories AS c ON (c.ID_CAT = b.ID_CAT)\n\t\t\t\tWHERE {$user_info['query_see_board']}" . (in_array(0, $boards) ? '' : "\n\t\t\t\t\tAND b.ID_BOARD IN (" . implode(', ', $boards) . ")"), __FILE__, __LINE__); $context['event']['boards'] = array(); while ($row = mysql_fetch_assoc($request)) { $context['event']['boards'][] = array('id' => $row['ID_BOARD'], 'name' => $row['boardName'], 'childLevel' => $row['childLevel'], 'prefix' => str_repeat(' ', $row['childLevel'] * 3), 'cat' => array('id' => $row['ID_CAT'], 'name' => $row['catName'])); } mysql_free_result($request); } // Find the last day of the month. $context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year'])); $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard']; } if (empty($context['post_errors'])) { $context['post_errors'] = array(); } // See if any new replies have come along. if (empty($_REQUEST['msg']) && !empty($topic)) { if (empty($options['no_new_reply_warning']) && isset($_REQUEST['num_replies'])) { $newReplies = $context['num_replies'] > $_REQUEST['num_replies'] ? $context['num_replies'] - $_REQUEST['num_replies'] : 0; if (!empty($newReplies)) { if ($newReplies == 1) { $txt['error_new_reply'] = isset($_GET['num_replies']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply']; } else { $txt['error_new_replies'] = sprintf(isset($_GET['num_replies']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $newReplies); } // If they've come from the display page then we treat the error differently.... if (isset($_GET['num_replies'])) { $newRepliesError = $newReplies; } else { $context['post_error'][$newReplies == 1 ? 'new_reply' : 'new_replies'] = true; } $modSettings['topicSummaryPosts'] = $newReplies > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts']; } } // Check whether this is a really old post being bumped... if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject'])) { $oldTopicError = true; } } // Get a response prefix (like 'Re:') in the default forum language. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix'))) { if ($language === $user_info['language']) { $context['response_prefix'] = $txt['response_prefix']; } else { loadLanguage('index', $language, false); $context['response_prefix'] = $txt['response_prefix']; loadLanguage('index'); } cache_put_data('response_prefix', $context['response_prefix'], 600); } // Previewing, modifying, or posting? if (isset($_REQUEST['message']) || !empty($context['post_error'])) { // Validate inputs. if (empty($context['post_error'])) { if ($func['htmltrim']($_REQUEST['subject']) == '') { $context['post_error']['no_subject'] = true; } if ($func['htmltrim']($_REQUEST['message']) == '') { $context['post_error']['no_message'] = true; } if (!empty($modSettings['max_messageLength']) && $func['strlen']($_REQUEST['message']) > $modSettings['max_messageLength']) { $context['post_error']['long_message'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']); $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']); // Validate the name and email. if (!isset($_REQUEST['guestname']) || trim(strtr($_REQUEST['guestname'], '_', ' ')) == '') { $context['post_error']['no_name'] = true; } elseif ($func['strlen']($_REQUEST['guestname']) > 25) { $context['post_error']['long_name'] = true; } else { require_once $sourcedir . '/Subs-Members.php'; if (isReservedName(htmlspecialchars($_REQUEST['guestname']), 0, true, false)) { $context['post_error']['bad_name'] = true; } } if (empty($modSettings['guest_post_no_email'])) { if (!isset($_REQUEST['email']) || $_REQUEST['email'] == '') { $context['post_error']['no_email'] = true; } elseif (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', stripslashes($_REQUEST['email'])) == 0) { $context['post_error']['bad_email'] = true; } } } // This is self explanatory - got any questions? if (isset($_REQUEST['question']) && trim($_REQUEST['question']) == '') { $context['post_error']['no_question'] = true; } // This means they didn't click Post and get an error. $really_previewing = true; } else { if (!isset($_REQUEST['subject'])) { $_REQUEST['subject'] = ''; } if (!isset($_REQUEST['message'])) { $_REQUEST['message'] = ''; } if (!isset($_REQUEST['icon'])) { $_REQUEST['icon'] = 'xx'; } $really_previewing = false; } // Set up the inputs for the form. $form_subject = strtr($func['htmlspecialchars'](stripslashes($_REQUEST['subject'])), array("\r" => '', "\n" => '', "\t" => '')); $form_message = $func['htmlspecialchars'](stripslashes($_REQUEST['message']), ENT_QUOTES); // Make sure the subject isn't too long - taking into account special characters. if ($func['strlen']($form_subject) > 100) { $form_subject = $func['substr']($form_subject, 0, 100); } // Have we inadvertently trimmed off the subject of useful information? if ($func['htmltrim']($form_subject) === '') { $context['post_error']['no_subject'] = true; } // Any errors occurred? if (!empty($context['post_error'])) { loadLanguage('Errors'); $context['error_type'] = 'minor'; $context['post_error']['messages'] = array(); foreach ($context['post_error'] as $post_error => $dummy) { if ($post_error == 'messages') { continue; } $context['post_error']['messages'][] = $txt['error_' . $post_error]; // If it's not a minor error flag it as such. if (!in_array($post_error, array('new_reply', 'new_replies', 'old_topic'))) { $context['error_type'] = 'serious'; } } } if (isset($_REQUEST['poll'])) { $context['question'] = isset($_REQUEST['question']) ? $func['htmlspecialchars'](stripslashes(trim($_REQUEST['question']))) : ''; $context['choices'] = array(); $choice_id = 0; $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive(stripslashes__recursive($_POST['options'])); foreach ($_POST['options'] as $option) { if (trim($option) == '') { continue; } $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => $option, 'is_last' => false); } if (count($context['choices']) < 2) { $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); } $context['choices'][count($context['choices']) - 1]['is_last'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']); $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']); $_REQUEST['guestname'] = htmlspecialchars($_REQUEST['guestname']); $context['name'] = $_REQUEST['guestname']; $_REQUEST['email'] = htmlspecialchars($_REQUEST['email']); $context['email'] = $_REQUEST['email']; $user_info['name'] = $_REQUEST['guestname']; } // Only show the preview stuff if they hit Preview. if ($really_previewing == true || isset($_REQUEST['xml'])) { // Set up the preview message and subject and censor them... $context['preview_message'] = $form_message; preparsecode($form_message, true); preparsecode($context['preview_message']); // Do all bulletin board code tags, with or without smileys. $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1); if ($form_subject != '') { $context['preview_subject'] = $form_subject; censorText($context['preview_subject']); censorText($context['preview_message']); } else { $context['preview_subject'] = '<i>' . $txt[24] . '</i>'; } // Protect any CDATA blocks. if (isset($_REQUEST['xml'])) { $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>')); } } // Set up the checkboxes. $context['notify'] = !empty($_REQUEST['notify']); $context['use_smileys'] = !isset($_REQUEST['ns']); $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx'; // Set the destination action for submission. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';sesc=' . $sc : '') . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = isset($_REQUEST['msg']) ? $txt[10] : $txt[105]; // Previewing an edit? if (isset($_REQUEST['msg'])) { if (!empty($modSettings['attachmentEnable'])) { $request = db_query("\n\t\t\t\t\tSELECT IFNULL(size, -1) AS filesize, filename, ID_ATTACH\n\t\t\t\t\tFROM {$db_prefix}attachments\n\t\t\t\t\tWHERE ID_MSG = " . (int) $_REQUEST['msg'] . "\n\t\t\t\t\t\t AND attachmentType = 0", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) { if ($row['filesize'] <= 0) { continue; } $context['current_attachments'][] = array('name' => $row['filename'], 'id' => $row['ID_ATTACH']); } mysql_free_result($request); } // Allow moderators to change names.... if (allowedTo('moderate_forum') && !empty($topic)) { $request = db_query("\n\t\t\t\t\tSELECT ID_MEMBER, posterName, posterEmail\n\t\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\t\tWHERE ID_MSG = " . (int) $_REQUEST['msg'] . "\n\t\t\t\t\t\tAND ID_TOPIC = {$topic}\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__); $row = mysql_fetch_assoc($request); mysql_free_result($request); if (empty($row['ID_MEMBER'])) { $context['name'] = htmlspecialchars($row['posterName']); $context['email'] = htmlspecialchars($row['posterEmail']); } } } // No check is needed, since nothing is really posted. checkSubmitOnce('free'); } elseif (isset($_REQUEST['msg'])) { checkSession('get'); // Get the existing message. $request = db_query("\n\t\t\tSELECT\n\t\t\t\tm.ID_MEMBER, m.modifiedTime, m.smileysEnabled, m.body,\n\t\t\t\tm.posterName, m.posterEmail, m.subject, m.icon,\n\t\t\t\tIFNULL(a.size, -1) AS filesize, a.filename, a.ID_ATTACH,\n\t\t\t\tt.ID_MEMBER_STARTED AS ID_MEMBER_POSTER, m.posterTime\n\t\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t)\n\t\t\t\tLEFT JOIN {$db_prefix}attachments AS a ON (a.ID_MSG = m.ID_MSG AND a.attachmentType = 0)\n\t\t\tWHERE m.ID_MSG = " . (int) $_REQUEST['msg'] . "\n\t\t\t\tAND m.ID_TOPIC = {$topic}\n\t\t\t\tAND t.ID_TOPIC = {$topic}", __FILE__, __LINE__); // The message they were trying to edit was most likely deleted. // !!! Change this error message? if (mysql_num_rows($request) == 0) { fatal_lang_error('smf232', false); } $row = mysql_fetch_assoc($request); $attachment_stuff = array($row); while ($row2 = mysql_fetch_assoc($request)) { $attachment_stuff[] = $row2; } mysql_free_result($request); if ($row['ID_MEMBER'] == $ID_MEMBER && !allowedTo('modify_any')) { // Give an extra five minutes over the disable time threshold, so they can type. if (!empty($modSettings['edit_disable_time']) && $row['posterTime'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } // When was it last modified? if (!empty($row['modifiedTime'])) { $context['last_modified'] = timeformat($row['modifiedTime']); } // Get the stuff ready for the form. $form_subject = $row['subject']; $form_message = un_preparsecode($row['body']); censorText($form_message); censorText($form_subject); // Check the boxes that should be checked. $context['use_smileys'] = !empty($row['smileysEnabled']); $context['icon'] = $row['icon']; // Load up 'em attachments! foreach ($attachment_stuff as $attachment) { if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable'])) { $context['current_attachments'][] = array('name' => $attachment['filename'], 'id' => $attachment['ID_ATTACH']); } } // Allow moderators to change names.... if (allowedTo('moderate_forum') && empty($row['ID_MEMBER'])) { $context['name'] = htmlspecialchars($row['posterName']); $context['email'] = htmlspecialchars($row['posterEmail']); } // Set the destinaton. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';sesc=' . $sc . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt[10]; } else { // By default.... $context['use_smileys'] = true; $context['icon'] = 'xx'; if ($user_info['is_guest']) { $context['name'] = ''; $context['email'] = ''; } $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt[105]; // Posting a quoted reply? if (!empty($topic) && !empty($_REQUEST['quote'])) { checkSession('get'); // Make sure they _can_ quote this post, and if so get it. $request = db_query("\n\t\t\t\tSELECT m.subject, IFNULL(mem.realName, m.posterName) AS posterName, m.posterTime, m.body\n\t\t\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}boards AS b)\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = m.ID_MEMBER)\n\t\t\t\tWHERE m.ID_MSG = " . (int) $_REQUEST['quote'] . "\n\t\t\t\t\tAND b.ID_BOARD = m.ID_BOARD\n\t\t\t\t\tAND {$user_info['query_see_board']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); if (mysql_num_rows($request) == 0) { fatal_lang_error('quoted_post_deleted', false); } list($form_subject, $mname, $mdate, $form_message) = mysql_fetch_row($request); mysql_free_result($request); // Add 'Re: ' to the front of the quoted subject. if (trim($context['response_prefix']) != '' && $func['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the message and subject. censorText($form_message); censorText($form_subject); $form_message = preg_replace('~<br(?: /)?' . '>~i', "\n", $form_message); // Remove any nested quotes, if necessary. if (!empty($modSettings['removeNestedQuotes'])) { $form_message = preg_replace(array('~\\n?\\[quote.*?\\].+?\\[/quote\\]\\n?~is', '~^\\n~', '~\\[/quote\\]~'), '', $form_message); } // Add a quote string on the front and end. $form_message = '[quote author=' . $mname . ' link=topic=' . $topic . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . $form_message . "\n" . '[/quote]'; } elseif (!empty($topic) && empty($_REQUEST['quote'])) { // Get the first message's subject. $form_subject = $first_subject; // Add 'Re: ' to the front of the subject. if (trim($context['response_prefix']) != '' && $form_subject != '' && $func['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the subject. censorText($form_subject); $form_message = ''; } else { $form_subject = isset($_GET['subject']) ? $_GET['subject'] : ''; $form_message = ''; } } // !!! This won't work if you're posting an event. if (allowedTo('post_attachment')) { if (empty($_SESSION['temp_attachments'])) { $_SESSION['temp_attachments'] = array(); } // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg'])) { $request = db_query("\n\t\t\t\tSELECT COUNT(*), SUM(size)\n\t\t\t\tFROM {$db_prefix}attachments\n\t\t\t\tWHERE ID_MSG = " . (int) $_REQUEST['msg'] . "\n\t\t\t\t\tAND attachmentType = 0", __FILE__, __LINE__); list($quantity, $total_size) = mysql_fetch_row($request); mysql_free_result($request); } else { $quantity = 0; $total_size = 0; } $temp_start = 0; if (!empty($_SESSION['temp_attachments'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $name) { $temp_start++; if (preg_match('~^post_tmp_' . $ID_MEMBER . '_\\d+$~', $attachID) == 0) { unset($_SESSION['temp_attachments'][$attachID]); continue; } if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) { $deleted_attachments = true; unset($_SESSION['temp_attachments'][$attachID]); @unlink($modSettings['attachmentUploadDir'] . '/' . $attachID); continue; } $quantity++; $total_size += filesize($modSettings['attachmentUploadDir'] . '/' . $attachID); $context['current_attachments'][] = array('name' => getAttachmentFilename($name, false, true), 'id' => $attachID); } } if (!empty($_POST['attach_del'])) { $del_temp = array(); foreach ($_POST['attach_del'] as $i => $dummy) { $del_temp[$i] = (int) $dummy; } foreach ($context['current_attachments'] as $k => $dummy) { if (!in_array($dummy['id'], $del_temp)) { $context['current_attachments'][$k]['unchecked'] = true; $deleted_attachments = !isset($deleted_attachments) || is_bool($deleted_attachments) ? 1 : $deleted_attachments + 1; $quantity--; } } } if (!empty($_FILES['attachment'])) { foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) { if ($_FILES['attachment']['name'][$n] == '') { continue; } if (!is_uploaded_file($_FILES['attachment']['tmp_name'][$n]) || @ini_get('open_basedir') == '' && !file_exists($_FILES['attachment']['tmp_name'][$n])) { fatal_lang_error('smf124'); } if (!empty($modSettings['attachmentSizeLimit']) && $_FILES['attachment']['size'][$n] > $modSettings['attachmentSizeLimit'] * 1024) { fatal_lang_error('smf122', false, array($modSettings['attachmentSizeLimit'])); } $quantity++; if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) { fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit'])); } $total_size += $_FILES['attachment']['size'][$n]; if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) { fatal_lang_error('smf122', false, array($modSettings['attachmentPostLimit'])); } if (!empty($modSettings['attachmentCheckExtensions'])) { if (!in_array(strtolower(substr(strrchr($_FILES['attachment']['name'][$n], '.'), 1)), explode(',', strtolower($modSettings['attachmentExtensions'])))) { fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['smf123'] . ' ' . $modSettings['attachmentExtensions'] . '.', false); } } if (!empty($modSettings['attachmentDirSizeLimit'])) { // Make sure the directory isn't full. $dirSize = 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; } $dirSize += filesize($modSettings['attachmentUploadDir'] . '/' . $file); } closedir($dir); // Too big! Maybe you could zip it or something... if ($_FILES['attachment']['size'][$n] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024) { fatal_lang_error('smf126'); } } if (!is_writable($modSettings['attachmentUploadDir'])) { fatal_lang_error('attachments_no_write'); } $attachID = 'post_tmp_' . $ID_MEMBER . '_' . $temp_start++; $_SESSION['temp_attachments'][$attachID] = stripslashes(basename($_FILES['attachment']['name'][$n])); $context['current_attachments'][] = array('name' => basename(stripslashes($_FILES['attachment']['name'][$n])), 'id' => $attachID); $destName = $modSettings['attachmentUploadDir'] . '/' . $attachID; if (!move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName)) { fatal_lang_error('smf124'); } @chmod($destName, 0644); } } } // If we are coming here to make a reply, and someone has already replied... make a special warning message. if (isset($newRepliesError)) { $context['post_error']['messages'][] = $newRepliesError == 1 ? $txt['error_new_reply'] : $txt['error_new_replies']; $context['error_type'] = 'minor'; } if (isset($oldTopicError)) { $context['post_error']['messages'][] = $txt['error_old_topic']; $context['error_type'] = 'minor'; } // What are you doing? Posting a poll, modifying, previewing, new post, or reply... if (isset($_REQUEST['poll'])) { $context['page_title'] = $txt['smf20']; } elseif ($context['make_event']) { $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar23'] : $txt['calendar20']; } elseif (isset($_REQUEST['msg'])) { $context['page_title'] = $txt[66]; } elseif (isset($_REQUEST['subject'], $context['preview_subject'])) { $context['page_title'] = $txt[507] . ' - ' . strip_tags($context['preview_subject']); } elseif (empty($topic)) { $context['page_title'] = $txt[33]; } else { $context['page_title'] = $txt[25]; } // Build the link tree. if (empty($topic)) { $context['linktree'][] = array('name' => '<i>' . $txt[33] . '</i>'); } else { $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'], 'name' => $form_subject, 'extra_before' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><b class="nav">' . $context['page_title'] . ' ( </b></span>', 'extra_after' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><b class="nav"> )</b></span>'); } // If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments. // !!! This won't work if you're posting an event. $context['num_allowed_attachments'] = min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']) + (isset($deleted_attachments) ? $deleted_attachments : 0), $modSettings['attachmentNumPerPostLimit']); $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && allowedTo('post_attachment') && $context['num_allowed_attachments'] > 0; $context['subject'] = addcslashes($form_subject, '"'); $context['message'] = str_replace(array('"', '<', '>', ' '), array('"', '<', '>', ' '), $form_message); $context['attached'] = ''; $context['allowed_extensions'] = strtr($modSettings['attachmentExtensions'], array(',' => ', ')); $context['make_poll'] = isset($_REQUEST['poll']); // Message icons - customized icons are off? if (empty($modSettings['messageIcons_enable'])) { $context['icons'] = array(array('value' => 'xx', 'name' => $txt[281]), array('value' => 'thumbup', 'name' => $txt[282]), array('value' => 'thumbdown', 'name' => $txt[283]), array('value' => 'exclamation', 'name' => $txt[284]), array('value' => 'question', 'name' => $txt[285]), array('value' => 'lamp', 'name' => $txt[286]), array('value' => 'smiley', 'name' => $txt[287]), array('value' => 'angry', 'name' => $txt[288]), array('value' => 'cheesy', 'name' => $txt[289]), array('value' => 'grin', 'name' => $txt[293]), array('value' => 'sad', 'name' => $txt[291]), array('value' => 'wink', 'name' => $txt[292])); foreach ($context['icons'] as $k => $dummy) { $context['icons'][$k]['url'] = $settings['images_url'] . '/post/' . $dummy['value'] . '.gif'; $context['icons'][$k]['is_last'] = false; } $context['icon_url'] = $settings['images_url'] . '/post/' . $context['icon'] . '.gif'; } else { // Regardless of what *should* exist, let's do this properly. $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless'); $context['icon_sources'] = array(); foreach ($stable_icons as $icon) { $context['icon_sources'][$icon] = 'images_url'; } // Array for all icons that need to revert to the default theme! $context['javascript_icons'] = array(); if (($temp = cache_get_data('posting_icons-' . $board, 480)) == null) { $request = db_query("\n\t\t\t\tSELECT title, filename\n\t\t\t\tFROM {$db_prefix}message_icons\n\t\t\t\tWHERE ID_BOARD IN (0, {$board})", __FILE__, __LINE__); $icon_data = array(); while ($row = mysql_fetch_assoc($request)) { $icon_data[] = $row; } mysql_free_result($request); cache_put_data('posting_icons-' . $board, $icon_data, 480); } else { $icon_data = $temp; } $context['icons'] = array(); foreach ($icon_data as $icon) { if (!isset($context['icon_sources'][$icon['filename']])) { $context['icon_sources'][$icon['filename']] = file_exists($settings['theme_dir'] . '/images/post/' . $icon['filename'] . '.gif') ? 'images_url' : 'default_images_url'; } // If the icon exists only in the default theme, ensure the javascript popup respects this. if ($context['icon_sources'][$icon['filename']] == 'default_images_url') { $context['javascript_icons'][] = $icon['filename']; } $context['icons'][] = array('value' => $icon['filename'], 'name' => $icon['title'], 'url' => $settings[$context['icon_sources'][$icon['filename']]] . '/post/' . $icon['filename'] . '.gif', 'is_last' => false); } $context['icon_url'] = $settings[isset($context['icon_sources'][$context['icon']]) ? $context['icon_sources'][$context['icon']] : 'images_url'] . '/post/' . $context['icon'] . '.gif'; } if (!empty($context['icons'])) { $context['icons'][count($context['icons']) - 1]['is_last'] = true; } $found = false; for ($i = 0, $n = count($context['icons']); $i < $n; $i++) { $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value']; if ($context['icons'][$i]['selected']) { $found = true; } } if (!$found) { array_unshift($context['icons'], array('value' => $context['icon'], 'name' => $txt['current_icon'], 'url' => $context['icon_url'], 'is_last' => empty($context['icons']), 'selected' => true)); } if (!empty($topic)) { getTopic(); } $context['back_to_topic'] = isset($_REQUEST['goback']) || isset($_REQUEST['msg']) && !isset($_REQUEST['subject']); $context['show_additional_options'] = !empty($_POST['additional_options']) || !empty($_SESSION['temp_attachments']) || !empty($deleted_attachments); $context['is_new_topic'] = empty($topic); $context['is_new_post'] = !isset($_REQUEST['msg']); $context['is_first_post'] = $context['is_new_topic'] || isset($_REQUEST['msg']) && $_REQUEST['msg'] == $ID_FIRST_MSG; // Register this form in the session variables. checkSubmitOnce('register'); // Finally, load the template. if (WIRELESS) { $context['sub_template'] = WIRELESS_PROTOCOL . '_post'; } elseif (!isset($_REQUEST['xml'])) { loadTemplate('Post'); } }
function loadAttachmentContext($ID_MSG) { global $attachments, $modSettings, $txt, $scripturl, $topic, $db_prefix, $sourcedir; // Set up the attachment info - based on code by Meriadoc. $attachmentData = array(); if (isset($attachments[$ID_MSG]) && !empty($modSettings['attachmentEnable'])) { foreach ($attachments[$ID_MSG] as $i => $attachment) { $attachmentData[$i] = array('id' => $attachment['ID_ATTACH'], 'name' => htmlspecialchars($attachment['filename']), 'downloads' => $attachment['downloads'], 'size' => round($attachment['filesize'] / 1024, 2) . ' ' . $txt['smf211'], 'byte_size' => $attachment['filesize'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['ID_ATTACH'], 'link' => '<a href="' . $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['ID_ATTACH'] . '">' . htmlspecialchars($attachment['filename']) . '</a>', 'is_image' => !empty($attachment['width']) && !empty($attachment['height']) && !empty($modSettings['attachmentShowImages'])); if (!$attachmentData[$i]['is_image']) { continue; } $attachmentData[$i]['real_width'] = $attachment['width']; $attachmentData[$i]['width'] = $attachment['width']; $attachmentData[$i]['real_height'] = $attachment['height']; $attachmentData[$i]['height'] = $attachment['height']; // Let's see, do we want thumbs? if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachment['width'] > $modSettings['attachmentThumbWidth'] || $attachment['height'] > $modSettings['attachmentThumbHeight']) && strlen($attachment['filename']) < 249) { // A proper thumb doesn't exist yet? Create one! if (empty($attachment['ID_THUMB']) || $attachment['thumb_width'] > $modSettings['attachmentThumbWidth'] || $attachment['thumb_height'] > $modSettings['attachmentThumbHeight'] || $attachment['thumb_width'] < $modSettings['attachmentThumbWidth'] && $attachment['thumb_height'] < $modSettings['attachmentThumbHeight']) { $filename = getAttachmentFilename($attachment['filename'], $attachment['ID_ATTACH']); require_once $sourcedir . '/Subs-Graphics.php'; if (createThumbnail($filename, $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // Calculate the size of the created thumbnail. list($attachment['thumb_width'], $attachment['thumb_height']) = @getimagesize($filename . '_thumb'); $thumb_size = filesize($filename . '_thumb'); $thumb_filename = addslashes($attachment['filename'] . '_thumb'); // Add this beauty to the database. db_query("\n\t\t\t\t\t\t\tINSERT INTO {$db_prefix}attachments\n\t\t\t\t\t\t\t\t(ID_MSG, attachmentType, filename, size, width, height)\n\t\t\t\t\t\t\tVALUES ({$ID_MSG}, 3, '{$thumb_filename}', " . (int) $thumb_size . ", " . (int) $attachment['thumb_width'] . ", " . (int) $attachment['thumb_height'] . ")", __FILE__, __LINE__); $attachment['ID_THUMB'] = db_insert_id(); if (!empty($attachment['ID_THUMB'])) { db_query("\n\t\t\t\t\t\t\t\tUPDATE {$db_prefix}attachments\n\t\t\t\t\t\t\t\tSET ID_THUMB = {$attachment['ID_THUMB']}\n\t\t\t\t\t\t\t\tWHERE ID_ATTACH = {$attachment['ID_ATTACH']}\n\t\t\t\t\t\t\t\tLIMIT 1", __FILE__, __LINE__); $thumb_realname = getAttachmentFilename($thumb_filename, $attachment['ID_THUMB'], true); rename($filename . '_thumb', $modSettings['attachmentUploadDir'] . '/' . $thumb_realname); } } } $attachmentData[$i]['width'] = $attachment['thumb_width']; $attachmentData[$i]['height'] = $attachment['thumb_height']; } if (!empty($attachment['ID_THUMB'])) { $attachmentData[$i]['thumbnail'] = array('id' => $attachment['ID_THUMB'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['ID_THUMB'] . ';image'); } $attachmentData[$i]['thumbnail']['has_thumb'] = !empty($attachment['ID_THUMB']); // If thumbnails are disabled, check the maximum size of the image. if (!$attachmentData[$i]['thumbnail']['has_thumb'] && (!empty($modSettings['max_image_width']) && $attachment['width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachment['height'] > $modSettings['max_image_height'])) { if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $attachment['height'] * $modSettings['max_image_width'] / $attachment['width'] <= $modSettings['max_image_height'])) { $attachmentData[$i]['width'] = $modSettings['max_image_width']; $attachmentData[$i]['height'] = floor($attachment['height'] * $modSettings['max_image_width'] / $attachment['width']); } elseif (!empty($modSettings['max_image_width'])) { $attachmentData[$i]['width'] = floor($attachment['width'] * $modSettings['max_image_height'] / $attachment['height']); $attachmentData[$i]['height'] = $modSettings['max_image_height']; } } elseif ($attachmentData[$i]['thumbnail']['has_thumb']) { // If the image is too large to show inline, make it a popup. if (!empty($modSettings['max_image_width']) && $attachmentData[$i]['real_width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachmentData[$i]['real_height'] > $modSettings['max_image_height']) { $attachmentData[$i]['thumbnail']['javascript'] = "return reqWin('" . $attachmentData[$i]['href'] . ";image', " . ($attachment['width'] + 20) . ', ' . ($attachment['height'] + 20) . ', true);'; } else { $attachmentData[$i]['thumbnail']['javascript'] = 'return expandThumb(' . $attachment['ID_ATTACH'] . ');'; } } if (!$attachmentData[$i]['thumbnail']['has_thumb']) { $attachmentData[$i]['downloads']++; } } } return $attachmentData; }
function tpattach() { global $txt, $modSettings, $context, $smcFunc; // Some defaults that we need. $context['character_set'] = empty($modSettings['global_character_set']) ? empty($txt['lang_character_set']) ? 'ISO-8859-1' : $txt['lang_character_set'] : $modSettings['global_character_set']; $context['utf8'] = $context['character_set'] === 'UTF-8' && (strpos(strtolower(PHP_OS), 'win') === false || @version_compare(PHP_VERSION, '4.2.3') != -1); $context['no_last_modified'] = true; // Make sure some attachment was requested! if (!isset($_REQUEST['attach']) && !isset($_REQUEST['id'])) { fatal_lang_error('no_access', false); } $_REQUEST['attach'] = isset($_REQUEST['attach']) ? (int) $_REQUEST['attach'] : (int) $_REQUEST['id']; if (isset($_REQUEST['type']) && $_REQUEST['type'] == 'avatar') { $request = $smcFunc['db_query']('', ' SELECT id_folder, filename, file_hash, fileext, id_attach, attachment_type, mime_type, approved FROM {db_prefix}attachments WHERE id_attach = {int:id_attach} AND id_member > {int:blank_id_member} LIMIT 1', array('id_attach' => $_REQUEST['attach'], 'blank_id_member' => 0)); $_REQUEST['image'] = true; } else { $request = $smcFunc['db_query']('', ' SELECT a.id_folder, a.filename, a.file_hash, a.fileext, a.id_attach, a.attachment_type, a.mime_type, a.approved FROM {db_prefix}attachments AS a WHERE a.id_attach = {int:attach} LIMIT 1', array('attach' => $_REQUEST['attach'])); } if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_access', false); } list($id_folder, $real_filename, $file_hash, $file_ext, $id_attach, $attachment_type, $mime_type, $is_approved) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); $filename = getAttachmentFilename($real_filename, $_REQUEST['attach'], $id_folder, false, $file_hash); // This is done to clear any output that was made before now. (would use ob_clean(), but that's PHP 4.2.0+...) ob_end_clean(); if (!empty($modSettings['enableCompressedOutput']) && @version_compare(PHP_VERSION, '4.2.0') >= 0 && @filesize($filename) <= 4194304 && in_array($file_ext, array('txt', 'html', 'htm', 'js', 'doc', 'pdf', 'docx', 'rtf', 'css', 'php', 'log', 'xml', 'sql', 'c', 'java'))) { @ob_start('ob_gzhandler'); } else { ob_start(); header('Content-Encoding: none'); } // No point in a nicer message, because this is supposed to be an attachment anyway... if (!file_exists($filename)) { loadLanguage('Errors'); header('HTTP/1.0 404 ' . $txt['attachment_not_found']); header('Content-Type: text/plain; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set'])); // We need to die like this *before* we send any anti-caching headers as below. die('404 - ' . $txt['attachment_not_found']); } // If it hasn't been modified since the last time this attachement was retrieved, there's no need to display it again. if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { list($modified_since) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE']); if (strtotime($modified_since) >= filemtime($filename)) { ob_end_clean(); // Answer the question - no, it hasn't been modified ;). header('HTTP/1.1 304 Not Modified'); exit; } } // Check whether the ETag was sent back, and cache based on that... $eTag = '"' . substr($_REQUEST['attach'] . $real_filename . filemtime($filename), 0, 64) . '"'; if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && strpos($_SERVER['HTTP_IF_NONE_MATCH'], $eTag) !== false) { ob_end_clean(); header('HTTP/1.1 304 Not Modified'); exit; } // Send the attachment headers. header('Pragma: '); if (!$context['browser']['is_gecko']) { header('Content-Transfer-Encoding: binary'); } header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($filename)) . ' GMT'); header('Accept-Ranges: bytes'); header('Set-Cookie:'); header('Connection: close'); header('ETag: ' . $eTag); // IE 6 just doesn't play nice. As dirty as this seems, it works. if ($context['browser']['is_ie6'] && isset($_REQUEST['image'])) { unset($_REQUEST['image']); } elseif (filesize($filename) != 0) { $size = @getimagesize($filename); if (!empty($size)) { // What headers are valid? $validTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 5 => 'psd', 6 => 'x-ms-bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpeg', 14 => 'iff'); // Do we have a mime type we can simpy use? if (!empty($size['mime']) && !in_array($size[2], array(4, 13))) { header('Content-Type: ' . strtr($size['mime'], array('image/bmp' => 'image/x-ms-bmp'))); } elseif (isset($validTypes[$size[2]])) { header('Content-Type: image/' . $validTypes[$size[2]]); } elseif (isset($_REQUEST['image'])) { unset($_REQUEST['image']); } } elseif (isset($_REQUEST['image'])) { unset($_REQUEST['image']); } } header('Content-Disposition: ' . (isset($_REQUEST['image']) ? 'inline' : 'attachment') . '; filename="' . $real_filename . '"'); if (!isset($_REQUEST['image'])) { header('Content-Type: application/octet-stream'); } // If this has an "image extension" - but isn't actually an image - then ensure it isn't cached cause of silly IE. if (!isset($_REQUEST['image']) && in_array($file_ext, array('gif', 'jpg', 'bmp', 'png', 'jpeg', 'tiff'))) { header('Cache-Control: no-cache'); } else { header('Cache-Control: max-age=' . 525600 * 60 . ', private'); } if (empty($modSettings['enableCompressedOutput']) || filesize($filename) > 4194304) { header('Content-Length: ' . filesize($filename)); } // Try to buy some time... @set_time_limit(0); // Since we don't do output compression for files this large... if (filesize($filename) > 4194304) { // Forcibly end any output buffering going on. if (function_exists('ob_get_level')) { while (@ob_get_level() > 0) { @ob_end_clean(); } } else { @ob_end_clean(); @ob_end_clean(); @ob_end_clean(); } $fp = fopen($filename, 'rb'); while (!feof($fp)) { if (isset($callback)) { echo $callback(fread($fp, 8192)); } else { echo fread($fp, 8192); } flush(); } fclose($fp); } elseif (isset($callback) || @readfile($filename) == null) { echo isset($callback) ? $callback(file_get_contents($filename)) : file_get_contents($filename); } obExit(false); }
function CopyAttachment($row, $attach_dir) { global $modSettings; // Original attachment link $row['original_file_link'] = getAttachmentFilename($row['filename'], $row['original_id'], $row['folder']); // New Attachment // Ay caramba!, we can't have two files with exact same name, so we need a new filename if (empty($modSettings['attachmentEncryptFilenames'])) { $row['filename'] = GenerateUniqueFilename($attach_dir . '/', $row['filename']); // Couldn't generate a new filename so return if (empty($row['filename'])) { return 0; } else { // Destination attachment link $row['file_link'] = $attach_dir . '/' . $row['filename']; } } else { // Destination attachment link $row['file_link'] = $attach_dir . '/' . getAttachmentFilename($row['filename'], $row['file_id'], $attach_dir, true); } // Now copy the file if (copy($row['original_file_link'], $row['file_link']) !== false) { // Attempt to chmod it. @chmod($row['file_link'], 0644); //Success // But what about the thumbnail if (!empty($row['thumb_id'])) { // Original attachment link $row['original_thumb_link'] = getAttachmentFilename($row['thumbname'], $row['original_thumb_id'], $row['thumbfolder']); if (empty($modSettings['attachmentEncryptFilenames'])) { $row['thumbname'] = $row['filename'] . '_thumb'; $row['thumb_link'] = $attach_dir . '/' . $row['thumbname']; } else { $row['thumb_link'] = $attach_dir . '/' . getAttachmentFilename($row['thumbname'], $row['thumb_id'], $attach_dir, true); } // If it fails to copy the thumb, send back 0 if (copy($row['original_thumb_link'], $row['thumb_link']) !== false) { // Attempt to chmod it. @chmod($row['thumb_link'], 0644); } else { return 0; } } //send back the new filename to store in the db return $row['filename']; } // If haven't exited, we must have failed return 0; }
function removeAttachments($condition, $query_type = '', $return_affected_messages = false, $autoThumbRemoval = true) { global $modSettings, $smcFunc; //!!! This might need more work! $new_condition = array(); $query_parameter = array('thumb_attachment_type' => 3); if (is_array($condition)) { foreach ($condition as $real_type => $restriction) { // Doing a NOT? $is_not = substr($real_type, 0, 4) == 'not_'; $type = $is_not ? substr($real_type, 4) : $real_type; if (in_array($type, array('id_member', 'id_attach', 'id_msg'))) { $new_condition[] = 'a.' . $type . ($is_not ? ' NOT' : '') . ' IN (' . (is_array($restriction) ? '{array_int:' . $real_type . '}' : '{int:' . $real_type . '}') . ')'; } elseif ($type == 'attachment_type') { $new_condition[] = 'a.attachment_type = {int:' . $real_type . '}'; } elseif ($type == 'poster_time') { $new_condition[] = 'm.poster_time < {int:' . $real_type . '}'; } elseif ($type == 'last_login') { $new_condition[] = 'mem.last_login < {int:' . $real_type . '}'; } elseif ($type == 'size') { $new_condition[] = 'a.size > {int:' . $real_type . '}'; } elseif ($type == 'id_topic') { $new_condition[] = 'm.id_topic IN (' . (is_array($restriction) ? '{array_int:' . $real_type . '}' : '{int:' . $real_type . '}') . ')'; } // Add the parameter! $query_parameter[$real_type] = $restriction; } $condition = implode(' AND ', $new_condition); } // Delete it only if it exists... $msgs = array(); $attach = array(); $parents = array(); // Get all the attachment names and id_msg's. $request = smf_db_query(' SELECT a.id_folder, a.filename, a.file_hash, a.attachment_type, a.id_attach, a.id_member' . ($query_type == 'messages' ? ', m.id_msg' : ', a.id_msg') . ', thumb.id_folder AS thumb_folder, IFNULL(thumb.id_attach, 0) AS id_thumb, thumb.filename AS thumb_filename, thumb.file_hash AS thumb_file_hash, thumb_parent.id_attach AS id_parent FROM {db_prefix}attachments AS a' . ($query_type == 'members' ? ' INNER JOIN {db_prefix}members AS mem ON (mem.id_member = a.id_member)' : ($query_type == 'messages' ? ' INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg)' : '')) . ' LEFT JOIN {db_prefix}attachments AS thumb ON (thumb.id_attach = a.id_thumb) LEFT JOIN {db_prefix}attachments AS thumb_parent ON (thumb.attachment_type = {int:thumb_attachment_type} AND thumb_parent.id_thumb = a.id_attach) WHERE ' . $condition, $query_parameter); while ($row = mysql_fetch_assoc($request)) { // Figure out the "encrypted" filename and unlink it ;). if ($row['attachment_type'] == 1) { @unlink($modSettings['custom_avatar_dir'] . '/' . $row['filename']); } else { $filename = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], 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'], $row['thumb_folder'], false, $row['thumb_file_hash']); @unlink($thumb_filename); $attach[] = $row['id_thumb']; } } // Make a list. if ($return_affected_messages && empty($row['attachment_type'])) { $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)) { smf_db_query(' UPDATE {db_prefix}attachments SET id_thumb = {int:no_thumb} WHERE id_attach IN ({array_int:parent_attachments})', array('parent_attachments' => $parents, 'no_thumb' => 0)); } if (!empty($attach)) { smf_db_query(' DELETE FROM {db_prefix}attachments WHERE id_attach IN ({array_int:attachment_list})', array('attachment_list' => $attach)); } if ($return_affected_messages) { return array_unique($msgs); } }
function profileSaveAvatarData(&$value) { global $modSettings, $sourcedir, $smcFunc, $profile_vars, $cur_profile, $context; $memID = $context['id_member']; if (empty($memID) && !empty($context['password_auth_failed'])) { return false; } require_once $sourcedir . '/ManageAttachments.php'; // We need to know where we're going to be putting it.. if (!empty($modSettings['custom_avatar_enabled'])) { $uploadDir = $modSettings['custom_avatar_dir']; $id_folder = 1; } elseif (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } // Just use the current path for temp files. $uploadDir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; $id_folder = $modSettings['currentAttachmentUploadDir']; } else { $uploadDir = $modSettings['attachmentUploadDir']; $id_folder = 1; } $downloadedExternalAvatar = false; if ($value == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && strlen($_POST['userpicpersonal']) > 7 && !empty($modSettings['avatar_download_external'])) { if (!is_writable($uploadDir)) { fatal_lang_error('attachments_no_write', 'critical'); } require_once $sourcedir . '/Subs-Package.php'; $url = parse_url($_POST['userpicpersonal']); $contents = fetch_web_data('http://' . $url['host'] . (empty($url['port']) ? '' : ':' . $url['port']) . str_replace(' ', '%20', trim($url['path']))); if ($contents != false && ($tmpAvatar = fopen($uploadDir . '/avatar_tmp_' . $memID, 'wb'))) { fwrite($tmpAvatar, $contents); fclose($tmpAvatar); $downloadedExternalAvatar = true; $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; } } if ($value == 'none') { $profile_vars['avatar'] = ''; // Reset the attach ID. $cur_profile['id_attach'] = 0; $cur_profile['attachment_type'] = 0; $cur_profile['filename'] = ''; removeAttachments(array('id_member' => $memID)); } elseif ($value == 'server_stored' && allowedTo('profile_server_avatar')) { $profile_vars['avatar'] = strtr(empty($_POST['file']) ? empty($_POST['cat']) ? '' : $_POST['cat'] : $_POST['file'], array('&' => '&')); $profile_vars['avatar'] = preg_match('~^([\\w _!@%*=\\-#()\\[\\]&.,]+/)?[\\w _!@%*=\\-#()\\[\\]&.,]+$~', $profile_vars['avatar']) != 0 && preg_match('/\\.\\./', $profile_vars['avatar']) == 0 && file_exists($modSettings['avatar_directory'] . '/' . $profile_vars['avatar']) ? $profile_vars['avatar'] == 'blank.gif' ? '' : $profile_vars['avatar'] : ''; // Clear current profile... $cur_profile['id_attach'] = 0; $cur_profile['attachment_type'] = 0; $cur_profile['filename'] = ''; // Get rid of their old avatar. (if uploaded.) removeAttachments(array('id_member' => $memID)); } elseif ($value == 'external' && allowedTo('profile_remote_avatar') && strtolower(substr($_POST['userpicpersonal'], 0, 7)) == 'http://' && empty($modSettings['avatar_download_external'])) { // We need these clean... $cur_profile['id_attach'] = 0; $cur_profile['attachment_type'] = 0; $cur_profile['filename'] = ''; // Remove any attached avatar... removeAttachments(array('id_member' => $memID)); $profile_vars['avatar'] = str_replace('%20', '', preg_replace('~action(?:=|%3d)(?!dlattach)~i', 'action-', $_POST['userpicpersonal'])); if ($profile_vars['avatar'] == 'http://' || $profile_vars['avatar'] == 'http:///') { $profile_vars['avatar'] = ''; } elseif (substr($profile_vars['avatar'], 0, 7) != 'http://') { return 'bad_avatar'; } elseif (!empty($modSettings['avatar_max_height_external']) || !empty($modSettings['avatar_max_width_external'])) { // Now let's validate the avatar. $sizes = url_image_size($profile_vars['avatar']); if (is_array($sizes) && ($sizes[0] > $modSettings['avatar_max_width_external'] && !empty($modSettings['avatar_max_width_external']) || $sizes[1] > $modSettings['avatar_max_height_external'] && !empty($modSettings['avatar_max_height_external']))) { // Houston, we have a problem. The avatar is too large!! if ($modSettings['avatar_action_too_large'] == 'option_refuse') { return 'bad_avatar'; } elseif ($modSettings['avatar_action_too_large'] == 'option_download_and_resize') { require_once $sourcedir . '/Subs-Graphics.php'; if (downloadAvatar($profile_vars['avatar'], $memID, $modSettings['avatar_max_width_external'], $modSettings['avatar_max_height_external'])) { $profile_vars['avatar'] = ''; $cur_profile['id_attach'] = $modSettings['new_avatar_data']['id']; $cur_profile['filename'] = $modSettings['new_avatar_data']['filename']; $cur_profile['attachment_type'] = $modSettings['new_avatar_data']['type']; } else { return 'bad_avatar'; } } } } } elseif ($value == 'upload' && allowedTo('profile_upload_avatar') || $downloadedExternalAvatar) { if (isset($_FILES['attachment']['name']) && $_FILES['attachment']['name'] != '' || $downloadedExternalAvatar) { // Get the dimensions of the image. if (!$downloadedExternalAvatar) { if (!is_writable($uploadDir)) { fatal_lang_error('attachments_no_write', 'critical'); } if (!move_uploaded_file($_FILES['attachment']['tmp_name'], $uploadDir . '/avatar_tmp_' . $memID)) { fatal_lang_error('attach_timeout', 'critical'); } $_FILES['attachment']['tmp_name'] = $uploadDir . '/avatar_tmp_' . $memID; } $sizes = @getimagesize($_FILES['attachment']['tmp_name']); // No size, then it's probably not a valid pic. if ($sizes === false) { return 'bad_avatar'; } elseif (!empty($modSettings['avatar_max_width_upload']) && $sizes[0] > $modSettings['avatar_max_width_upload'] || !empty($modSettings['avatar_max_height_upload']) && $sizes[1] > $modSettings['avatar_max_height_upload']) { if (!empty($modSettings['avatar_resize_upload'])) { // Attempt to chmod it. @chmod($uploadDir . '/avatar_tmp_' . $memID, 0644); require_once $sourcedir . '/Subs-Graphics.php'; if (!downloadAvatar($uploadDir . '/avatar_tmp_' . $memID, $memID, $modSettings['avatar_max_width_upload'], $modSettings['avatar_max_height_upload'])) { return 'bad_avatar'; } // Reset attachment avatar data. $cur_profile['id_attach'] = $modSettings['new_avatar_data']['id']; $cur_profile['filename'] = $modSettings['new_avatar_data']['filename']; $cur_profile['attachment_type'] = $modSettings['new_avatar_data']['type']; } else { return 'bad_avatar'; } } elseif (is_array($sizes)) { // Now try to find an infection. require_once $sourcedir . '/Subs-Graphics.php'; if (!checkImageContents($_FILES['attachment']['tmp_name'], !empty($modSettings['avatar_paranoid']))) { // It's bad. Try to re-encode the contents? if (empty($modSettings['avatar_reencode']) || !reencodeImage($_FILES['attachment']['tmp_name'], $sizes[2])) { return 'bad_avatar'; } // We were successful. However, at what price? $sizes = @getimagesize($_FILES['attachment']['tmp_name']); // Hard to believe this would happen, but can you bet? if ($sizes === false) { return 'bad_avatar'; } } $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png', '6' => 'bmp'); $extension = isset($extensions[$sizes[2]]) ? $extensions[$sizes[2]] : 'bmp'; $mime_type = 'image/' . ($extension === 'jpg' ? 'jpeg' : ($extension === 'bmp' ? 'x-ms-bmp' : $extension)); $destName = 'avatar_' . $memID . '_' . time() . '.' . $extension; list($width, $height) = getimagesize($_FILES['attachment']['tmp_name']); $file_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, null, true) : ''; // Remove previous attachments this member might have had. removeAttachments(array('id_member' => $memID)); $smcFunc['db_insert']('', '{db_prefix}attachments', array('id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string', 'file_hash' => 'string', 'fileext' => 'string', 'size' => 'int', 'width' => 'int', 'height' => 'int', 'mime_type' => 'string', 'id_folder' => 'int'), array($memID, empty($modSettings['custom_avatar_enabled']) ? 0 : 1, $destName, $file_hash, $extension, filesize($_FILES['attachment']['tmp_name']), (int) $width, (int) $height, $mime_type, $id_folder), array('id_attach')); $cur_profile['id_attach'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); $cur_profile['filename'] = $destName; $cur_profile['attachment_type'] = empty($modSettings['custom_avatar_enabled']) ? 0 : 1; $destinationPath = $uploadDir . '/' . (empty($file_hash) ? $destName : $cur_profile['id_attach'] . '_' . $file_hash); if (!rename($_FILES['attachment']['tmp_name'], $destinationPath)) { // I guess a man can try. removeAttachments(array('id_member' => $memID)); fatal_lang_error('attach_timeout', 'critical'); } // Attempt to chmod it. @chmod($uploadDir . '/' . $destinationPath, 0644); } $profile_vars['avatar'] = ''; // Delete any temporary file. if (file_exists($uploadDir . '/avatar_tmp_' . $memID)) { @unlink($uploadDir . '/avatar_tmp_' . $memID); } } else { $profile_vars['avatar'] = ''; } } else { $profile_vars['avatar'] = ''; } // Setup the profile variables so it shows things right on display! $cur_profile['avatar'] = $profile_vars['avatar']; return false; }
function loadAttachmentContext($id_msg) { global $attachments, $modSettings, $txt, $scripturl, $topic, $sourcedir, $smcFunc; // Set up the attachment info - based on code by Meriadoc. $attachmentData = array(); $have_unapproved = false; if (isset($attachments[$id_msg]) && !empty($modSettings['attachmentEnable'])) { foreach ($attachments[$id_msg] as $i => $attachment) { $attachmentData[$i] = array('id' => $attachment['id_attach'], 'name' => preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($attachment['filename'])), 'downloads' => $attachment['downloads'], 'size' => round($attachment['filesize'] / 1024, 2) . ' ' . $txt['kilobyte'], 'byte_size' => $attachment['filesize'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_attach'], 'link' => '<a href="' . $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_attach'] . '">' . htmlspecialchars($attachment['filename']) . '</a>', 'is_image' => !empty($attachment['width']) && !empty($attachment['height']) && !empty($modSettings['attachmentShowImages']), 'is_approved' => $attachment['approved']); // If something is unapproved we'll note it so we can sort them. if (!$attachment['approved']) { $have_unapproved = true; } if (!$attachmentData[$i]['is_image']) { continue; } $attachmentData[$i]['real_width'] = $attachment['width']; $attachmentData[$i]['width'] = $attachment['width']; $attachmentData[$i]['real_height'] = $attachment['height']; $attachmentData[$i]['height'] = $attachment['height']; // Let's see, do we want thumbs? if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachment['width'] > $modSettings['attachmentThumbWidth'] || $attachment['height'] > $modSettings['attachmentThumbHeight']) && strlen($attachment['filename']) < 249) { // A proper thumb doesn't exist yet? Create one! if (empty($attachment['id_thumb']) || $attachment['thumb_width'] > $modSettings['attachmentThumbWidth'] || $attachment['thumb_height'] > $modSettings['attachmentThumbHeight'] || $attachment['thumb_width'] < $modSettings['attachmentThumbWidth'] && $attachment['thumb_height'] < $modSettings['attachmentThumbHeight']) { $filename = getAttachmentFilename($attachment['filename'], $attachment['id_attach'], $attachment['id_folder']); require_once $sourcedir . '/Subs-Graphics.php'; if (createThumbnail($filename, $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // So what folder are we putting this image in? if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = @unserialize($modSettings['attachmentUploadDir']); } $path = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; $id_folder_thumb = $modSettings['currentAttachmentUploadDir']; } else { $path = $modSettings['attachmentUploadDir']; $id_folder_thumb = 1; } // Calculate the size of the created thumbnail. $size = @getimagesize($filename . '_thumb'); list($attachment['thumb_width'], $attachment['thumb_height']) = $size; $thumb_size = filesize($filename . '_thumb'); // These are the only valid image types for SMF. $validImageTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 5 => 'psd', 6 => 'bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpeg', 14 => 'iff'); // What about the extension? $thumb_ext = isset($validImageTypes[$size[2]]) ? $validImageTypes[$size[2]] : ''; // Figure out the mime type. if (!empty($size['mime'])) { $thumb_mime = $size['mime']; } else { $thumb_mime = 'image/' . $thumb_ext; } $thumb_filename = $attachment['filename'] . '_thumb'; $thumb_hash = getAttachmentFilename($thumb_filename, false, null, true); // Add this beauty to the database. $smcFunc['db_insert']('', '{db_prefix}attachments', array('id_folder' => 'int', 'id_msg' => 'int', 'attachment_type' => 'int', 'filename' => 'string', 'file_hash' => 'string', 'size' => 'int', 'width' => 'int', 'height' => 'int', 'fileext' => 'string', 'mime_type' => 'string'), array($id_folder_thumb, $id_msg, 3, $thumb_filename, $thumb_hash, (int) $thumb_size, (int) $attachment['thumb_width'], (int) $attachment['thumb_height'], $thumb_ext, $thumb_mime), array('id_attach')); $old_id_thumb = $attachment['id_thumb']; $attachment['id_thumb'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); if (!empty($attachment['id_thumb'])) { $smcFunc['db_query']('', ' UPDATE {db_prefix}attachments SET id_thumb = {int:id_thumb} WHERE id_attach = {int:id_attach}', array('id_thumb' => $attachment['id_thumb'], 'id_attach' => $attachment['id_attach'])); $thumb_realname = getAttachmentFilename($thumb_filename, $attachment['id_thumb'], $id_folder_thumb, false, $thumb_hash); rename($filename . '_thumb', $thumb_realname); // Do we need to remove an old thumbnail? if (!empty($old_id_thumb)) { require_once $sourcedir . '/ManageAttachments.php'; removeAttachments(array('id_attach' => $old_id_thumb), '', false, false); } } } } // Only adjust dimensions on successful thumbnail creation. if (!empty($attachment['thumb_width']) && !empty($attachment['thumb_height'])) { $attachmentData[$i]['width'] = $attachment['thumb_width']; $attachmentData[$i]['height'] = $attachment['thumb_height']; } } if (!empty($attachment['id_thumb'])) { $attachmentData[$i]['thumbnail'] = array('id' => $attachment['id_thumb'], 'href' => $scripturl . '?action=dlattach;topic=' . $topic . '.0;attach=' . $attachment['id_thumb'] . ';image'); } $attachmentData[$i]['thumbnail']['has_thumb'] = !empty($attachment['id_thumb']); // If thumbnails are disabled, check the maximum size of the image. if (!$attachmentData[$i]['thumbnail']['has_thumb'] && (!empty($modSettings['max_image_width']) && $attachment['width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachment['height'] > $modSettings['max_image_height'])) { if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $attachment['height'] * $modSettings['max_image_width'] / $attachment['width'] <= $modSettings['max_image_height'])) { $attachmentData[$i]['width'] = $modSettings['max_image_width']; $attachmentData[$i]['height'] = floor($attachment['height'] * $modSettings['max_image_width'] / $attachment['width']); } elseif (!empty($modSettings['max_image_width'])) { $attachmentData[$i]['width'] = floor($attachment['width'] * $modSettings['max_image_height'] / $attachment['height']); $attachmentData[$i]['height'] = $modSettings['max_image_height']; } } elseif ($attachmentData[$i]['thumbnail']['has_thumb']) { // If the image is too large to show inline, make it a popup. if (!empty($modSettings['max_image_width']) && $attachmentData[$i]['real_width'] > $modSettings['max_image_width'] || !empty($modSettings['max_image_height']) && $attachmentData[$i]['real_height'] > $modSettings['max_image_height']) { $attachmentData[$i]['thumbnail']['javascript'] = 'return reqWin(\'' . $attachmentData[$i]['href'] . ';image\', ' . ($attachment['width'] + 20) . ', ' . ($attachment['height'] + 20) . ', true);'; } else { $attachmentData[$i]['thumbnail']['javascript'] = 'return expandThumb(' . $attachment['id_attach'] . ');'; } } if (!$attachmentData[$i]['thumbnail']['has_thumb']) { $attachmentData[$i]['downloads']++; } } } // Do we need to instigate a sort? if ($have_unapproved) { usort($attachmentData, 'approved_attach_sort'); } return $attachmentData; }
/** * Downloads an attachment or avatar, and increments the download count. * It requires the view_attachments permission. (not for avatars!) * It disables the session parser, and clears any previous output. * It is accessed via the query string ?action=dlattach. * Views to attachments and avatars do not increase hits and are not logged in the "Who's Online" log. */ public function action_dlattach() { global $txt, $modSettings, $user_info, $context, $topic; // Some defaults that we need. $context['no_last_modified'] = true; // Make sure some attachment was requested! if (!isset($_REQUEST['attach']) && !isset($_REQUEST['id'])) { fatal_lang_error('no_access', false); } // We need to do some work on attachments and avatars. require_once SUBSDIR . '/Attachments.subs.php'; $id_attach = isset($_REQUEST['attach']) ? (int) $_REQUEST['attach'] : (int) $_REQUEST['id']; if (isset($_REQUEST['type']) && $_REQUEST['type'] == 'avatar') { $attachment = getAvatar($id_attach); $is_avatar = true; $_REQUEST['image'] = true; } else { isAllowedTo('view_attachments'); $attachment = getAttachmentFromTopic($id_attach, $topic); } if (empty($attachment)) { fatal_lang_error('no_access', false); } list($id_folder, $real_filename, $file_hash, $file_ext, $id_attach, $attachment_type, $mime_type, $is_approved, $id_member) = $attachment; // If it isn't yet approved, do they have permission to view it? if (!$is_approved && ($id_member == 0 || $user_info['id'] != $id_member) && ($attachment_type == 0 || $attachment_type == 3)) { isAllowedTo('approve_posts'); } // Update the download counter (unless it's a thumbnail or an avatar). if (empty($is_avatar) || $attachment_type != 3) { increaseDownloadCounter($id_attach); } $filename = getAttachmentFilename($real_filename, $id_attach, $id_folder, false, $file_hash); // This is done to clear any output that was made before now. while (ob_get_level() > 0) { @ob_end_clean(); } if (!empty($modSettings['enableCompressedOutput']) && @filesize($filename) <= 4194304 && in_array($file_ext, array('txt', 'html', 'htm', 'js', 'doc', 'docx', 'rtf', 'css', 'php', 'log', 'xml', 'sql', 'c', 'java'))) { ob_start('ob_gzhandler'); } else { ob_start(); header('Content-Encoding: none'); } // No point in a nicer message, because this is supposed to be an attachment anyway... if (!file_exists($filename)) { loadLanguage('Errors'); header((preg_match('~HTTP/1\\.[01]~i', $_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0') . ' 404 Not Found'); header('Content-Type: text/plain; charset=UTF-8'); // We need to die like this *before* we send any anti-caching headers as below. die('404 - ' . $txt['attachment_not_found']); } // If it hasn't been modified since the last time this attachment was retrieved, there's no need to display it again. if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { list($modified_since) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE']); if (strtotime($modified_since) >= filemtime($filename)) { @ob_end_clean(); // Answer the question - no, it hasn't been modified ;). header('HTTP/1.1 304 Not Modified'); exit; } } // Check whether the ETag was sent back, and cache based on that... $eTag = '"' . substr($id_attach . $real_filename . filemtime($filename), 0, 64) . '"'; if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && strpos($_SERVER['HTTP_IF_NONE_MATCH'], $eTag) !== false) { @ob_end_clean(); header('HTTP/1.1 304 Not Modified'); exit; } // Send the attachment headers. header('Pragma: '); if (!isBrowser('gecko')) { header('Content-Transfer-Encoding: binary'); } header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($filename)) . ' GMT'); header('Accept-Ranges: bytes'); header('Connection: close'); header('ETag: ' . $eTag); // Make sure the mime type warrants an inline display. if (isset($_REQUEST['image']) && !empty($mime_type) && strpos($mime_type, 'image/') !== 0) { unset($_REQUEST['image']); } elseif (!empty($mime_type) && (isset($_REQUEST['image']) || !in_array($file_ext, array('jpg', 'gif', 'jpeg', 'x-ms-bmp', 'png', 'psd', 'tiff', 'iff')))) { header('Content-Type: ' . strtr($mime_type, array('image/bmp' => 'image/x-ms-bmp'))); } else { header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream')); if (isset($_REQUEST['image'])) { unset($_REQUEST['image']); } } $disposition = !isset($_REQUEST['image']) ? 'attachment' : 'inline'; // Different browsers like different standards... if (isBrowser('firefox')) { header('Content-Disposition: ' . $disposition . '; filename*=UTF-8\'\'' . rawurlencode(preg_replace_callback('~&#(\\d{3,8});~', 'fixchar__callback', $real_filename))); } elseif (isBrowser('opera')) { header('Content-Disposition: ' . $disposition . '; filename="' . preg_replace_callback('~&#(\\d{3,8});~', 'fixchar__callback', $real_filename) . '"'); } elseif (isBrowser('ie')) { header('Content-Disposition: ' . $disposition . '; filename="' . urlencode(preg_replace_callback('~&#(\\d{3,8});~', 'fixchar__callback', $real_filename)) . '"'); } else { header('Content-Disposition: ' . $disposition . '; filename="' . $real_filename . '"'); } // If this has an "image extension" - but isn't actually an image - then ensure it isn't cached cause of silly IE. if (!isset($_REQUEST['image']) && in_array($file_ext, array('gif', 'jpg', 'bmp', 'png', 'jpeg', 'tiff'))) { header('Cache-Control: no-cache'); } else { header('Cache-Control: max-age=' . 525600 * 60 . ', private'); } if (empty($modSettings['enableCompressedOutput']) || filesize($filename) > 4194304) { header('Content-Length: ' . filesize($filename)); } // Try to buy some time... @set_time_limit(600); // Recode line endings for text files, if enabled. if (!empty($modSettings['attachmentRecodeLineEndings']) && !isset($_REQUEST['image']) && in_array($file_ext, array('txt', 'css', 'htm', 'html', 'php', 'xml'))) { $req = request(); if (strpos($req->user_agent(), 'Windows') !== false) { $callback = create_function('$buffer', 'return preg_replace(\'~[\\r]?\\n~\', "\\r\\n", $buffer);'); } elseif (strpos($req->user_agent(), 'Mac') !== false) { $callback = create_function('$buffer', 'return preg_replace(\'~[\\r]?\\n~\', "\\r", $buffer);'); } else { $callback = create_function('$buffer', 'return preg_replace(\'~[\\r]?\\n~\', "\\n", $buffer);'); } } // Since we don't do output compression for files this large... if (filesize($filename) > 4194304) { // Forcibly end any output buffering going on. while (ob_get_level() > 0) { @ob_end_clean(); } $fp = fopen($filename, 'rb'); while (!feof($fp)) { if (isset($callback)) { echo $callback(fread($fp, 8192)); } else { echo fread($fp, 8192); } flush(); } fclose($fp); } elseif (isset($callback) || @readfile($filename) === null) { echo isset($callback) ? $callback(file_get_contents($filename)) : file_get_contents($filename); } obExit(false); }