/** * 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; } }
/** * Called from a mouse click, * works out what we want to do with attachments and actions it. * Accessed by ?action=attachapprove */ public function action_attachapprove() { global $user_info; // Security is our primary concern... checkSession('get'); // If it approve or delete? $is_approve = !isset($_GET['sa']) || $_GET['sa'] != 'reject' ? true : false; $attachments = array(); require_once SUBSDIR . '/ManageAttachments.subs.php'; // If we are approving all ID's in a message , get the ID's. if ($_GET['sa'] == 'all' && !empty($_GET['mid'])) { $id_msg = (int) $_GET['mid']; $attachments = attachmentsOfMessage($id_msg); } elseif (!empty($_GET['aid'])) { $attachments[] = (int) $_GET['aid']; } if (empty($attachments)) { fatal_lang_error('no_access', false); } // @todo nb: this requires permission to approve posts, not manage attachments // Now we have some ID's cleaned and ready to approve, but first - let's check we have permission! $allowed_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts'); if ($allowed_boards == array(0)) { $approve_query = ''; } elseif (!empty($allowed_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $allowed_boards) . ')'; } else { $approve_query = ' AND 0'; } // Validate the attachments exist and have the right approval state. $attachments = validateAttachments($attachments, $approve_query); // Set up a return link based off one of the attachments for this message $attach_home = attachmentBelongsTo($attachments[0]); $redirect = 'topic=' . $attach_home['id_topic'] . '.msg' . $attach_home['id_msg'] . '#msg' . $attach_home['id_msg']; if (empty($attachments)) { fatal_lang_error('no_access', false); } // Finally, we are there. Follow through! if ($is_approve) { // Checked and deemed worthy. approveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments, 'do_logging' => true)); } // We approved or removed, either way we reset those numbers cache_put_data('num_menu_errors', null, 900); // Return to the topic.... redirectexit($redirect); }
/** * View all unapproved attachments. */ public function action_unapproved_attachments() { global $txt, $scripturl, $context, $user_info, $modSettings; $context['page_title'] = $txt['mc_unapproved_attachments']; // Once again, permissions are king! $approve_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts'); if ($approve_boards == array(0)) { $approve_query = ''; } elseif (!empty($approve_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')'; } else { $approve_query = ' AND 0'; } // Get together the array of things to act on, if any. $attachments = array(); if (isset($_GET['approve'])) { $attachments[] = (int) $_GET['approve']; } elseif (isset($_GET['delete'])) { $attachments[] = (int) $_GET['delete']; } elseif (isset($_POST['item'])) { foreach ($_POST['item'] as $item) { $attachments[] = (int) $item; } } // Are we approving or deleting? if (isset($_GET['approve']) || isset($_POST['do']) && $_POST['do'] == 'approve') { $curAction = 'approve'; } elseif (isset($_GET['delete']) || isset($_POST['do']) && $_POST['do'] == 'delete') { $curAction = 'delete'; } // Something to do, let's do it! if (!empty($attachments) && isset($curAction)) { checkSession('request'); // This will be handy. require_once SUBSDIR . '/ManageAttachments.subs.php'; // Confirm the attachments are eligible for changing! $attachments = validateAttachments($attachments, $approve_query); // Assuming it wasn't all like, proper illegal, we can do the approving. if (!empty($attachments)) { if ($curAction == 'approve') { approveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments, 'do_logging' => true)); } cache_put_data('num_menu_errors', null, 900); } } require_once SUBSDIR . '/GenericList.class.php'; require_once SUBSDIR . '/ManageAttachments.subs.php'; $listOptions = array('id' => 'mc_unapproved_attach', 'width' => '100%', 'items_per_page' => $modSettings['defaultMaxMessages'], 'no_items_label' => $txt['mc_unapproved_attachments_none_found'], 'base_href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments', 'default_sort_col' => 'attach_name', 'get_items' => array('function' => 'list_getUnapprovedAttachments', 'params' => array($approve_query)), 'get_count' => array('function' => 'list_getNumUnapprovedAttachments', 'params' => array($approve_query)), 'columns' => array('attach_name' => array('header' => array('value' => $txt['mc_unapproved_attach_name']), 'data' => array('db' => 'filename'), 'sort' => array('default' => 'a.filename', 'reverse' => 'a.filename DESC')), 'attach_size' => array('header' => array('value' => $txt['mc_unapproved_attach_size']), 'data' => array('db' => 'size'), 'sort' => array('default' => 'a.size', 'reverse' => 'a.size DESC')), 'attach_poster' => array('header' => array('value' => $txt['mc_unapproved_attach_poster']), 'data' => array('function' => create_function('$data', ' return $data[\'poster\'][\'link\'];')), 'sort' => array('default' => 'm.id_member', 'reverse' => 'm.id_member DESC')), 'date' => array('header' => array('value' => $txt['date'], 'style' => 'width: 18%;'), 'data' => array('db' => 'time', 'class' => 'smalltext', 'style' => 'white-space:nowrap;'), 'sort' => array('default' => 'm.poster_time', 'reverse' => 'm.poster_time DESC')), 'message' => array('header' => array('value' => $txt['post']), 'data' => array('function' => create_function('$data', ' global $modSettings; return \'<a href="\' . $data[\'message\'][\'href\'] . \'">\' . Util::shorten_text($data[\'message\'][\'subject\'], !empty($modSettings[\'subject_length\']) ? $modSettings[\'subject_length\'] : 24) . \'</a>\';'), 'class' => 'smalltext', 'style' => 'width:15em;'), 'sort' => array('default' => 'm.subject', 'reverse' => 'm.subject DESC')), 'action' => array('header' => array('value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />', 'style' => 'width: 4%'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="item[]" value="%1$d" class="input_check" />', 'params' => array('id' => false))))), 'form' => array('href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments', 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id']), 'token' => 'mod-ap'), 'additional_rows' => array(array('position' => 'bottom_of_list', 'value' => ' <select name="do" onchange="if (this.value != 0 && confirm(\'' . $txt['mc_unapproved_sure'] . '\')) submit();"> <option value="0">' . $txt['with_selected'] . ':</option> <option value="0" disabled="disabled">' . str_repeat('—', strlen($txt['approve'])) . '</option> <option value="approve">' . (isBrowser('ie8') ? '»' : '➤') . ' ' . $txt['approve'] . '</option> <option value="delete">' . (isBrowser('ie8') ? '»' : '➤') . ' ' . $txt['delete'] . '</option> </select> <noscript><input type="submit" name="ml_go" value="' . $txt['go'] . '" class="right_submit" /></noscript>', 'class' => 'floatright'))); // Create the request list. createToken('mod-ap'); createList($listOptions); $context['sub_template'] = 'show_list'; $context['default_list'] = 'mc_unapproved_attach'; $context[$context['moderation_menu_name']]['tab_data'] = array('title' => $txt['mc_unapproved_attachments'], 'help' => '', 'description' => $txt['mc_unapproved_attachments_desc']); }
function deleteMembers($users, $check_not_admin = false) { global $sourcedir, $modSettings, $user_info, $backend_subdir; // Try give us a while to sort this out... @set_time_limit(600); // Try to get some more memory. if (@ini_get('memory_limit') < 128) { @ini_set('memory_limit', '128M'); } // If it's not an array, make it so! if (!is_array($users)) { $users = array($users); } else { $users = array_unique($users); } // Make sure there's no void user in here. $users = array_diff($users, array(0)); // How many are they deleting? if (empty($users)) { return; } elseif (count($users) == 1) { list($user) = $users; if ($user == $user_info['id']) { isAllowedTo('profile_remove_own'); } else { isAllowedTo('profile_remove_any'); } } else { foreach ($users as $k => $v) { $users[$k] = (int) $v; } // Deleting more than one? You can't have more than one account... isAllowedTo('profile_remove_any'); } // Get their names for logging purposes. $request = smf_db_query(' SELECT id_member, member_name, CASE WHEN id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0 THEN 1 ELSE 0 END AS is_admin FROM {db_prefix}members WHERE id_member IN ({array_int:user_list}) LIMIT ' . count($users), array('user_list' => $users, 'admin_group' => 1)); $admins = array(); $user_log_details = array(); while ($row = mysql_fetch_assoc($request)) { if ($row['is_admin']) { $admins[] = $row['id_member']; } $user_log_details[$row['id_member']] = array($row['id_member'], $row['member_name']); } mysql_free_result($request); if (empty($user_log_details)) { return; } // Make sure they aren't trying to delete administrators if they aren't one. But don't bother checking if it's just themself. if (!empty($admins) && ($check_not_admin || !allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $user_info['id']))) { $users = array_diff($users, $admins); foreach ($admins as $id) { unset($user_log_details[$id]); } } // No one left? if (empty($users)) { return; } // Log the action - regardless of who is deleting it. $log_inserts = array(); foreach ($user_log_details as $user) { // Integration rocks! HookAPI::callHook('integrate_delete_member', array($user[0])); // Add it to the administration log for future reference. $log_inserts[] = array(time(), 3, $user_info['id'], $user_info['ip'], 'delete_member', 0, 0, 0, serialize(array('member' => $user[0], 'name' => $user[1], 'member_acted' => $user_info['name']))); // Remove any cached data if enabled. if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) { CacheAPI::putCache('user_settings-' . $user[0], null, 60); } } // Do the actual logging... if (!empty($log_inserts) && !empty($modSettings['modlog_enabled'])) { smf_db_insert('', '{db_prefix}log_actions', array('log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'action' => 'string', 'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534'), $log_inserts, array('id_action')); } // Make these peoples' posts guest posts. smf_db_query(' UPDATE {db_prefix}messages SET id_member = {int:guest_id}, poster_email = {string:blank_email} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'blank_email' => '', 'users' => $users)); smf_db_query(' UPDATE {db_prefix}polls SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Make these peoples' posts guest first posts and last posts. smf_db_query(' UPDATE {db_prefix}topics SET id_member_started = {int:guest_id} WHERE id_member_started IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); smf_db_query(' UPDATE {db_prefix}topics SET id_member_updated = {int:guest_id} WHERE id_member_updated IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); smf_db_query(' UPDATE {db_prefix}log_actions SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); smf_db_query(' UPDATE {db_prefix}log_banned SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); smf_db_query(' UPDATE {db_prefix}log_errors SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Delete the member. smf_db_query(' DELETE FROM {db_prefix}members WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete the logs... smf_db_query(' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:log_type} AND id_member IN ({array_int:users})', array('log_type' => 2, 'users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_boards WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_comments WHERE id_recipient IN ({array_int:users}) AND comment_type = {string:warntpl}', array('users' => $users, 'warntpl' => 'warntpl')); smf_db_query(' DELETE FROM {db_prefix}log_group_requests WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_karma WHERE id_target IN ({array_int:users}) OR id_executor IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_mark_read WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_notify WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_online WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_subscribed WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}log_topics WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}collapsed_categories WHERE id_member IN ({array_int:users})', array('users' => $users)); // delete activities and corresponding notifications smf_db_query(' DELETE a.*, n.* FROM {db_prefix}log_activities AS a LEFT JOIN {db_prefix}log_notifications AS n ON (n.id_act = a.id_act) WHERE a.id_member IN ({array_int:users})', array('users' => $users)); // Make their votes appear as guest votes - at least it keeps the totals right. //!!! Consider adding back in cookie protection. smf_db_query(' UPDATE {db_prefix}log_polls SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Delete personal messages. require_once $sourcedir . '/PersonalMessage.php'; deleteMessages(null, null, $users); smf_db_query(' UPDATE {db_prefix}personal_messages SET id_member_from = {int:guest_id} WHERE id_member_from IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // They no longer exist, so we don't know who it was sent to. smf_db_query(' DELETE FROM {db_prefix}pm_recipients WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}drafts WHERE id_member IN ({array_int:members})', array('members' => $users)); // Delete avatar. require_once $sourcedir . '/lib/Subs-ManageAttachments.php'; removeAttachments(array('id_member' => $users)); // It's over, no more moderation for you. smf_db_query(' DELETE FROM {db_prefix}moderators WHERE id_member IN ({array_int:users})', array('users' => $users)); smf_db_query(' DELETE FROM {db_prefix}group_moderators WHERE id_member IN ({array_int:users})', array('users' => $users)); // If you don't exist we can't ban you. smf_db_query(' DELETE FROM {db_prefix}ban_items WHERE id_member IN ({array_int:users})', array('users' => $users)); // Remove individual theme settings. smf_db_query(' DELETE FROM {db_prefix}themes WHERE id_member IN ({array_int:users})', array('users' => $users)); // These users are nobody's buddy nomore. $request = smf_db_query(' SELECT id_member, pm_ignore_list, buddy_list FROM {db_prefix}members WHERE FIND_IN_SET({raw:pm_ignore_list}, pm_ignore_list) != 0 OR FIND_IN_SET({raw:buddy_list}, buddy_list) != 0', array('pm_ignore_list' => implode(', pm_ignore_list) != 0 OR FIND_IN_SET(', $users), 'buddy_list' => implode(', buddy_list) != 0 OR FIND_IN_SET(', $users))); while ($row = mysql_fetch_assoc($request)) { smf_db_query(' UPDATE {db_prefix}members SET pm_ignore_list = {string:pm_ignore_list}, buddy_list = {string:buddy_list} WHERE id_member = {int:id_member}', array('id_member' => $row['id_member'], 'pm_ignore_list' => implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)), 'buddy_list' => implode(',', array_diff(explode(',', $row['buddy_list']), $users)))); } mysql_free_result($request); // Make sure no member's birthday is still sticking in the calendar... updateSettings(array('calendar_updated' => time())); updateStats('member'); }
function Post2() { global $board, $topic, $txt, $modSettings, $sourcedir, $context; global $user_info, $board_info, $options, $smcFunc; // Sneaking off, are we? if (empty($_POST) && empty($topic)) { redirectexit('action=post;board=' . $board . '.0'); } elseif (empty($_POST) && !empty($topic)) { redirectexit('action=post;topic=' . $topic . '.0'); } // No need! $context['robot_no_index'] = true; // If we came from WYSIWYG then turn it back into BBC regardless. if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message'])) { require_once $sourcedir . '/Subs-Editor.php'; $_REQUEST['message'] = html_to_bbc($_REQUEST['message']); // We need to unhtml it now as it gets done shortly. $_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']); // We need this for everything else. $_POST['message'] = $_REQUEST['message']; } // Previewing? Go back to start. if (isset($_REQUEST['preview'])) { return Post(); } // Prevent double submission of this form. checkSubmitOnce('check'); // No errors as yet. $post_errors = array(); // If the session has timed out, let the user re-submit their form. if (checkSession('post', '', false) != '') { $post_errors[] = 'session_timeout'; } // Wrong verification code? if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) { require_once $sourcedir . '/Subs-Editor.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { $post_errors = array_merge($post_errors, $context['require_verification']); } } require_once $sourcedir . '/Subs-Post.php'; loadLanguage('Post'); // If this isn't a new topic load the topic info that we need. if (!empty($topic)) { $request = $smcFunc['db_query']('', ' SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board FROM {db_prefix}topics WHERE id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic)); $topic_info = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); // Though the topic should be there, it might have vanished. if (!is_array($topic_info)) { fatal_lang_error('topic_doesnt_exist'); } // Did this topic suddenly move? Just checking... if ($topic_info['id_board'] != $board) { fatal_lang_error('not_a_topic'); } } // Replying to a topic? if (!empty($topic) && !isset($_REQUEST['msg'])) { // Don't allow a post if it's locked. if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } // Sorry, multiple polls aren't allowed... yet. You should stop giving me ideas :P. if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) { unset($_REQUEST['poll']); } // Do the permissions and approval stuff... $becomesApproved = true; if ($topic_info['id_member_started'] != $user_info['id']) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) { $becomesApproved = false; } else { isAllowedTo('post_reply_any'); } } elseif (!allowedTo('post_reply_any')) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) { $becomesApproved = false; } else { isAllowedTo('post_reply_own'); } } if (isset($_POST['lock'])) { // Nothing is changed to the lock. if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You cannot override a moderator lock. if ($topic_info['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // So you wanna (un)sticky this...let's see. if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error. if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) { $_REQUEST['preview'] = true; return Post(); } $posterIsGuest = $user_info['is_guest']; } elseif (empty($topic)) { // Now don't be silly, new topics will get their own id_msg soon enough. unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']); // Do like, the permissions, for safety and stuff... $becomesApproved = true; if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) { $becomesApproved = false; } else { isAllowedTo('post_new'); } if (isset($_POST['lock'])) { // New topics are by default not locked. if (empty($_POST['lock'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own'))) { unset($_POST['lock']); } else { $_POST['lock'] = allowedTo('lock_any') ? 1 : 2; } } if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } $posterIsGuest = $user_info['is_guest']; } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; $request = $smcFunc['db_query']('', ' SELECT id_member, poster_name, poster_email, poster_time, approved FROM {db_prefix}messages WHERE id_msg = {int:id_msg} LIMIT 1', array('id_msg' => $_REQUEST['msg'])); if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('cant_find_messages', false); } $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } if (isset($_POST['lock'])) { // Nothing changes to the lock status. if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You're not allowed to break a moderator's lock. if ($topic_info['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // Change the sticky status of this topic? if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) { unset($_POST['sticky']); } if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); // If you're modifying a reply, I say it better be logged... $moderationAction = true; } else { isAllowedTo('modify_any'); // Log it, assuming you're not modifying your own post. if ($row['id_member'] != $user_info['id']) { $moderationAction = true; } } $posterIsGuest = empty($row['id_member']); // Can they approve it? $can_approve = allowedTo('approve_posts'); $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$row['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $row['approved'] : 1; $approve_has_changed = $row['approved'] != $becomesApproved; if (!allowedTo('moderate_forum') || !$posterIsGuest) { $_POST['guestname'] = $row['poster_name']; $_POST['email'] = $row['poster_email']; } } // If the poster is a guest evaluate the legality of name and email. if ($posterIsGuest) { $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']); $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']); if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') { $post_errors[] = 'no_name'; } if ($smcFunc['strlen']($_POST['guestname']) > 25) { $post_errors[] = 'long_name'; } if (empty($modSettings['guest_post_no_email'])) { // Only check if they changed it! if (!isset($row) || $row['poster_email'] != $_POST['email']) { if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == '')) { $post_errors[] = 'no_email'; } if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_POST['email']) == 0) { $post_errors[] = 'bad_email'; } } // Now make sure this email address is not banned from posting. isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title'])); } // In case they are making multiple posts this visit, help them along by storing their name. if (empty($post_errors)) { $_SESSION['guest_name'] = $_POST['guestname']; $_SESSION['guest_email'] = $_POST['email']; } } // Check the subject and message. if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '') { $post_errors[] = 'no_subject'; } if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '') { $post_errors[] = 'no_message'; } elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength']) { $post_errors[] = 'long_message'; } else { // Prepare the message a bit for some additional testing. $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES); // Preparse code. (Zef) if ($user_info['is_guest']) { $user_info['name'] = $_POST['guestname']; } preparsecode($_POST['message']); // Let's see if there's still some content left without the tags. if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) { $post_errors[] = 'no_message'; } } if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '') { $post_errors[] = 'no_event'; } // You are not! if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin']) { fatal_error('Knave! Masquerader! Charlatan!', false); } // Validate the poll... if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') { if (!empty($topic) && !isset($_REQUEST['msg'])) { fatal_lang_error('no_access', false); } // This is a new topic... so it's a new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } if (!isset($_POST['question']) || trim($_POST['question']) == '') { $post_errors[] = 'no_question'; } $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']); // Get rid of empty ones. foreach ($_POST['options'] as $k => $option) { if ($option == '') { unset($_POST['options'][$k], $_POST['options'][$k]); } } // What are you going to vote between with one choice?!? if (count($_POST['options']) < 2) { $post_errors[] = 'poll_few'; } } if ($posterIsGuest) { // If user is a guest, make sure the chosen name isn't taken. require_once $sourcedir . '/Subs-Members.php'; if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name'])) { $post_errors[] = 'bad_name'; } } elseif (!isset($_REQUEST['msg'])) { $_POST['guestname'] = $user_info['username']; $_POST['email'] = $user_info['email']; } // Any mistakes? if (!empty($post_errors)) { loadLanguage('Errors'); // Previewing. $_REQUEST['preview'] = true; $context['post_error'] = array('messages' => array()); foreach ($post_errors as $post_error) { $context['post_error'][$post_error] = true; if ($post_error == 'long_message') { $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']); } $context['post_error']['messages'][] = $txt['error_' . $post_error]; } return Post(); } // Make sure the user isn't spamming the board. if (!isset($_REQUEST['msg'])) { spamProtection('post'); } // At about this point, we're posting and that's that. ignore_user_abort(true); @set_time_limit(300); // Add special html entities to the subject, name, and email. $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $_POST['guestname'] = htmlspecialchars($_POST['guestname']); $_POST['email'] = htmlspecialchars($_POST['email']); // At this point, we want to make sure the subject isn't too long. if ($smcFunc['strlen']($_POST['subject']) > 100) { $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100); } // Make the poll... if (isset($_REQUEST['poll'])) { // Make sure that the user has not entered a ridiculous number of options.. if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) { $_POST['poll_max_votes'] = 1; } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) { $_POST['poll_max_votes'] = count($_POST['options']); } else { $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes']; } $_POST['poll_expire'] = (int) $_POST['poll_expire']; $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']); // Just set it to zero if it's not there.. if (!isset($_POST['poll_hide'])) { $_POST['poll_hide'] = 0; } else { $_POST['poll_hide'] = (int) $_POST['poll_hide']; } $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0; $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0; // Make sure guests are actually allowed to vote generally. if ($_POST['poll_guest_vote']) { require_once $sourcedir . '/Subs-Members.php'; $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); if (!in_array(-1, $allowedVoteGroups['allowed'])) { $_POST['poll_guest_vote'] = 0; } } // If the user tries to set the poll too far in advance, don't let them. if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) { fatal_lang_error('poll_range_error', false); } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) { $_POST['poll_hide'] = 1; } // Clean up the question and answers. $_POST['question'] = htmlspecialchars($_POST['question']); $_POST['question'] = $smcFunc['truncate']($_POST['question'], 255); $_POST['question'] = preg_replace('~&#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']); $_POST['options'] = htmlspecialchars__recursive($_POST['options']); } // Check if they are trying to delete any current attachments.... if (isset($_REQUEST['msg'], $_POST['attach_del']) && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))) { $del_temp = array(); foreach ($_POST['attach_del'] as $i => $dummy) { $del_temp[$i] = (int) $dummy; } require_once $sourcedir . '/ManageAttachments.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $del_temp); removeAttachments($attachmentQuery); } // ...or attach a new file... if (isset($_FILES['attachment']['name']) || !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) { // Verify they can post them! if (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_attachments')) { isAllowedTo('post_attachment'); } // Make sure we're uploading to the right place. if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } // The current directory, of course! $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; } else { $current_attach_dir = $modSettings['attachmentUploadDir']; } // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg'])) { $request = $smcFunc['db_query']('', ' SELECT COUNT(*), SUM(size) FROM {db_prefix}attachments WHERE id_msg = {int:id_msg} AND attachment_type = {int:attachment_type}', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0)); list($quantity, $total_size) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); } else { $quantity = 0; $total_size = 0; } if (!empty($_SESSION['temp_attachments'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $name) { if (preg_match('~^post_tmp_' . $user_info['id'] . '_\\d+$~', $attachID) == 0) { continue; } if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) { unset($_SESSION['temp_attachments'][$attachID]); @unlink($current_attach_dir . '/' . $attachID); continue; } $_FILES['attachment']['tmp_name'][] = $attachID; $_FILES['attachment']['name'][] = $name; $_FILES['attachment']['size'][] = filesize($current_attach_dir . '/' . $attachID); list($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($current_attach_dir . '/' . $attachID); unset($_SESSION['temp_attachments'][$attachID]); } } if (!isset($_FILES['attachment']['name'])) { $_FILES['attachment']['tmp_name'] = array(); } $attachIDs = array(); foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) { if ($_FILES['attachment']['name'][$n] == '') { continue; } // Have we reached the maximum number of files we are allowed? $quantity++; if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) { checkSubmitOnce('free'); fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit'])); } // Check the total upload size for this post... $total_size += $_FILES['attachment']['size'][$n]; if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) { checkSubmitOnce('free'); fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit'])); } $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $_FILES['attachment']['name'][$n], 'tmp_name' => $_FILES['attachment']['tmp_name'][$n], 'size' => $_FILES['attachment']['size'][$n], 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment')); if (createAttachment($attachmentOptions)) { $attachIDs[] = $attachmentOptions['id']; if (!empty($attachmentOptions['thumb'])) { $attachIDs[] = $attachmentOptions['thumb']; } } else { if (in_array('could_not_upload', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('attach_timeout', 'critical'); } if (in_array('too_large', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit'])); } if (in_array('bad_extension', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false); } if (in_array('directory_full', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('ran_out_of_space', 'critical'); } if (in_array('bad_filename', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical'); } if (in_array('taken_filename', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('filename_exists'); } if (in_array('bad_attachment', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('bad_attachment'); } } } } // Make the poll... if (isset($_REQUEST['poll'])) { // Create the poll. $smcFunc['db_insert']('', '{db_prefix}polls', array('question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int', 'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'), array($_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24, $user_info['id'], $_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote']), array('id_poll')); $id_poll = $smcFunc['db_insert_id']('{db_prefix}polls', 'id_poll'); // Create each answer choice. $i = 0; $pollOptions = array(); foreach ($_POST['options'] as $option) { $pollOptions[] = array($id_poll, $i, $option); $i++; } $smcFunc['db_insert']('insert', '{db_prefix}poll_choices', array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'), $pollOptions, array('id_poll', 'id_choice')); } else { $id_poll = 0; } // Creating a new topic? $newTopic = empty($_REQUEST['msg']) && empty($topic); $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon']; // Collect all parameters for the creation or modification of a post. $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved); $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved'])); $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']); // This is an already existing message. Edit it. if (!empty($_REQUEST['msg'])) { // Have admins allowed people to hide their screwups? if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) { $msgOptions['modify_time'] = time(); $msgOptions['modify_name'] = $user_info['name']; } // This will save some time... if (empty($approve_has_changed)) { unset($msgOptions['approved']); } modifyPost($msgOptions, $topicOptions, $posterOptions); } else { createPost($msgOptions, $topicOptions, $posterOptions); if (isset($topicOptions['id'])) { $topic = $topicOptions['id']; } } // Editing or posting an event? if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) { require_once $sourcedir . '/Subs-Calendar.php'; // Make sure they can link an event to this post. canLinkEvent(); // Insert the event. $eventOptions = array('board' => $board, 'topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0); insertEvent($eventOptions); } elseif (isset($_POST['calendar'])) { $_REQUEST['eventid'] = (int) $_REQUEST['eventid']; // Validate the post... require_once $sourcedir . '/Subs-Calendar.php'; validateEventPost(); // If you're not allowed to edit any events, you have to be the poster. if (!allowedTo('calendar_edit_any')) { // Get the event's poster. $request = $smcFunc['db_query']('', ' SELECT id_member FROM {db_prefix}calendar WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid'])); $row2 = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...) isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any')); } // Delete it? if (isset($_REQUEST['deleteevent'])) { $smcFunc['db_query']('', ' DELETE FROM {db_prefix}calendar WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid'])); } else { $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0; $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']); $smcFunc['db_query']('', ' UPDATE {db_prefix}calendar SET end_date = {date:end_date}, start_date = {date:start_date}, title = {string:title} WHERE id_event = {int:id_event}', array('end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'start_date' => strftime('%Y-%m-%d', $start_time), 'id_event' => $_REQUEST['eventid'], 'title' => $smcFunc['htmlspecialchars']($_REQUEST['evtitle'], ENT_QUOTES))); } updateSettings(array('calendar_updated' => time())); } // Marking read should be done even for editing messages.... // Mark all the parents read. (since you just posted and they will be unread.) if (!$user_info['is_guest'] && !empty($board_info['parent_boards'])) { $smcFunc['db_query']('', ' UPDATE {db_prefix}log_boards SET id_msg = {int:id_msg} WHERE id_member = {int:current_member} AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID'])); } // Turn notification on or off. (note this just blows smoke if it's already on or off.) if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) { $smcFunc['db_insert']('ignore', '{db_prefix}log_notify', array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'), array($user_info['id'], $topic, 0), array('id_member', 'id_topic', 'id_board')); } elseif (!$newTopic) { $smcFunc['db_query']('', ' DELETE FROM {db_prefix}log_notify WHERE id_member = {int:current_member} AND id_topic = {int:current_topic}', array('current_member' => $user_info['id'], 'current_topic' => $topic)); } // Log an act of moderation - modifying. if (!empty($moderationAction)) { logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board)); } if (isset($_POST['lock']) && $_POST['lock'] != 2) { logAction('lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board'])); } if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) { logAction('sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board'])); } // Notify any members who have notification turned on for this topic - only do this if it's going to be approved(!) if ($becomesApproved) { if ($newTopic) { $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic); notifyMembersBoard($notifyData); } elseif (empty($_REQUEST['msg'])) { // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it. if ($topic_info['approved']) { sendNotifications($topic, 'reply'); } else { sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']); } } } // Returning to the topic? if (!empty($_REQUEST['goback'])) { // Mark the board as read.... because it might get confusing otherwise. $smcFunc['db_query']('', ' UPDATE {db_prefix}log_boards SET id_msg = {int:maxMsgID} WHERE id_member = {int:current_member} AND id_board = {int:current_board}', array('current_board' => $board, 'current_member' => $user_info['id'], 'maxMsgID' => $modSettings['maxMsgID'])); } if ($board_info['num_topics'] == 0) { cache_put_data('board-' . $board, null, 120); } if (!empty($_POST['announce_topic'])) { redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback')); } if (!empty($_POST['move']) && allowedTo('move_any')) { redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback')); } // Return to post if the mod is on. if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], $context['browser']['is_ie']); } elseif (!empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.new#new', $context['browser']['is_ie']); } else { redirectexit('board=' . $board . '.0'); } }
/** * Remove a specific message (including permission checks). * - normally, local and global should be the localCookies and globalCookies settings, respectively. * - uses boardurl to determine these two things. * * @param int $message The message id * @param bool $decreasePostCount if true users' post count will be reduced * @return array an array to set the cookie on with domain and path in it, in that order */ function removeMessage($message, $decreasePostCount = true) { global $board, $sourcedir, $modSettings, $user_info, $smcFunc, $context; if (empty($message) || !is_numeric($message)) { return false; } $request = $smcFunc['db_query']('', ' SELECT m.id_member, m.icon, m.poster_time, m.subject,' . (empty($modSettings['search_custom_index_config']) ? '' : ' m.body,') . ' m.approved, t.id_topic, t.id_first_msg, t.id_last_msg, t.num_replies, t.id_board, t.id_member_started AS id_member_poster, b.count_posts FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE m.id_msg = {int:id_msg} LIMIT 1', array('id_msg' => $message)); if ($smcFunc['db_num_rows']($request) == 0) { return false; } $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); if (empty($board) || $row['id_board'] != $board) { $delete_any = boardsAllowedTo('delete_any'); if (!in_array(0, $delete_any) && !in_array($row['id_board'], $delete_any)) { $delete_own = boardsAllowedTo('delete_own'); $delete_own = in_array(0, $delete_own) || in_array($row['id_board'], $delete_own); $delete_replies = boardsAllowedTo('delete_replies'); $delete_replies = in_array(0, $delete_replies) || in_array($row['id_board'], $delete_replies); if ($row['id_member'] == $user_info['id']) { if (!$delete_own) { if ($row['id_member_poster'] == $user_info['id']) { if (!$delete_replies) { fatal_lang_error('cannot_delete_replies', 'permission'); } } else { fatal_lang_error('cannot_delete_own', 'permission'); } } elseif (($row['id_member_poster'] != $user_info['id'] || !$delete_replies) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + $modSettings['edit_disable_time'] * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } } elseif ($row['id_member_poster'] == $user_info['id']) { if (!$delete_replies) { fatal_lang_error('cannot_delete_replies', 'permission'); } } else { fatal_lang_error('cannot_delete_any', 'permission'); } } // Can't delete an unapproved message, if you can't see it! if ($modSettings['postmod_active'] && !$row['approved'] && $row['id_member'] != $user_info['id'] && !(in_array(0, $delete_any) || in_array($row['id_board'], $delete_any))) { $approve_posts = boardsAllowedTo('approve_posts'); if (!in_array(0, $approve_posts) && !in_array($row['id_board'], $approve_posts)) { return false; } } } else { // Check permissions to delete this message. if ($row['id_member'] == $user_info['id']) { if (!allowedTo('delete_own')) { if ($row['id_member_poster'] == $user_info['id'] && !allowedTo('delete_any')) { isAllowedTo('delete_replies'); } elseif (!allowedTo('delete_any')) { isAllowedTo('delete_own'); } } elseif (!allowedTo('delete_any') && ($row['id_member_poster'] != $user_info['id'] || !allowedTo('delete_replies')) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + $modSettings['edit_disable_time'] * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('delete_any')) { isAllowedTo('delete_replies'); } else { isAllowedTo('delete_any'); } if ($modSettings['postmod_active'] && !$row['approved'] && $row['id_member'] != $user_info['id'] && !allowedTo('delete_own')) { isAllowedTo('approve_posts'); } } // Close any moderation reports for this message. $smcFunc['db_query']('', ' UPDATE {db_prefix}log_reported SET closed = {int:is_closed} WHERE id_msg = {int:id_msg}', array('is_closed' => 1, 'id_msg' => $message)); if ($smcFunc['db_affected_rows']() != 0) { require_once $sourcedir . '/ModerationCenter.php'; updateSettings(array('last_mod_report_action' => time())); recountOpenReports(); } // Delete the *whole* topic, but only if the topic consists of one message. if ($row['id_first_msg'] == $message) { if (empty($board) || $row['id_board'] != $board) { $remove_any = boardsAllowedTo('remove_any'); $remove_any = in_array(0, $remove_any) || in_array($row['id_board'], $remove_any); if (!$remove_any) { $remove_own = boardsAllowedTo('remove_own'); $remove_own = in_array(0, $remove_own) || in_array($row['id_board'], $remove_own); } if ($row['id_member'] != $user_info['id'] && !$remove_any) { fatal_lang_error('cannot_remove_any', 'permission'); } elseif (!$remove_any && !$remove_own) { fatal_lang_error('cannot_remove_own', 'permission'); } } else { // Check permissions to delete a whole topic. if ($row['id_member'] != $user_info['id']) { isAllowedTo('remove_any'); } elseif (!allowedTo('remove_any')) { isAllowedTo('remove_own'); } } // ...if there is only one post. if (!empty($row['num_replies'])) { fatal_lang_error('delFirstPost', false); } removeTopics($row['id_topic']); return true; } // Deleting a recycled message can not lower anyone's post count. if ($row['icon'] == 'recycled') { $decreasePostCount = false; } // This is the last post, update the last post on the board. if ($row['id_last_msg'] == $message) { // Find the last message, set it, and decrease the post count. $request = $smcFunc['db_query']('', ' SELECT id_msg, id_member FROM {db_prefix}messages WHERE id_topic = {int:id_topic} AND id_msg != {int:id_msg} ORDER BY ' . ($modSettings['postmod_active'] ? 'approved DESC, ' : '') . 'id_msg DESC LIMIT 1', array('id_topic' => $row['id_topic'], 'id_msg' => $message)); $row2 = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); $smcFunc['db_query']('', ' UPDATE {db_prefix}topics SET id_last_msg = {int:id_last_msg}, id_member_updated = {int:id_member_updated}' . (!$modSettings['postmod_active'] || $row['approved'] ? ', num_replies = CASE WHEN num_replies = {int:no_replies} THEN 0 ELSE num_replies - 1 END' : ', unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . ' WHERE id_topic = {int:id_topic}', array('id_last_msg' => $row2['id_msg'], 'id_member_updated' => $row2['id_member'], 'no_replies' => 0, 'no_unapproved' => 0, 'id_topic' => $row['id_topic'])); } else { $smcFunc['db_query']('', ' UPDATE {db_prefix}topics SET ' . ($row['approved'] ? ' num_replies = CASE WHEN num_replies = {int:no_replies} THEN 0 ELSE num_replies - 1 END' : ' unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . ' WHERE id_topic = {int:id_topic}', array('no_replies' => 0, 'no_unapproved' => 0, 'id_topic' => $row['id_topic'])); } // Default recycle to false. $recycle = false; // If recycle topics has been set, make a copy of this message in the recycle board. // Make sure we're not recycling messages that are already on the recycle board. if (!empty($modSettings['recycle_enable']) && $row['id_board'] != $modSettings['recycle_board'] && $row['icon'] != 'recycled') { // Check if the recycle board exists and if so get the read status. $request = $smcFunc['db_query']('', ' SELECT (IFNULL(lb.id_msg, 0) >= b.id_msg_updated) AS is_seen, id_last_msg FROM {db_prefix}boards AS b LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member}) WHERE b.id_board = {int:recycle_board}', array('current_member' => $user_info['id'], 'recycle_board' => $modSettings['recycle_board'])); if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('recycle_no_valid_board'); } list($isRead, $last_board_msg) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Is there an existing topic in the recycle board to group this post with? $request = $smcFunc['db_query']('', ' SELECT id_topic, id_first_msg, id_last_msg FROM {db_prefix}topics WHERE id_previous_topic = {int:id_previous_topic} AND id_board = {int:recycle_board}', array('id_previous_topic' => $row['id_topic'], 'recycle_board' => $modSettings['recycle_board'])); list($id_recycle_topic, $first_topic_msg, $last_topic_msg) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Insert a new topic in the recycle board if $id_recycle_topic is empty. if (empty($id_recycle_topic)) { $smcFunc['db_insert']('', '{db_prefix}topics', array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'id_previous_topic' => 'int'), array($modSettings['recycle_board'], $row['id_member'], $row['id_member'], $message, $message, 0, 1, $row['id_topic']), array('id_topic')); } // Capture the ID of the new topic... $topicID = empty($id_recycle_topic) ? $smcFunc['db_insert_id']('{db_prefix}topics', 'id_topic') : $id_recycle_topic; // If the topic creation went successful, move the message. if ($topicID > 0) { $smcFunc['db_query']('', ' UPDATE {db_prefix}messages SET id_topic = {int:id_topic}, id_board = {int:recycle_board}, icon = {string:recycled}, approved = {int:is_approved} WHERE id_msg = {int:id_msg}', array('id_topic' => $topicID, 'recycle_board' => $modSettings['recycle_board'], 'id_msg' => $message, 'recycled' => 'recycled', 'is_approved' => 1)); // Take any reported posts with us... $smcFunc['db_query']('', ' UPDATE {db_prefix}log_reported SET id_topic = {int:id_topic}, id_board = {int:recycle_board} WHERE id_msg = {int:id_msg}', array('id_topic' => $topicID, 'recycle_board' => $modSettings['recycle_board'], 'id_msg' => $message)); // Mark recycled topic as read. if (!$user_info['is_guest']) { $smcFunc['db_insert']('replace', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($topicID, $user_info['id'], $modSettings['maxMsgID']), array('id_topic', 'id_member')); } // Mark recycle board as seen, if it was marked as seen before. if (!empty($isRead) && !$user_info['is_guest']) { $smcFunc['db_insert']('replace', '{db_prefix}log_boards', array('id_board' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($modSettings['recycle_board'], $user_info['id'], $modSettings['maxMsgID']), array('id_board', 'id_member')); } // Add one topic and post to the recycle bin board. $smcFunc['db_query']('', ' UPDATE {db_prefix}boards SET num_topics = num_topics + {int:num_topics_inc}, num_posts = num_posts + 1' . ($message > $last_board_msg ? ', id_last_msg = {int:id_merged_msg}' : '') . ' WHERE id_board = {int:recycle_board}', array('num_topics_inc' => empty($id_recycle_topic) ? 1 : 0, 'recycle_board' => $modSettings['recycle_board'], 'id_merged_msg' => $message)); // Lets increase the num_replies, and the first/last message ID as appropriate. if (!empty($id_recycle_topic)) { $smcFunc['db_query']('', ' UPDATE {db_prefix}topics SET num_replies = num_replies + 1' . ($message > $last_topic_msg ? ', id_last_msg = {int:id_merged_msg}' : '') . ($message < $first_topic_msg ? ', id_first_msg = {int:id_merged_msg}' : '') . ' WHERE id_topic = {int:id_recycle_topic}', array('id_recycle_topic' => $id_recycle_topic, 'id_merged_msg' => $message)); } // Make sure this message isn't getting deleted later on. $recycle = true; // Make sure we update the search subject index. updateStats('subject', $topicID, $row['subject']); } // If it wasn't approved don't keep it in the queue. if (!$row['approved']) { $smcFunc['db_query']('', ' DELETE FROM {db_prefix}approval_queue WHERE id_msg = {int:id_msg} AND id_attach = {int:id_attach}', array('id_msg' => $message, 'id_attach' => 0)); } } $smcFunc['db_query']('', ' UPDATE {db_prefix}boards SET ' . ($row['approved'] ? ' num_posts = CASE WHEN num_posts = {int:no_posts} THEN 0 ELSE num_posts - 1 END' : ' unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . ' WHERE id_board = {int:id_board}', array('no_posts' => 0, 'no_unapproved' => 0, 'id_board' => $row['id_board'])); // If the poster was registered and the board this message was on incremented // the member's posts when it was posted, decrease his or her post count. if (!empty($row['id_member']) && $decreasePostCount && empty($row['count_posts']) && $row['approved']) { updateMemberData($row['id_member'], array('posts' => '-')); } // Only remove posts if they're not recycled. if (!$recycle) { // Remove the message! $smcFunc['db_query']('', ' DELETE FROM {db_prefix}messages WHERE id_msg = {int:id_msg}', array('id_msg' => $message)); if (!empty($modSettings['search_custom_index_config'])) { $customIndexSettings = unserialize($modSettings['search_custom_index_config']); $words = text2words($row['body'], $customIndexSettings['bytes_per_word'], true); if (!empty($words)) { $smcFunc['db_query']('', ' DELETE FROM {db_prefix}log_search_words WHERE id_word IN ({array_int:word_list}) AND id_msg = {int:id_msg}', array('word_list' => $words, 'id_msg' => $message)); } } // Delete attachment(s) if they exist. require_once $sourcedir . '/ManageAttachments.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => $message); removeAttachments($attachmentQuery); // Allow mods to remove message related data of their own (likes, maybe?) call_integration_hook('integrate_remove_message', array($message)); } // Update the pesky statistics. updateStats('message'); updateStats('topic'); updateSettings(array('calendar_updated' => time())); // And now to update the last message of each board we messed with. require_once $sourcedir . '/Subs-Post.php'; if ($recycle) { updateLastMessages(array($row['id_board'], $modSettings['recycle_board'])); } else { updateLastMessages($row['id_board']); } return false; }
function ApproveAttach() { global $smcFunc; // Security is our primary concern... checkSession('get'); // If it approve or delete? $is_approve = !isset($_GET['sa']) || $_GET['sa'] != 'reject' ? true : false; $attachments = array(); // If we are approving all ID's in a message , get the ID's. if ($_GET['sa'] == 'all' && !empty($_GET['mid'])) { $id_msg = (int) $_GET['mid']; $request = $smcFunc['db_query']('', ' SELECT id_attach FROM {db_prefix}attachments WHERE id_msg = {int:id_msg} AND approved = {int:is_approved} AND attachment_type = {int:attachment_type}', array('id_msg' => $id_msg, 'is_approved' => 0, 'attachment_type' => 0)); while ($row = $smcFunc['db_fetch_assoc']($request)) { $attachments[] = $row['id_attach']; } $smcFunc['db_free_result']($request); } elseif (!empty($_GET['aid'])) { $attachments[] = (int) $_GET['aid']; } if (empty($attachments)) { fatal_lang_error('no_access', false); } // Now we have some ID's cleaned and ready to approve, but first - let's check we have permission! $allowed_boards = boardsAllowedTo('approve_posts'); // Validate the attachments exist and are the right approval state. $request = $smcFunc['db_query']('', ' SELECT a.id_attach, m.id_board, m.id_msg, m.id_topic FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) WHERE a.id_attach IN ({array_int:attachments}) AND a.attachment_type = {int:attachment_type} AND a.approved = {int:is_approved}', array('attachments' => $attachments, 'attachment_type' => 0, 'is_approved' => 0)); $attachments = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { // We can only add it if we can approve in this board! if ($allowed_boards = array(0) || in_array($row['id_board'], $allowed_boards)) { $attachments[] = $row['id_attach']; // Also come up witht he redirection URL. $redirect = 'topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']; } } $smcFunc['db_free_result']($request); if (empty($attachments)) { fatal_lang_error('no_access', false); } // Finally, we are there. Follow through! if ($is_approve) { ApproveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments)); } // Return to the topic.... redirectexit($redirect); }
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 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; }
/** * Update an attachment's thumbnail * * @package Attachments * @param string $filename * @param int $id_attach * @param int $id_msg * @param int $old_id_thumb = 0 * @return array The updated information */ function updateAttachmentThumbnail($filename, $id_attach, $id_msg, $old_id_thumb = 0) { global $modSettings; $attachment = array('id_attach' => $id_attach); require_once SUBSDIR . '/Graphics.subs.php'; if (createThumbnail($filename, $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight'])) { // So what folder are we putting this image in? $id_folder_thumb = getAttachmentPathID(); // 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. $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 = $filename . '_thumb'; $thumb_hash = getAttachmentFilename($thumb_filename, 0, null, true); $db = database(); // Add this beauty to the database. $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')); $attachment['id_thumb'] = $db->insert_id('{db_prefix}attachments', 'id_attach'); if (!empty($attachment['id_thumb'])) { $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 SUBSDIR . '/ManageAttachments.subs.php'; removeAttachments(array('id_attach' => $old_id_thumb), '', false, false); } } } return $attachment; }
/** * View all unapproved attachments. */ function UnapprovedAttachments() { global $txt, $scripturl, $context, $user_info, $sourcedir, $smcFunc, $modSettings; $context['page_title'] = $txt['mc_unapproved_attachments']; // Once again, permissions are king! $approve_boards = boardsAllowedTo('approve_posts'); if ($approve_boards == array(0)) { $approve_query = ''; } elseif (!empty($approve_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')'; } else { $approve_query = ' AND 0'; } // Get together the array of things to act on, if any. $attachments = array(); if (isset($_GET['approve'])) { $attachments[] = (int) $_GET['approve']; } elseif (isset($_GET['delete'])) { $attachments[] = (int) $_GET['delete']; } elseif (isset($_POST['item'])) { foreach ($_POST['item'] as $item) { $attachments[] = (int) $item; } } // Are we approving or deleting? if (isset($_GET['approve']) || isset($_POST['do']) && $_POST['do'] == 'approve') { $curAction = 'approve'; } elseif (isset($_GET['delete']) || isset($_POST['do']) && $_POST['do'] == 'delete') { $curAction = 'delete'; } // Something to do, let's do it! if (!empty($attachments) && isset($curAction)) { checkSession('request'); // This will be handy. require_once $sourcedir . '/ManageAttachments.php'; // Confirm the attachments are eligible for changing! $request = $smcFunc['db_query']('', ' SELECT a.id_attach FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) LEFT JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board) WHERE a.id_attach IN ({array_int:attachments}) AND a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('attachments' => $attachments, 'not_approved' => 0, 'attachment_type' => 0)); $attachments = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $attachments[] = $row['id_attach']; } $smcFunc['db_free_result']($request); // Assuming it wasn't all like, proper illegal, we can do the approving. if (!empty($attachments)) { if ($curAction == 'approve') { ApproveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments, 'do_logging' => true)); } } } require_once $sourcedir . '/Subs-List.php'; $listOptions = array('id' => 'mc_unapproved_attach', 'width' => '100%', 'items_per_page' => $modSettings['defaultMaxMessages'], 'no_items_label' => $txt['mc_unapproved_attachments_none_found'], 'base_href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments', 'default_sort_col' => 'attach_name', 'get_items' => array('function' => 'list_getUnapprovedAttachments', 'params' => array($approve_query)), 'get_count' => array('function' => 'list_getNumUnapprovedAttachments', 'params' => array($approve_query)), 'columns' => array('attach_name' => array('header' => array('value' => $txt['mc_unapproved_attach_name']), 'data' => array('db' => 'filename'), 'sort' => array('default' => 'a.filename', 'reverse' => 'a.filename DESC')), 'attach_size' => array('header' => array('value' => $txt['mc_unapproved_attach_size']), 'data' => array('db' => 'size'), 'sort' => array('default' => 'a.size', 'reverse' => 'a.size DESC')), 'attach_poster' => array('header' => array('value' => $txt['mc_unapproved_attach_poster']), 'data' => array('function' => create_function('$data', ' return $data[\'poster\'][\'link\'];')), 'sort' => array('default' => 'm.id_member', 'reverse' => 'm.id_member DESC')), 'date' => array('header' => array('value' => $txt['date'], 'style' => 'width: 18%;'), 'data' => array('db' => 'time', 'class' => 'smalltext', 'style' => 'white-space:nowrap;'), 'sort' => array('default' => 'm.poster_time', 'reverse' => 'm.poster_time DESC')), 'message' => array('header' => array('value' => $txt['post']), 'data' => array('function' => create_function('$data', ' return \'<a href="\' . $data[\'message\'][\'href\'] . \'">\' . shorten_subject($data[\'message\'][\'subject\'], 20) . \'</a>\';'), 'class' => 'smalltext', 'style' => 'width:15em;'), 'sort' => array('default' => 'm.subject', 'reverse' => 'm.subject DESC')), 'action' => array('header' => array('value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" checked="checked" />', 'style' => 'width: 4%;'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="item[]" value="%1$d" checked="checked" class="input_check" />', 'params' => array('id' => false)), 'style' => 'text-align: center;'))), 'form' => array('href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments', 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id']), 'token' => 'mod-ap'), 'additional_rows' => array(array('position' => 'bottom_of_list', 'value' => ' <select name="do" onchange="if (this.value != 0 && confirm(\'' . $txt['mc_unapproved_sure'] . '\')) submit();"> <option value="0">' . $txt['with_selected'] . ':</option> <option value="0">-------------------</option> <option value="approve"> -- ' . $txt['approve'] . '</option> <option value="delete"> -- ' . $txt['delete'] . '</option> </select> <noscript><input type="submit" name="ml_go" value="' . $txt['go'] . '" class="button_submit" /></noscript>', 'align' => 'right'))); // Create the request list. createToken('mod-ap'); createList($listOptions); $context['sub_template'] = 'unapproved_attachments'; }
function shd_attach_delete() { global $smcFunc, $user_info, $context, $sourcedir; if (empty($context['ticket_id']) || empty($_GET['attach']) || (int) $_GET['attach'] == 0) { fatal_lang_error('no_access', false); } $_GET['attach'] = (int) $_GET['attach']; // Well, we have a ticket id. Let's figure out what department we're in so we can check permissions. $query = shd_db_query('', ' SELECT hdt.id_dept, a.filename, hda.id_msg, hdt.subject FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}helpdesk_attachments AS hda ON (hda.id_attach = a.id_attach) INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hda.id_ticket = hdt.id_ticket) WHERE {query_see_ticket} AND hda.id_ticket = {int:ticket} AND hda.id_attach = {int:attach} AND a.attachment_type = 0', array('attach' => $_GET['attach'], 'ticket' => $context['ticket_id'])); if ($smcFunc['db_num_rows']($query) == 0) { $smcFunc['db_free_result']($query); fatal_lang_error('no_access'); } list($dept, $filename, $id_msg, $subject) = $smcFunc['db_fetch_row']($query); $smcFunc['db_free_result']($query); shd_is_allowed_to('shd_delete_attachment', $dept); // So, we can delete the attachment. We already know it exists, we know we have permission. $log_params = array('subject' => $subject, 'ticket' => $context['ticket_id'], 'msg' => $id_msg, 'att_removed' => array(htmlspecialchars($filename))); shd_log_action('editticket', $log_params); // Now you can delete require_once $sourcedir . '/ManageAttachments.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => 0, 'id_attach' => array($_GET['attach'])); removeAttachments($attachmentQuery); redirectexit('action=helpdesk;sa=ticket;ticket=' . $context['ticket_id']); }
/** * Posts or saves the message composed with Post(). * * requires various permissions depending on the action. * handles attachment, post, and calendar saving. * sends off notifications, and allows for announcements and moderation. * accessed from ?action=post2. */ public function action_post2() { global $board, $topic, $txt, $modSettings, $context, $user_settings; global $user_info, $board_info, $options, $ignore_temp; // Sneaking off, are we? if (empty($_POST) && empty($topic)) { if (empty($_SERVER['CONTENT_LENGTH'])) { redirectexit('action=post;board=' . $board . '.0'); } else { fatal_lang_error('post_upload_error', false); } } elseif (empty($_POST) && !empty($topic)) { redirectexit('action=post;topic=' . $topic . '.0'); } // No need! $context['robot_no_index'] = true; // We are now in post2 action $context['current_action'] = 'post2'; require_once SOURCEDIR . '/AttachmentErrorContext.class.php'; // No errors as yet. $post_errors = Error_Context::context('post', 1); $attach_errors = Attachment_Error_Context::context(); // If the session has timed out, let the user re-submit their form. if (checkSession('post', '', false) != '') { $post_errors->addError('session_timeout'); // Disable the preview so that any potentially malicious code is not executed $_REQUEST['preview'] = false; return $this->action_post(); } // Wrong verification code? if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { foreach ($context['require_verification'] as $verification_error) { $post_errors->addError($verification_error); } } } require_once SUBSDIR . '/Boards.subs.php'; require_once SUBSDIR . '/Post.subs.php'; loadLanguage('Post'); // Drafts enabled and needed? if (!empty($modSettings['drafts_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft']))) { require_once SUBSDIR . '/Drafts.subs.php'; } // First check to see if they are trying to delete any current attachments. if (isset($_POST['attach_del'])) { $keep_temp = array(); $keep_ids = array(); foreach ($_POST['attach_del'] as $dummy) { if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false) { $keep_temp[] = $dummy; } else { $keep_ids[] = (int) $dummy; } } if (isset($_SESSION['temp_attachments'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files']) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } unset($_SESSION['temp_attachments'][$attachID]); @unlink($attachment['tmp_name']); } } if (!empty($_REQUEST['msg'])) { require_once SUBSDIR . '/ManageAttachments.subs.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $keep_ids); removeAttachments($attachmentQuery); } } // Then try to upload any attachments. $context['attachments']['can']['post'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')); if ($context['attachments']['can']['post'] && empty($_POST['from_qr'])) { require_once SUBSDIR . '/Attachments.subs.php'; if (isset($_REQUEST['msg'])) { processAttachments((int) $_REQUEST['msg']); } else { processAttachments(); } } // Previewing? Go back to start. if (isset($_REQUEST['preview'])) { return $this->action_post(); } // Prevent double submission of this form. checkSubmitOnce('check'); // If this isn't a new topic load the topic info that we need. if (!empty($topic)) { require_once SUBSDIR . '/Topic.subs.php'; $topic_info = getTopicInfo($topic); // Though the topic should be there, it might have vanished. if (empty($topic_info)) { fatal_lang_error('topic_doesnt_exist'); } // Did this topic suddenly move? Just checking... if ($topic_info['id_board'] != $board) { fatal_lang_error('not_a_topic'); } } // Replying to a topic? if (!empty($topic) && !isset($_REQUEST['msg'])) { // Don't allow a post if it's locked. if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } // Sorry, multiple polls aren't allowed... yet. You should stop giving me ideas :P. if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) { unset($_REQUEST['poll']); } // Do the permissions and approval stuff... $becomesApproved = true; if ($topic_info['id_member_started'] != $user_info['id']) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) { $becomesApproved = false; } else { isAllowedTo('post_reply_any'); } } elseif (!allowedTo('post_reply_any')) { if ($modSettings['postmod_active']) { if (allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) { $becomesApproved = false; } elseif ($user_info['is_guest'] && allowedTo('post_unapproved_replies_any')) { $becomesApproved = false; } else { isAllowedTo('post_reply_own'); } } } if (isset($_POST['lock'])) { // Nothing is changed to the lock. if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You cannot override a moderator lock. if ($topic_info['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // So you wanna (un)sticky this...let's see. if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } // If drafts are enabled, then pass this off if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) { saveDraft(); return $this->action_post(); } // If the number of replies has changed, if the setting is enabled, go back to action_post() - which handles the error. if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) { addInlineJavascript(' $(document).ready(function () { $("html,body").scrollTop($(\'.category_header:visible:first\').offset().top); });'); return $this->action_post(); } $posterIsGuest = $user_info['is_guest']; } elseif (empty($topic)) { // Now don't be silly, new topics will get their own id_msg soon enough. unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']); // Do like, the permissions, for safety and stuff... $becomesApproved = true; if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) { $becomesApproved = false; } else { isAllowedTo('post_new'); } if (isset($_POST['lock'])) { // New topics are by default not locked. if (empty($_POST['lock'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own'))) { unset($_POST['lock']); } else { $_POST['lock'] = allowedTo('lock_any') ? 1 : 2; } } if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } // Saving your new topic as a draft first? if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) { saveDraft(); return $this->action_post(); } $posterIsGuest = $user_info['is_guest']; } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; require_once SUBSDIR . '/Messages.subs.php'; $msgInfo = basicMessageInfo($_REQUEST['msg'], true); if (empty($msgInfo)) { fatal_lang_error('cant_find_messages', false); } if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } if (isset($_POST['lock'])) { // Nothing changes to the lock status. if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You're not allowed to break a moderator's lock. if ($topic_info['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // Change the sticky status of this topic? if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) { unset($_POST['sticky']); } if ($msgInfo['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { if ((!$modSettings['postmod_active'] || $msgInfo['approved']) && !empty($modSettings['edit_disable_time']) && $msgInfo['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); // If you're modifying a reply, I say it better be logged... $moderationAction = true; } else { isAllowedTo('modify_any'); // Log it, assuming you're not modifying your own post. if ($msgInfo['id_member'] != $user_info['id']) { $moderationAction = true; } } // If drafts are enabled, then lets send this off to save if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) { saveDraft(); return $this->action_post(); } $posterIsGuest = empty($msgInfo['id_member']); // Can they approve it? $can_approve = allowedTo('approve_posts'); $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$msgInfo['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $msgInfo['approved'] : 1; $approve_has_changed = $msgInfo['approved'] != $becomesApproved; if (!allowedTo('moderate_forum') || !$posterIsGuest) { $_POST['guestname'] = $msgInfo['poster_name']; $_POST['email'] = $msgInfo['poster_email']; } } // In case we want to override if (allowedTo('approve_posts')) { $becomesApproved = !isset($_REQUEST['approve']) || !empty($_REQUEST['approve']) ? 1 : 0; $approve_has_changed = isset($msgInfo['approved']) ? $msgInfo['approved'] != $becomesApproved : false; } // If the poster is a guest evaluate the legality of name and email. if ($posterIsGuest) { $_POST['guestname'] = !isset($_POST['guestname']) ? '' : Util::htmlspecialchars(trim($_POST['guestname'])); $_POST['email'] = !isset($_POST['email']) ? '' : Util::htmlspecialchars(trim($_POST['email'])); if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') { $post_errors->addError('no_name'); } if (Util::strlen($_POST['guestname']) > 25) { $post_errors->addError('long_name'); } if (empty($modSettings['guest_post_no_email'])) { // Only check if they changed it! if (!isset($msgInfo) || $msgInfo['poster_email'] != $_POST['email']) { require_once SUBSDIR . '/DataValidator.class.php'; if (!allowedTo('moderate_forum') && !Data_Validator::is_valid($_POST, array('email' => 'valid_email|required'), array('email' => 'trim'))) { empty($_POST['email']) ? $post_errors->addError('no_email') : $post_errors->addError('bad_email'); } } // Now make sure this email address is not banned from posting. isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title'])); } // In case they are making multiple posts this visit, help them along by storing their name. if (!$post_errors->hasErrors()) { $_SESSION['guest_name'] = $_POST['guestname']; $_SESSION['guest_email'] = $_POST['email']; } } // Check the subject and message. if (!isset($_POST['subject']) || Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) === '') { $post_errors->addError('no_subject'); } if (!isset($_POST['message']) || Util::htmltrim(Util::htmlspecialchars($_POST['message'], ENT_QUOTES)) === '') { $post_errors->addError('no_message'); } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) { $post_errors->addError(array('long_message', array($modSettings['max_messageLength']))); } else { // Prepare the message a bit for some additional testing. $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES); // Preparse code. (Zef) if ($user_info['is_guest']) { $user_info['name'] = $_POST['guestname']; } preparsecode($_POST['message']); // Let's see if there's still some content left without the tags. if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) { $post_errors->addError('no_message'); } } if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && Util::htmltrim($_POST['evtitle']) === '') { $post_errors->addError('no_event'); } // Validate the poll... if (isset($_REQUEST['poll']) && !empty($modSettings['pollMode'])) { if (!empty($topic) && !isset($_REQUEST['msg'])) { fatal_lang_error('no_access', false); } // This is a new topic... so it's a new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } if (!isset($_POST['question']) || trim($_POST['question']) == '') { $post_errors->addError('no_question'); } $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']); // Get rid of empty ones. foreach ($_POST['options'] as $k => $option) { if ($option == '') { unset($_POST['options'][$k], $_POST['options'][$k]); } } // What are you going to vote between with one choice?!? if (count($_POST['options']) < 2) { $post_errors->addError('poll_few'); } elseif (count($_POST['options']) > 256) { $post_errors->addError('poll_many'); } } if ($posterIsGuest) { // If user is a guest, make sure the chosen name isn't taken. require_once SUBSDIR . '/Members.subs.php'; if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($msgInfo['poster_name']) || $_POST['guestname'] != $msgInfo['poster_name'])) { $post_errors->addError('bad_name'); } } elseif (!isset($_REQUEST['msg'])) { $_POST['guestname'] = $user_info['username']; $_POST['email'] = $user_info['email']; } // Posting somewhere else? Are we sure you can? if (!empty($_REQUEST['post_in_board'])) { $new_board = (int) $_REQUEST['post_in_board']; if (!allowedTo('post_new', $new_board)) { $post_in_board = boardInfo($new_board); if (!empty($post_in_board)) { $post_errors->addError(array('post_new_board', array($post_in_board['name']))); } else { $post_errors->addError('post_new'); } } } // Any mistakes? if ($post_errors->hasErrors() || $attach_errors->hasErrors()) { addInlineJavascript(' $(document).ready(function () { $("html,body").scrollTop($(\'.category_header:visible:first\').offset().top); });'); return $this->action_post(); } // Make sure the user isn't spamming the board. if (!isset($_REQUEST['msg'])) { spamProtection('post'); } // At about this point, we're posting and that's that. ignore_user_abort(true); @set_time_limit(300); // Add special html entities to the subject, name, and email. $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $_POST['guestname'] = htmlspecialchars($_POST['guestname'], ENT_COMPAT, 'UTF-8'); $_POST['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8'); // At this point, we want to make sure the subject isn't too long. if (Util::strlen($_POST['subject']) > 100) { $_POST['subject'] = Util::substr($_POST['subject'], 0, 100); } if (!empty($modSettings['mentions_enabled']) && !empty($_REQUEST['uid'])) { $query_params = array(); $query_params['member_ids'] = array_unique(array_map('intval', $_REQUEST['uid'])); require_once SUBSDIR . '/Members.subs.php'; $mentioned_members = membersBy('member_ids', $query_params, true); $replacements = 0; $actually_mentioned = array(); foreach ($mentioned_members as $member) { $_POST['message'] = str_replace('@' . $member['real_name'], '[member=' . $member['id_member'] . ']' . $member['real_name'] . '[/member]', $_POST['message'], $replacements); if ($replacements > 0) { $actually_mentioned[] = $member['id_member']; } } } // Make the poll... if (isset($_REQUEST['poll'])) { // Make sure that the user has not entered a ridiculous number of options.. if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) { $_POST['poll_max_votes'] = 1; } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) { $_POST['poll_max_votes'] = count($_POST['options']); } else { $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes']; } $_POST['poll_expire'] = (int) $_POST['poll_expire']; $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']); // Just set it to zero if it's not there.. if (!isset($_POST['poll_hide'])) { $_POST['poll_hide'] = 0; } else { $_POST['poll_hide'] = (int) $_POST['poll_hide']; } $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0; $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0; // Make sure guests are actually allowed to vote generally. if ($_POST['poll_guest_vote']) { require_once SUBSDIR . '/Members.subs.php'; $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); if (!in_array(-1, $allowedVoteGroups['allowed'])) { $_POST['poll_guest_vote'] = 0; } } // If the user tries to set the poll too far in advance, don't let them. if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) { fatal_lang_error('poll_range_error', false); } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) { $_POST['poll_hide'] = 1; } // Clean up the question and answers. $_POST['question'] = htmlspecialchars($_POST['question'], ENT_COMPAT, 'UTF-8'); $_POST['question'] = Util::substr($_POST['question'], 0, 255); $_POST['question'] = preg_replace('~&#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']); $_POST['options'] = htmlspecialchars__recursive($_POST['options']); // Finally, make the poll. require_once SUBSDIR . '/Poll.subs.php'; $id_poll = createPoll($_POST['question'], $user_info['id'], $_POST['guestname'], $_POST['poll_max_votes'], $_POST['poll_hide'], $_POST['poll_expire'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'], $_POST['options']); } else { $id_poll = 0; } // ...or attach a new file... if (empty($ignore_temp) && $context['attachments']['can']['post'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) { $attachIDs = array(); foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } // If there was an initial error just show that message. if ($attachID == 'initial_error') { unset($_SESSION['temp_attachments']); break; } // No errors, then try to create the attachment if (empty($attachment['errors'])) { // Load the attachmentOptions array with the data needed to create an attachment $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $attachment['name'], 'tmp_name' => $attachment['tmp_name'], 'size' => isset($attachment['size']) ? $attachment['size'] : 0, 'mime_type' => isset($attachment['type']) ? $attachment['type'] : '', 'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : 0, 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'), 'errors' => array()); if (createAttachment($attachmentOptions)) { $attachIDs[] = $attachmentOptions['id']; if (!empty($attachmentOptions['thumb'])) { $attachIDs[] = $attachmentOptions['thumb']; } } } else { @unlink($attachment['tmp_name']); } } unset($_SESSION['temp_attachments']); } // Creating a new topic? $newTopic = empty($_REQUEST['msg']) && empty($topic); $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon']; // Collect all parameters for the creation or modification of a post. $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved); $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved'])); $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']); // This is an already existing message. Edit it. if (!empty($_REQUEST['msg'])) { // Have admins allowed people to hide their screwups? if (time() - $msgInfo['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $msgInfo['id_member']) { $msgOptions['modify_time'] = time(); $msgOptions['modify_name'] = $user_info['name']; } // This will save some time... if (empty($approve_has_changed)) { unset($msgOptions['approved']); } modifyPost($msgOptions, $topicOptions, $posterOptions); } else { if (!empty($modSettings['enableFollowup']) && !empty($_REQUEST['followup'])) { $original_post = (int) $_REQUEST['followup']; } // We also have to fake the board: // if it's valid and it's not the current, let's forget about the "current" and load the new one if (!empty($new_board) && $board !== $new_board) { $board = $new_board; loadBoard(); // Some details changed $topicOptions['board'] = $board; $topicOptions['is_approved'] = !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']); $posterOptions['update_post_count'] = !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']; } createPost($msgOptions, $topicOptions, $posterOptions); if (isset($topicOptions['id'])) { $topic = $topicOptions['id']; } if (!empty($modSettings['enableFollowup'])) { require_once SUBSDIR . '/FollowUps.subs.php'; require_once SUBSDIR . '/Messages.subs.php'; // Time to update the original message with a pointer to the new one if (!empty($original_post) && canAccessMessage($original_post)) { linkMessages($original_post, $topic); } } } // If we had a draft for this, its time to remove it since it was just posted if (!empty($modSettings['drafts_enabled']) && !empty($_POST['id_draft'])) { deleteDrafts($_POST['id_draft'], $user_info['id']); } // Editing or posting an event? if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) { require_once SUBSDIR . '/Calendar.subs.php'; // Make sure they can link an event to this post. canLinkEvent(); // Insert the event. $eventOptions = array('id_board' => $board, 'id_topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0); insertEvent($eventOptions); } elseif (isset($_POST['calendar'])) { $_REQUEST['eventid'] = (int) $_REQUEST['eventid']; // Validate the post... require_once SUBSDIR . '/Calendar.subs.php'; validateEventPost(); // If you're not allowed to edit any events, you have to be the poster. if (!allowedTo('calendar_edit_any')) { $event_poster = getEventPoster($_REQUEST['eventid']); // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...) isAllowedTo('calendar_edit_' . ($event_poster == $user_info['id'] ? 'own' : 'any')); } // Delete it? if (isset($_REQUEST['deleteevent'])) { removeEvent($_REQUEST['eventid']); } else { $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0; $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']); $eventOptions = array('start_date' => strftime('%Y-%m-%d', $start_time), 'end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'title' => $_REQUEST['evtitle']); modifyEvent($_REQUEST['eventid'], $eventOptions); } } // Marking boards as read. // (You just posted and they will be unread.) if (!$user_info['is_guest']) { $board_list = !empty($board_info['parent_boards']) ? array_keys($board_info['parent_boards']) : array(); // Returning to the topic? if (!empty($_REQUEST['goback'])) { $board_list[] = $board; } if (!empty($board_list)) { markBoardsRead($board_list, false, false); } } // Turn notification on or off. if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) { setTopicNotification($user_info['id'], $topic, true); } elseif (!$newTopic) { setTopicNotification($user_info['id'], $topic, false); } // Log an act of moderation - modifying. if (!empty($moderationAction)) { logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $msgInfo['id_member'], 'board' => $board)); } if (isset($_POST['lock']) && $_POST['lock'] != 2) { logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board'])); } if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) { logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board'])); } // Notify any members who have notification turned on for this topic/board - only do this if it's going to be approved(!) if ($becomesApproved) { require_once SUBSDIR . '/Notification.subs.php'; if ($newTopic) { $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic, 'signature' => isset($user_settings['signature']) ? $user_settings['signature'] : ''); sendBoardNotifications($notifyData); } elseif (empty($_REQUEST['msg'])) { // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it. if ($topic_info['approved']) { sendNotifications($topic, 'reply'); } else { sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']); } } } if (!empty($modSettings['mentions_enabled']) && !empty($actually_mentioned)) { require_once CONTROLLERDIR . '/Mentions.controller.php'; $mentions = new Mentions_Controller(); $mentions->setData(array('id_member' => $actually_mentioned, 'type' => 'men', 'id_msg' => $msgOptions['id'], 'status' => $becomesApproved ? 'new' : 'unapproved')); $mentions->action_add(); } if ($board_info['num_topics'] == 0) { cache_put_data('board-' . $board, null, 120); } if (!empty($_POST['announce_topic'])) { redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback')); } if (!empty($_POST['move']) && allowedTo('move_any')) { redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback')); } // Return to post if the mod is on. if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie')); } elseif (!empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.new#new', isBrowser('ie')); } else { redirectexit('board=' . $board . '.0'); } }
/** * If we are deleting an attachment, check if we should handle this. * * @since 2.1 * @param array &$listOptions The listOptions of attachments page. * @param array &$titles All the sections we have. * @param array &$list_title List title. */ function shd_attachment_remove(&$filesRemoved, $attachments) { if (in_array($_REQUEST['type'], array('shd_attach', 'shd_thumb')) && !empty($attachments)) { $messages = removeAttachments(array('id_attach' => $attachments), '', true); } }
function deleteMembers($users) { global $db_prefix, $sourcedir, $modSettings, $ID_MEMBER; // If it's not an array, make it so! if (!is_array($users)) { $users = array($users); } else { $users = array_unique($users); } // Make sure there's no void user in here. $users = array_diff($users, array(0)); // How many are they deleting? if (empty($users)) { return; } elseif (count($users) == 1) { list($user) = $users; $condition = '= ' . $user; if ($user == $ID_MEMBER) { isAllowedTo('profile_remove_own'); } else { isAllowedTo('profile_remove_any'); } } else { foreach ($users as $k => $v) { $users[$k] = (int) $v; } $condition = 'IN (' . implode(', ', $users) . ')'; // Deleting more than one? You can't have more than one account... isAllowedTo('profile_remove_any'); } // Make sure they aren't trying to delete administrators if they aren't one. But don't bother checking if it's just themself. if (!allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $ID_MEMBER)) { $request = db_query("\n\t\t\tSELECT ID_MEMBER\n\t\t\tFROM {$db_prefix}members\n\t\t\tWHERE ID_MEMBER IN (" . implode(', ', $users) . ")\n\t\t\t\tAND (ID_GROUP = 1 OR FIND_IN_SET(1, additionalGroups) != 0)\n\t\t\tLIMIT " . count($users), __FILE__, __LINE__); $admins = array(); while ($row = mysql_fetch_assoc($request)) { $admins[] = $row['ID_MEMBER']; } mysql_free_result($request); if (!empty($admins)) { $users = array_diff($users, $admins); } } if (empty($users)) { return; } // Log the action - regardless of who is deleting it. foreach ($users as $user) { // Integration rocks! if (isset($modSettings['integrate_delete_member']) && function_exists($modSettings['integrate_delete_member'])) { call_user_func($modSettings['integrate_delete_member'], $user); } logAction('delete_member', array('member' => $user)); } // Make these peoples' posts guest posts. db_query("\n\t\tUPDATE {$db_prefix}messages\n\t\tSET ID_MEMBER = 0" . (!empty($modSettings['allow_hideEmail']) ? ", posterEmail = ''" : '') . "\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tUPDATE {$db_prefix}polls\n\t\tSET ID_MEMBER = 0\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // Make these peoples' posts guest first posts and last posts. db_query("\n\t\tUPDATE {$db_prefix}topics\n\t\tSET ID_MEMBER_STARTED = 0\n\t\tWHERE ID_MEMBER_STARTED {$condition}", __FILE__, __LINE__); db_query("\n\t\tUPDATE {$db_prefix}topics\n\t\tSET ID_MEMBER_UPDATED = 0\n\t\tWHERE ID_MEMBER_UPDATED {$condition}", __FILE__, __LINE__); db_query("\n\t\tUPDATE {$db_prefix}log_actions\n\t\tSET ID_MEMBER = 0\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tUPDATE {$db_prefix}log_banned\n\t\tSET ID_MEMBER = 0\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tUPDATE {$db_prefix}log_errors\n\t\tSET ID_MEMBER = 0\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // Delete the member. db_query("\n\t\tDELETE FROM {$db_prefix}members\n\t\tWHERE ID_MEMBER {$condition}\n\t\tLIMIT " . count($users), __FILE__, __LINE__); // Delete the logs... db_query("\n\t\tDELETE FROM {$db_prefix}log_boards\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_karma\n\t\tWHERE ID_TARGET {$condition}\n\t\t\tOR ID_EXECUTOR {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_mark_read\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_notify\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_online\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_polls\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}log_topics\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); db_query("\n\t\tDELETE FROM {$db_prefix}collapsed_categories\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // Delete personal messages. require_once $sourcedir . '/PersonalMessage.php'; deleteMessages(null, null, $users); db_query("\n\t\tUPDATE {$db_prefix}personal_messages\n\t\tSET ID_MEMBER_FROM = 0\n\t\tWHERE ID_MEMBER_FROM {$condition}", __FILE__, __LINE__); // Delete avatar. require_once $sourcedir . '/ManageAttachments.php'; removeAttachments('a.ID_MEMBER ' . $condition); // It's over, no more moderation for you. db_query("\n\t\tDELETE FROM {$db_prefix}moderators\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // If you don't exist we can't ban you. db_query("\n\t\tDELETE FROM {$db_prefix}ban_items\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // Remove individual theme settings. db_query("\n\t\tDELETE FROM {$db_prefix}themes\n\t\tWHERE ID_MEMBER {$condition}", __FILE__, __LINE__); // These users are nobody's buddy nomore. $request = db_query("\n\t\tSELECT ID_MEMBER, pm_ignore_list, buddy_list\n\t\tFROM {$db_prefix}members\n\t\tWHERE FIND_IN_SET(" . implode(', pm_ignore_list) OR FIND_IN_SET(', $users) . ', pm_ignore_list) OR FIND_IN_SET(' . implode(', buddy_list) OR FIND_IN_SET(', $users) . ', buddy_list)', __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) { db_query("\n\t\t\tUPDATE {$db_prefix}members\n\t\t\tSET\n\t\t\t\tpm_ignore_list = '" . implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)) . "',\n\t\t\t\tbuddy_list = '" . implode(',', array_diff(explode(',', $row['buddy_list']), $users)) . "'\n\t\t\tWHERE ID_MEMBER = {$row['ID_MEMBER']}\n\t\t\tLIMIT 1", __FILE__, __LINE__); } mysql_free_result($request); // Make sure no member's birthday is still sticking in the calendar... updateStats('calendar'); updateStats('member'); }
function shd_handle_attachments() { global $modSettings, $smcFunc, $context, $user_info, $sourcedir, $txt; if (!shd_allowed_to('shd_post_attachment', $context['ticket_form']['dept'])) { return; } $attachIDs = array(); require_once $sourcedir . '/Subs-Attachments.php'; // Check if they are trying to delete any current attachments.... if (isset($_POST['attach_del'])) { shd_is_allowed_to('shd_delete_attachment', $context['ticket_form']['dept']); $del_temp = array(); foreach ($_POST['attach_del'] as $i => $dummy) { $del_temp[$i] = (int) $dummy; } // First, get them from the other table $query = shd_db_query('', ' SELECT a.id_attach FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}helpdesk_attachments AS hda ON (hda.id_attach = a.id_attach) WHERE ' . ($modSettings['shd_attachments_mode'] == 'ticket' ? 'hda.id_ticket = {int:ticket}' : 'hda.id_msg = {int:msg}'), array('msg' => $context['ticket_form']['msg'], 'ticket' => $context['ticket_id'])); $attachments = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { $attachments[] = $row['id_attach']; } $smcFunc['db_free_result']($query); // OK, so attachments = full list of attachments on this post, del_temp is list of ones to keep, so look for the ones that aren't in both lists $del_temp = array_diff($attachments, $del_temp); if (!empty($del_temp)) { $filenames = array(); // Before deleting, get the names for the log $query = $smcFunc['db_query']('', ' SELECT filename, attachment_type FROM {db_prefix}attachments WHERE id_attach IN ({array_int:attach}) ORDER BY id_attach', array('attach' => $del_temp)); $removed = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { $row['filename'] = htmlspecialchars($row['filename']); $filenames[] = $row['filename']; if ($row['attachment_type'] == 0) { $removed[] = $row['filename']; } } if (!empty($removed)) { $context['log_params']['att_removed'] = $removed; } // Now you can delete require_once $sourcedir . '/ManageAttachments.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => 0, 'id_attach' => $del_temp); removeAttachments($attachmentQuery); } } // ...or attach a new file... if (!empty($_FILES) || !empty($_SESSION['temp_attachments'])) { if (!empty($FILES)) { $_FILES = array_reverse($_FILES); } shd_is_allowed_to('shd_post_attachment'); // Make sure we're uploading to the right place. if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = json_decode($modSettings['attachmentUploadDir'], true); } // The current directory, of course! $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; } else { $current_attach_dir = $modSettings['attachmentUploadDir']; } // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg']) || !empty($context['ticket_id'])) { $request = shd_db_query('', ' SELECT COUNT(*), SUM(size) FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}helpdesk_attachments AS hda ON (a.id_attach = hda.id_attach) WHERE ' . ($modSettings['shd_attachments_mode'] == 'ticket' ? 'hda.id_ticket = {int:ticket}' : 'hda.id_msg = {int:msg}') . ' AND attachment_type = {int:attachment_type}', array('msg' => $context['ticket_form']['msg'], 'ticket' => $context['ticket_id'], 'attachment_type' => 0)); list($quantity, $total_size) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); } else { $quantity = 0; $total_size = 0; } if (!empty($_SESSION['temp_attachments'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $name) { if (preg_match('~^post_tmp_' . $user_info['id'] . '_\\d+$~', $attachID) == 0) { continue; } if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) { unset($_SESSION['temp_attachments'][$attachID]); @unlink($current_attach_dir . '/' . $attachID); continue; } $_FILES['attachment' . $attachID]['tmp_name'] = $attachID; $_FILES['attachment' . $attachID]['name'] = $name; $_FILES['attachment' . $attachID]['size'] = filesize($current_attach_dir . '/' . $attachID); list($_FILES['attachment' . $attachID]['width'], $_FILES['attachment' . $attachID]['height']) = @getimagesize($current_attach_dir . '/' . $attachID); unset($_SESSION['temp_attachments'][$attachID]); } } foreach ($_FILES as $uplfile) { if ($uplfile['name'] == '') { continue; } // Have we reached the maximum number of files we are allowed? $quantity++; $file_limit = !empty($modSettings['attachmentNumPerPostLimit']) && $modSettings['shd_attachments_mode'] != 'ticket' ? $modSettings['attachmentNumPerPostLimit'] : $quantity + 1; if ($quantity > $file_limit) { checkSubmitOnce('free'); fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit'])); } // Check the total upload size for this post... $total_size += $uplfile['size']; $size_limit = !empty($modSettings['attachmentPostLimit']) && $modSettings['shd_attachments_mode'] != 'ticket' ? $modSettings['attachmentPostLimit'] * 1024 : $total_size + 1024; if ($total_size > $size_limit) { checkSubmitOnce('free'); fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit'])); } $attachmentOptions = array('post' => 0, 'poster' => $user_info['id'], 'name' => $uplfile['name'], 'tmp_name' => $uplfile['tmp_name'], 'size' => $uplfile['size'], 'id_folder' => $modSettings['currentAttachmentUploadDir']); if (createAttachment($attachmentOptions)) { $attachIDs[] = $attachmentOptions['id']; if (!empty($attachmentOptions['thumb'])) { $attachIDs[] = $attachmentOptions['thumb']; } $context['log_params']['att_added'][] = htmlspecialchars($attachmentOptions['name']); } else { if (in_array('could_not_upload', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('attach_timeout', 'critical'); } if (in_array('too_large', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit'])); } if (in_array('bad_extension', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . strtr($modSettings['attachmentExtensions'], array(',' => ', ')) . '.', false); } if (in_array('directory_full', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('ran_out_of_space', 'critical'); } if (in_array('bad_filename', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical'); } if (in_array('taken_filename', $attachmentOptions['errors'])) { checkSubmitOnce('free'); fatal_lang_error('filename_exists'); } } } } return $attachIDs; }
/** * Delete one or more members. * * What it does: * - Requires profile_remove_own or profile_remove_any permission for * respectively removing your own account or any account. * - Non-admins cannot delete admins. * * The function: * - changes author of messages, topics and polls to guest authors. * - removes all log entries concerning the deleted members, except the * error logs, ban logs and moderation logs. * - removes these members' personal messages (only the inbox) * - rmoves avatars, ban entries, theme settings, moderator positions, poll votes, * drafts, likes, mentions, notifications * - removes custom field data associated with them * - updates member statistics afterwards. * * @package Members * @param int[]|int $users * @param bool $check_not_admin = false */ function deleteMembers($users, $check_not_admin = false) { global $modSettings, $user_info; $db = database(); // Try give us a while to sort this out... @set_time_limit(600); // Try to get some more memory. setMemoryLimit('128M'); // If it's not an array, make it so! if (!is_array($users)) { $users = array($users); } else { $users = array_unique($users); } // Make sure there's no void user in here. $users = array_diff($users, array(0)); // How many are they deleting? if (empty($users)) { return; } elseif (count($users) == 1) { list($user) = $users; if ($user == $user_info['id']) { isAllowedTo('profile_remove_own'); } else { isAllowedTo('profile_remove_any'); } } else { foreach ($users as $k => $v) { $users[$k] = (int) $v; } // Deleting more than one? You can't have more than one account... isAllowedTo('profile_remove_any'); } // Get their names for logging purposes. $request = $db->query('', ' SELECT id_member, member_name, email_address, CASE WHEN id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0 THEN 1 ELSE 0 END AS is_admin FROM {db_prefix}members WHERE id_member IN ({array_int:user_list}) LIMIT ' . count($users), array('user_list' => $users, 'admin_group' => 1)); $admins = array(); $emails = array(); $user_log_details = array(); while ($row = $db->fetch_assoc($request)) { if ($row['is_admin']) { $admins[] = $row['id_member']; } $user_log_details[$row['id_member']] = array($row['id_member'], $row['member_name']); $emails[] = $row['email_address']; } $db->free_result($request); if (empty($user_log_details)) { return; } // Make sure they aren't trying to delete administrators if they aren't one. But don't bother checking if it's just themself. if (!empty($admins) && ($check_not_admin || !allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $user_info['id']))) { $users = array_diff($users, $admins); foreach ($admins as $id) { unset($user_log_details[$id]); } } // No one left? if (empty($users)) { return; } // Log the action - regardless of who is deleting it. $log_changes = array(); foreach ($user_log_details as $user) { $log_changes[] = array('action' => 'delete_member', 'log_type' => 'admin', 'extra' => array('member' => $user[0], 'name' => $user[1], 'member_acted' => $user_info['name'])); // Remove any cached data if enabled. if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) { cache_put_data('user_settings-' . $user[0], null, 60); } } // Make these peoples' posts guest posts. $db->query('', ' UPDATE {db_prefix}messages SET id_member = {int:guest_id}' . (!empty($modSettings['deleteMembersRemovesEmail']) ? ', poster_email = {string:blank_email}' : '') . ' WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'blank_email' => '', 'users' => $users)); $db->query('', ' UPDATE {db_prefix}polls SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Make these peoples' posts guest first posts and last posts. $db->query('', ' UPDATE {db_prefix}topics SET id_member_started = {int:guest_id} WHERE id_member_started IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); $db->query('', ' UPDATE {db_prefix}topics SET id_member_updated = {int:guest_id} WHERE id_member_updated IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); $db->query('', ' UPDATE {db_prefix}log_actions SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); $db->query('', ' UPDATE {db_prefix}log_banned SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); $db->query('', ' UPDATE {db_prefix}log_errors SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Delete the member. $db->query('', ' DELETE FROM {db_prefix}members WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete any drafts... $db->query('', ' DELETE FROM {db_prefix}user_drafts WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete any likes... $db->query('', ' DELETE FROM {db_prefix}message_likes WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete any custom field data... $db->query('', ' DELETE FROM {db_prefix}custom_fields_data WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete any post by email keys... $db->query('', ' DELETE FROM {db_prefix}postby_emails WHERE email_to IN ({array_string:emails})', array('emails' => $emails)); // Delete the logs... $db->query('', ' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:log_type} AND id_member IN ({array_int:users})', array('log_type' => 2, 'users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_boards WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_comments WHERE id_recipient IN ({array_int:users}) AND comment_type = {string:warntpl}', array('users' => $users, 'warntpl' => 'warntpl')); $db->query('', ' DELETE FROM {db_prefix}log_group_requests WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_karma WHERE id_target IN ({array_int:users}) OR id_executor IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_mark_read WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_notify WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_online WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_subscribed WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}log_topics WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}collapsed_categories WHERE id_member IN ({array_int:users})', array('users' => $users)); // Make their votes appear as guest votes - at least it keeps the totals right. // @todo Consider adding back in cookie protection. $db->query('', ' UPDATE {db_prefix}log_polls SET id_member = {int:guest_id} WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // Remove the mentions $db->query('', ' DELETE FROM {db_prefix}log_mentions WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete personal messages. require_once SUBSDIR . '/PersonalMessage.subs.php'; deleteMessages(null, null, $users); $db->query('', ' UPDATE {db_prefix}personal_messages SET id_member_from = {int:guest_id} WHERE id_member_from IN ({array_int:users})', array('guest_id' => 0, 'users' => $users)); // They no longer exist, so we don't know who it was sent to. $db->query('', ' DELETE FROM {db_prefix}pm_recipients WHERE id_member IN ({array_int:users})', array('users' => $users)); // Delete avatar. require_once SUBSDIR . '/ManageAttachments.subs.php'; removeAttachments(array('id_member' => $users)); // It's over, no more moderation for you. $db->query('', ' DELETE FROM {db_prefix}moderators WHERE id_member IN ({array_int:users})', array('users' => $users)); $db->query('', ' DELETE FROM {db_prefix}group_moderators WHERE id_member IN ({array_int:users})', array('users' => $users)); // If you don't exist we can't ban you. $db->query('', ' DELETE FROM {db_prefix}ban_items WHERE id_member IN ({array_int:users})', array('users' => $users)); // Remove individual theme settings. $db->query('', ' DELETE FROM {db_prefix}themes WHERE id_member IN ({array_int:users})', array('users' => $users)); // These users are nobody's buddy nomore. $request = $db->query('', ' SELECT id_member, pm_ignore_list, buddy_list FROM {db_prefix}members WHERE FIND_IN_SET({raw:pm_ignore_list}, pm_ignore_list) != 0 OR FIND_IN_SET({raw:buddy_list}, buddy_list) != 0', array('pm_ignore_list' => implode(', pm_ignore_list) != 0 OR FIND_IN_SET(', $users), 'buddy_list' => implode(', buddy_list) != 0 OR FIND_IN_SET(', $users))); while ($row = $db->fetch_assoc($request)) { updateMemberData($row['id_member'], array('pm_ignore_list' => implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)), 'buddy_list' => implode(',', array_diff(explode(',', $row['buddy_list']), $users)))); } $db->free_result($request); // Make sure no member's birthday is still sticking in the calendar... updateSettings(array('calendar_updated' => time())); // Integration rocks! call_integration_hook('integrate_delete_members', array($users)); updateMemberStats(); logActions($log_changes); }
function UnapprovedAttachments() { global $txt, $scripturl, $context, $user_info, $sourcedir, $smcFunc; $context['page_title'] = $txt['mc_unapproved_attachments']; // Once again, permissions are king! $approve_boards = boardsAllowedTo('approve_posts'); if ($approve_boards == array(0)) { $approve_query = ''; } elseif (!empty($approve_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')'; } else { $approve_query = ' AND 0'; } // Get together the array of things to act on, if any. $attachments = array(); if (isset($_GET['approve'])) { $attachments[] = (int) $_GET['approve']; } elseif (isset($_GET['delete'])) { $attachments[] = (int) $_GET['delete']; } elseif (isset($_POST['item'])) { foreach ($_POST['item'] as $item) { $attachments[] = (int) $item; } } // Are we approving or deleting? if (isset($_GET['approve']) || isset($_POST['do']) && $_POST['do'] == 'approve') { $curAction = 'approve'; } elseif (isset($_GET['delete']) || isset($_POST['do']) && $_POST['do'] == 'delete') { $curAction = 'delete'; } // Something to do, let's do it! if (!empty($attachments) && isset($curAction)) { checkSession('request'); // This will be handy. require_once $sourcedir . '/ManageAttachments.php'; // Confirm the attachments are eligible for changing! $request = $smcFunc['db_query']('', ' SELECT a.id_attach FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) LEFT JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board) WHERE a.id_attach IN ({array_int:attachments}) AND a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('attachments' => $attachments, 'not_approved' => 0, 'attachment_type' => 0)); $attachments = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $attachments[] = $row['id_attach']; } $smcFunc['db_free_result']($request); // Assuming it wasn't all like, proper illegal, we can do the approving. if (!empty($attachments)) { if ($curAction == 'approve') { ApproveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments)); } } } // How many unapproved attachments in total? $request = $smcFunc['db_query']('', ' SELECT COUNT(*) FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('not_approved' => 0, 'attachment_type' => 0)); list($context['total_unapproved_attachments']) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); $context['page_index'] = constructPageIndex($scripturl . '?action=moderate;area=attachmod;sa=attachments', $_GET['start'], $context['total_unapproved_attachments'], 10); $context['start'] = $_GET['start']; // Get all unapproved attachments. $request = $smcFunc['db_query']('', ' SELECT a.id_attach, a.filename, a.size, m.id_msg, m.id_topic, m.id_board, m.subject, m.body, m.id_member, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, t.id_member_started, t.id_first_msg, b.name AS board_name, c.id_cat, c.name AS cat_name FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query . ' LIMIT ' . $context['start'] . ', 10', array('not_approved' => 0, 'attachment_type' => 0)); $context['unapproved_items'] = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $context['unapproved_items'][] = array('id' => $row['id_attach'], 'filename' => $row['filename'], 'size' => round($row['size'] / 1024, 2), 'time' => timeformat($row['poster_time']), 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' : $row['poster_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member']), 'message' => array('id' => $row['id_msg'], 'subject' => $row['subject'], 'body' => parse_bbc($row['body']), 'time' => timeformat($row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), 'topic' => array('id' => $row['id_topic']), 'board' => array('id' => $row['id_board'], 'name' => $row['board_name']), 'category' => array('id' => $row['id_cat'], 'name' => $row['cat_name'])); } $smcFunc['db_free_result']($request); $context['sub_template'] = 'unapproved_attachments'; }
function avatar_save($memID, &$profile_vars, &$cur_profile) { // Remove any attached avatar... removeAttachments(array('id_member' => $memID)); $profile_vars['avatar'] = $_POST['attachment']; // if ($profile_vars['avatar'] == 'http://' || $profile_vars['avatar'] == 'http:///') // $profile_vars['avatar'] = ''; // Trying to make us do something we'll regret? // var_dump($profile_vars['avatar']);die; if (!is_numeric($profile_vars['avatar'])) { return 'bad_avatar'; } // Should we check dimensions? // 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 $this->sourcedir . '/Subs-Graphics.php'; $tea_avatar_size = !empty($this->modSettings['tea_avatar_size']) ? $this->modSettings['tea_avatar_size'] : 64; if (downloadAvatar('http://image.eveonline.com/Character/' . $profile_vars['avatar'] . '_' . $tea_avatar_size . '.jpg', $memID, $tea_avatar_size, $tea_avatar_size)) { $profile_vars['avatar'] = ''; $cur_profile['id_attach'] = $this->modSettings['new_avatar_data']['id']; $cur_profile['filename'] = $this->modSettings['new_avatar_data']['filename']; $cur_profile['attachment_type'] = $this->modSettings['new_avatar_data']['type']; } // } // } // } }
/** * Removes the passed id_topic's. * Permissions are NOT checked here because the function is used in a scheduled task * * @param int[]|int $topics The topics to remove (can be an id or an array of ids). * @param bool $decreasePostCount if true users' post count will be reduced * @param bool $ignoreRecycling if true topics are not moved to the recycle board (if it exists). */ function removeTopics($topics, $decreasePostCount = true, $ignoreRecycling = false) { global $modSettings; $db = database(); // Nothing to do? if (empty($topics)) { return; } // Only a single topic. if (is_numeric($topics)) { $topics = array($topics); } // Decrease the post counts for members. if ($decreasePostCount) { $requestMembers = $db->query('', ' SELECT m.id_member, COUNT(*) AS posts FROM {db_prefix}messages AS m INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE m.id_topic IN ({array_int:topics}) AND m.icon != {string:recycled} AND b.count_posts = {int:do_count_posts} AND m.approved = {int:is_approved} GROUP BY m.id_member', array('do_count_posts' => 0, 'recycled' => 'recycled', 'topics' => $topics, 'is_approved' => 1)); if ($db->num_rows($requestMembers) > 0) { while ($rowMembers = $db->fetch_assoc($requestMembers)) { updateMemberData($rowMembers['id_member'], array('posts' => 'posts - ' . $rowMembers['posts'])); } } $db->free_result($requestMembers); } // Recycle topics that aren't in the recycle board... if (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 && !$ignoreRecycling) { $request = $db->query('', ' SELECT id_topic, id_board, unapproved_posts, approved FROM {db_prefix}topics WHERE id_topic IN ({array_int:topics}) AND id_board != {int:recycle_board} LIMIT ' . count($topics), array('recycle_board' => $modSettings['recycle_board'], 'topics' => $topics)); if ($db->num_rows($request) > 0) { // Get topics that will be recycled. $recycleTopics = array(); while ($row = $db->fetch_assoc($request)) { if (function_exists('apache_reset_timeout')) { @apache_reset_timeout(); } $recycleTopics[] = $row['id_topic']; // Set the id_previous_board for this topic - and make it not sticky. $db->query('', ' UPDATE {db_prefix}topics SET id_previous_board = {int:id_previous_board}, is_sticky = {int:not_sticky} WHERE id_topic = {int:id_topic}', array('id_previous_board' => $row['id_board'], 'id_topic' => $row['id_topic'], 'not_sticky' => 0)); } $db->free_result($request); // Mark recycled topics as recycled. $db->query('', ' UPDATE {db_prefix}messages SET icon = {string:recycled} WHERE id_topic IN ({array_int:recycle_topics})', array('recycle_topics' => $recycleTopics, 'recycled' => 'recycled')); // Move the topics to the recycle board. require_once SUBSDIR . '/Topic.subs.php'; moveTopics($recycleTopics, $modSettings['recycle_board']); // Close reports that are being recycled. require_once SUBSDIR . '/Moderation.subs.php'; $db->query('', ' UPDATE {db_prefix}log_reported SET closed = {int:is_closed} WHERE id_topic IN ({array_int:recycle_topics})', array('recycle_topics' => $recycleTopics, 'is_closed' => 1)); updateSettings(array('last_mod_report_action' => time())); recountOpenReports(); // Topics that were recycled don't need to be deleted, so subtract them. $topics = array_diff($topics, $recycleTopics); } else { $db->free_result($request); } } // Still topics left to delete? if (empty($topics)) { return; } $adjustBoards = array(); // Find out how many posts we are deleting. $request = $db->query('', ' SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts, SUM(num_replies) AS num_replies FROM {db_prefix}topics WHERE id_topic IN ({array_int:topics}) GROUP BY id_board, approved', array('topics' => $topics)); while ($row = $db->fetch_assoc($request)) { if (!isset($adjustBoards[$row['id_board']]['num_posts'])) { cache_put_data('board-' . $row['id_board'], null, 120); $adjustBoards[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0, 'id_board' => $row['id_board']); } // Posts = (num_replies + 1) for each approved topic. $adjustBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0); $adjustBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; // Add the topics to the right type. if ($row['approved']) { $adjustBoards[$row['id_board']]['num_topics'] += $row['num_topics']; } else { $adjustBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics']; } } $db->free_result($request); // Decrease number of posts and topics for each board. foreach ($adjustBoards as $stats) { if (function_exists('apache_reset_timeout')) { @apache_reset_timeout(); } $db->query('', ' UPDATE {db_prefix}boards SET num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END, num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END, unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END, unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END WHERE id_board = {int:id_board}', array('id_board' => $stats['id_board'], 'num_posts' => $stats['num_posts'], 'num_topics' => $stats['num_topics'], 'unapproved_posts' => $stats['unapproved_posts'], 'unapproved_topics' => $stats['unapproved_topics'])); } // Remove polls for these topics. $request = $db->query('', ' SELECT id_poll FROM {db_prefix}topics WHERE id_topic IN ({array_int:topics}) AND id_poll > {int:no_poll} LIMIT ' . count($topics), array('no_poll' => 0, 'topics' => $topics)); $polls = array(); while ($row = $db->fetch_assoc($request)) { $polls[] = $row['id_poll']; } $db->free_result($request); if (!empty($polls)) { $db->query('', ' DELETE FROM {db_prefix}polls WHERE id_poll IN ({array_int:polls})', array('polls' => $polls)); $db->query('', ' DELETE FROM {db_prefix}poll_choices WHERE id_poll IN ({array_int:polls})', array('polls' => $polls)); $db->query('', ' DELETE FROM {db_prefix}log_polls WHERE id_poll IN ({array_int:polls})', array('polls' => $polls)); } // Get rid of the attachment(s). require_once SUBSDIR . '/ManageAttachments.subs.php'; $attachmentQuery = array('attachment_type' => 0, 'id_topic' => $topics); removeAttachments($attachmentQuery, 'messages'); // Delete search index entries. if (!empty($modSettings['search_custom_index_config'])) { $customIndexSettings = unserialize($modSettings['search_custom_index_config']); $request = $db->query('', ' SELECT id_msg, body FROM {db_prefix}messages WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); $words = array(); $messages = array(); while ($row = $db->fetch_assoc($request)) { if (function_exists('apache_reset_timeout')) { @apache_reset_timeout(); } $words = array_merge($words, text2words($row['body'], $customIndexSettings['bytes_per_word'], true)); $messages[] = $row['id_msg']; } $db->free_result($request); $words = array_unique($words); if (!empty($words) && !empty($messages)) { $db->query('', ' DELETE FROM {db_prefix}log_search_words WHERE id_word IN ({array_int:word_list}) AND id_msg IN ({array_int:message_list})', array('word_list' => $words, 'message_list' => $messages)); } } // Reuse the message array if available if (empty($messages)) { $messages = messagesInTopics($topics); } // If there are messages left in this topic if (!empty($messages)) { // Remove all likes now that the topic is gone $db->query('', ' DELETE FROM {db_prefix}message_likes WHERE id_msg IN ({array_int:messages})', array('messages' => $messages)); // Remove all mentions now that the topic is gone $db->query('', ' DELETE FROM {db_prefix}log_mentions WHERE id_msg IN ({array_int:messages})', array('messages' => $messages)); } // Delete messages in each topic. $db->query('', ' DELETE FROM {db_prefix}messages WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); // Remove linked calendar events. // @todo if unlinked events are enabled, wouldn't this be expected to keep them? $db->query('', ' DELETE FROM {db_prefix}calendar WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); // Delete log_topics data $db->query('', ' DELETE FROM {db_prefix}log_topics WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); // Delete notifications $db->query('', ' DELETE FROM {db_prefix}log_notify WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); // Delete the topics themselves $db->query('', ' DELETE FROM {db_prefix}topics WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); // Remove data from the subjects for search cache $db->query('', ' DELETE FROM {db_prefix}log_search_subjects WHERE id_topic IN ({array_int:topics})', array('topics' => $topics)); require_once SUBSDIR . '/FollowUps.subs.php'; removeFollowUpsByTopic($topics); foreach ($topics as $topic_id) { cache_put_data('topic_board-' . $topic_id, null, 120); } // Maybe there's an addon that wants to delete topic related data of its own call_integration_hook('integrate_remove_topics', array($topics)); // Update the totals... updateStats('message'); updateTopicStats(); updateSettings(array('calendar_updated' => time())); require_once SUBSDIR . '/Post.subs.php'; $updates = array(); foreach ($adjustBoards as $stats) { $updates[] = $stats['id_board']; } updateLastMessages($updates); }
/** * Removes all attachments in a single click * * - Called from the maintenance screen by ?action=admin;area=manageattachments;sa=removeall. */ public function action_removeall() { global $txt; checkSession('get', 'admin'); // lots of work to do require_once SUBSDIR . '/ManageAttachments.subs.php'; $messages = removeAttachments(array('attachment_type' => 0), '', true); $notice = isset($_POST['notice']) ? $_POST['notice'] : $txt['attachment_delete_admin']; // Add the notice on the end of the changed messages. if (!empty($messages)) { setRemovalNotice($messages, $notice); } redirectexit('action=admin;area=manageattachments;sa=maintenance'); }
function RemoveAllAttachments() { global $db_prefix, $txt; checkSession('get', 'manageattachments'); $messages = removeAttachments('a.attachmentType = 0', '', true); if (!isset($_POST['notice'])) { $_POST['notice'] = $txt['smf216']; } // Add the notice on the end of the changed messages. if (!empty($messages)) { db_query("\n\t\t\tUPDATE {$db_prefix}messages\n\t\t\tSET body = CONCAT(body, '<br /><br />{$_POST['notice']}')\n\t\t\tWHERE ID_MSG IN (" . implode(',', $messages) . ")\n\t\t\tLIMIT " . count($messages), __FILE__, __LINE__); } redirectexit('action=manageattachments;sa=maintenance'); }
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; } }
function Post2() { global $board, $topic, $txt, $db_prefix, $modSettings, $sourcedir, $context; global $ID_MEMBER, $user_info, $board_info, $options, $func; // Previewing? Go back to start. if (isset($_REQUEST['preview'])) { return Post(); } // Prevent double submission of this form. checkSubmitOnce('check'); // No errors as yet. $post_errors = array(); // If the session has timed out, let the user re-submit their form. if (checkSession('post', '', false) != '') { $post_errors[] = 'session_timeout'; } require_once $sourcedir . '/Subs-Post.php'; loadLanguage('Post'); // Replying to a topic? if (!empty($topic) && !isset($_REQUEST['msg'])) { $request = db_query("\n\t\t\tSELECT t.locked, t.isSticky, t.ID_POLL, t.numReplies, m.ID_MEMBER\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS m)\n\t\t\tWHERE t.ID_TOPIC = {$topic}\n\t\t\t\tAND m.ID_MSG = t.ID_FIRST_MSG\n\t\t\tLIMIT 1", __FILE__, __LINE__); list($tmplocked, $tmpstickied, $pollID, $numReplies, $ID_MEMBER_POSTER) = mysql_fetch_row($request); mysql_free_result($request); // Don't allow a post if it's locked. if ($tmplocked != 0 && !allowedTo('moderate_board')) { fatal_lang_error(90, false); } // Sorry, multiple polls aren't allowed... yet. You should stop giving me ideas :P. if (isset($_REQUEST['poll']) && $pollID > 0) { unset($_REQUEST['poll']); } if ($ID_MEMBER_POSTER != $ID_MEMBER) { isAllowedTo('post_reply_any'); } elseif (!allowedTo('post_reply_any')) { isAllowedTo('post_reply_own'); } if (isset($_POST['lock'])) { // Nothing is changed to the lock. if (empty($tmplocked) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($tmplocked)) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $ID_MEMBER != $ID_MEMBER_POSTER) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You cannot override a moderator lock. if ($tmplocked == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // So you wanna (un)sticky this...let's see. if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $tmpstickied || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error. $newReplies = isset($_POST['num_replies']) && $numReplies > $_POST['num_replies'] ? $numReplies - $_POST['num_replies'] : 0; if (empty($options['no_new_reply_warning']) && !empty($newReplies)) { $_REQUEST['preview'] = true; return Post(); } $posterIsGuest = $user_info['is_guest']; } elseif (empty($topic)) { if (!isset($_REQUEST['poll']) || $modSettings['pollMode'] != '1') { isAllowedTo('post_new'); } if (isset($_POST['lock'])) { // New topics are by default not locked. if (empty($_POST['lock'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own'))) { unset($_POST['lock']); } else { $_POST['lock'] = allowedTo('lock_any') ? 1 : 2; } } if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) { unset($_POST['sticky']); } $posterIsGuest = $user_info['is_guest']; } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; $request = db_query("\n\t\t\tSELECT\n\t\t\t\tm.ID_MEMBER, m.posterName, m.posterEmail, m.posterTime, \n\t\t\t\tt.ID_FIRST_MSG, t.locked, t.isSticky, t.ID_MEMBER_STARTED AS ID_MEMBER_POSTER\n\t\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t)\n\t\t\tWHERE m.ID_MSG = {$_REQUEST['msg']}\n\t\t\t\tAND t.ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__); if (mysql_num_rows($request) == 0) { fatal_lang_error('smf272', false); } $row = mysql_fetch_assoc($request); mysql_free_result($request); if (!empty($row['locked']) && !allowedTo('moderate_board')) { fatal_lang_error(90, false); } if (isset($_POST['lock'])) { // Nothing changes to the lock status. if (empty($_POST['lock']) && empty($row['locked']) || !empty($_POST['lock']) && !empty($row['locked'])) { unset($_POST['lock']); } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $ID_MEMBER != $row['ID_MEMBER_POSTER']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { // You're not allowed to break a moderator's lock. if ($row['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } // Change the sticky status of this topic? if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $row['isSticky'])) { unset($_POST['sticky']); } if ($row['ID_MEMBER'] == $ID_MEMBER && !allowedTo('modify_any')) { 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'); // If you're modifying a reply, I say it better be logged... $moderationAction = true; } else { isAllowedTo('modify_any'); // Log it, assuming you're not modifying your own post. if ($row['ID_MEMBER'] != $ID_MEMBER) { $moderationAction = true; } } $posterIsGuest = empty($row['ID_MEMBER']); if (!allowedTo('moderate_forum') || !$posterIsGuest) { $_POST['guestname'] = addslashes($row['posterName']); $_POST['email'] = addslashes($row['posterEmail']); } } // If the poster is a guest evaluate the legality of name and email. if ($posterIsGuest) { $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']); $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']); if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') { $post_errors[] = 'no_name'; } if ($func['strlen']($_POST['guestname']) > 25) { $post_errors[] = 'long_name'; } if (empty($modSettings['guest_post_no_email'])) { // Only check if they changed it! if (!isset($row) || $row['posterEmail'] != $_POST['email']) { if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == '')) { $post_errors[] = 'no_email'; } if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', stripslashes($_POST['email'])) == 0) { $post_errors[] = 'bad_email'; } } // Now make sure this email address is not banned from posting. isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt[28])); } } // Check the subject and message. if (!isset($_POST['subject']) || $func['htmltrim']($_POST['subject']) === '') { $post_errors[] = 'no_subject'; } if (!isset($_POST['message']) || $func['htmltrim']($_POST['message']) === '') { $post_errors[] = 'no_message'; } elseif (!empty($modSettings['max_messageLength']) && $func['strlen']($_POST['message']) > $modSettings['max_messageLength']) { $post_errors[] = 'long_message'; } else { // Prepare the message a bit for some additional testing. $_POST['message'] = $func['htmlspecialchars']($_POST['message'], ENT_QUOTES); // Preparse code. (Zef) if ($user_info['is_guest']) { $user_info['name'] = $_POST['guestname']; } preparsecode($_POST['message']); // Let's see if there's still some content left without the tags. if ($func['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') { $post_errors[] = 'no_message'; } } if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $func['htmltrim']($_POST['evtitle']) === '') { $post_errors[] = 'no_event'; } // You are not! if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin']) { fatal_error('Knave! Masquerader! Charlatan!', false); } // Validate the poll... if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') { if (!empty($topic) && !isset($_REQUEST['msg'])) { fatal_lang_error(1, false); } // This is a new topic... so it's a new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($ID_MEMBER == $row['ID_MEMBER_POSTER'] && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } if (!isset($_POST['question']) || trim($_POST['question']) == '') { $post_errors[] = 'no_question'; } $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']); // Get rid of empty ones. foreach ($_POST['options'] as $k => $option) { if ($option == '') { unset($_POST['options'][$k], $_POST['options'][$k]); } } // What are you going to vote between with one choice?!? if (count($_POST['options']) < 2) { $post_errors[] = 'poll_few'; } } if ($posterIsGuest) { // If user is a guest, make sure the chosen name isn't taken. require_once $sourcedir . '/Subs-Members.php'; if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['posterName']) || $_POST['guestname'] != $row['posterName'])) { $post_errors[] = 'bad_name'; } } elseif (!isset($_REQUEST['msg'])) { $_POST['guestname'] = addslashes($user_info['username']); $_POST['email'] = addslashes($user_info['email']); } // Any mistakes? if (!empty($post_errors)) { loadLanguage('Errors'); // Previewing. $_REQUEST['preview'] = true; $context['post_error'] = array('messages' => array()); foreach ($post_errors as $post_error) { $context['post_error'][$post_error] = true; $context['post_error']['messages'][] = $txt['error_' . $post_error]; } return Post(); } // Make sure the user isn't spamming the board. if (!isset($_REQUEST['msg'])) { spamProtection('spam'); } // At about this point, we're posting and that's that. ignore_user_abort(true); @set_time_limit(300); // Add special html entities to the subject, name, and email. $_POST['subject'] = strtr($func['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $_POST['guestname'] = htmlspecialchars($_POST['guestname']); $_POST['email'] = htmlspecialchars($_POST['email']); // At this point, we want to make sure the subject isn't too long. if ($func['strlen']($_POST['subject']) > 100) { $_POST['subject'] = addslashes($func['substr'](stripslashes($_POST['subject']), 0, 100)); } // Make the poll... if (isset($_REQUEST['poll'])) { // Make sure that the user has not entered a ridiculous number of options.. if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) { $_POST['poll_max_votes'] = 1; } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) { $_POST['poll_max_votes'] = count($_POST['options']); } else { $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes']; } // Just set it to zero if it's not there.. if (!isset($_POST['poll_hide'])) { $_POST['poll_hide'] = 0; } else { $_POST['poll_hide'] = (int) $_POST['poll_hide']; } $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0; // If the user tries to set the poll too far in advance, don't let them. if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) { fatal_lang_error('poll_range_error', false); } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) { $_POST['poll_hide'] = 1; } // Clean up the question and answers. $_POST['question'] = $func['htmlspecialchars']($_POST['question']); $_POST['options'] = htmlspecialchars__recursive($_POST['options']); } // Check if they are trying to delete any current attachments.... if (isset($_REQUEST['msg'], $_POST['attach_del']) && allowedTo('post_attachment')) { $del_temp = array(); foreach ($_POST['attach_del'] as $i => $dummy) { $del_temp[$i] = (int) $dummy; } require_once $sourcedir . '/ManageAttachments.php'; removeAttachments('a.attachmentType = 0 AND a.ID_MSG = ' . (int) $_REQUEST['msg'] . ' AND a.ID_ATTACH NOT IN (' . implode(', ', $del_temp) . ')'); } // ...or attach a new file... if (isset($_FILES['attachment']['name']) || !empty($_SESSION['temp_attachments'])) { isAllowedTo('post_attachment'); // 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; } if (!empty($_SESSION['temp_attachments'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $name) { if (preg_match('~^post_tmp_' . $ID_MEMBER . '_\\d+$~', $attachID) == 0) { continue; } if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) { unset($_SESSION['temp_attachments'][$attachID]); @unlink($modSettings['attachmentUploadDir'] . '/' . $attachID); continue; } $_FILES['attachment']['tmp_name'][] = $attachID; $_FILES['attachment']['name'][] = addslashes($name); $_FILES['attachment']['size'][] = filesize($modSettings['attachmentUploadDir'] . '/' . $attachID); list($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($modSettings['attachmentUploadDir'] . '/' . $attachID); unset($_SESSION['temp_attachments'][$attachID]); } } if (!isset($_FILES['attachment']['name'])) { $_FILES['attachment']['tmp_name'] = array(); } $attachIDs = array(); foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) { if ($_FILES['attachment']['name'][$n] == '') { continue; } // Have we reached the maximum number of files we are allowed? $quantity++; if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) { fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit'])); } // Check the total upload size for this post... $total_size += $_FILES['attachment']['size'][$n]; if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) { fatal_lang_error('smf122', false, array($modSettings['attachmentPostLimit'])); } $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $ID_MEMBER, 'name' => $_FILES['attachment']['name'][$n], 'tmp_name' => $_FILES['attachment']['tmp_name'][$n], 'size' => $_FILES['attachment']['size'][$n]); if (createAttachment($attachmentOptions)) { $attachIDs[] = $attachmentOptions['id']; if (!empty($attachmentOptions['thumb'])) { $attachIDs[] = $attachmentOptions['thumb']; } } else { if (in_array('could_not_upload', $attachmentOptions['errors'])) { fatal_lang_error('smf124'); } if (in_array('too_large', $attachmentOptions['errors'])) { fatal_lang_error('smf122', false, array($modSettings['attachmentSizeLimit'])); } if (in_array('bad_extension', $attachmentOptions['errors'])) { fatal_error($attachmentOptions['name'] . '.<br />' . $txt['smf123'] . ' ' . $modSettings['attachmentExtensions'] . '.', false); } if (in_array('directory_full', $attachmentOptions['errors'])) { fatal_lang_error('smf126'); } if (in_array('bad_filename', $attachmentOptions['errors'])) { fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['smf130b'] . '.'); } if (in_array('taken_filename', $attachmentOptions['errors'])) { fatal_lang_error('smf125'); } } } } // Make the poll... if (isset($_REQUEST['poll'])) { // Create the poll. db_query("\n\t\t\tINSERT INTO {$db_prefix}polls\n\t\t\t\t(question, hideResults, maxVotes, expireTime, ID_MEMBER, posterName, changeVote)\n\t\t\tVALUES (SUBSTRING('{$_POST['question']}', 1, 255), {$_POST['poll_hide']}, {$_POST['poll_max_votes']},\n\t\t\t\t" . (empty($_POST['poll_expire']) ? '0' : time() + $_POST['poll_expire'] * 3600 * 24) . ", {$ID_MEMBER}, SUBSTRING('{$_POST['guestname']}', 1, 255), {$_POST['poll_change_vote']})", __FILE__, __LINE__); $ID_POLL = db_insert_id(); // Create each answer choice. $i = 0; $setString = ''; foreach ($_POST['options'] as $option) { $setString .= "\n\t\t\t\t\t({$ID_POLL}, {$i}, SUBSTRING('{$option}', 1, 255)),"; $i++; } db_query("\n\t\t\tINSERT INTO {$db_prefix}poll_choices\n\t\t\t\t(ID_POLL, ID_CHOICE, label)\n\t\t\tVALUES" . substr($setString, 0, -1), __FILE__, __LINE__); } else { $ID_POLL = 0; } // Creating a new topic? $newTopic = empty($_REQUEST['msg']) && empty($topic); // Collect all parameters for the creation or modification of a post. $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*\':"<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs); $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $ID_POLL : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true); $posterOptions = array('id' => $ID_MEMBER, 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']); // This is an already existing message. Edit it. if (!empty($_REQUEST['msg'])) { // Have admins allowed people to hide their screwups? if (time() - $row['posterTime'] > $modSettings['edit_wait_time'] || $ID_MEMBER != $row['ID_MEMBER']) { $msgOptions['modify_time'] = time(); $msgOptions['modify_name'] = addslashes($user_info['name']); } modifyPost($msgOptions, $topicOptions, $posterOptions); } else { createPost($msgOptions, $topicOptions, $posterOptions); if (isset($topicOptions['id'])) { $topic = $topicOptions['id']; } } // Editing or posting an event? if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) { require_once $sourcedir . '/Calendar.php'; calendarCanLink(); calendarInsertEvent($board, $topic, $_POST['evtitle'], $ID_MEMBER, $_POST['month'], $_POST['day'], $_POST['year'], isset($_POST['span']) ? $_POST['span'] : null); } elseif (isset($_POST['calendar'])) { $_REQUEST['eventid'] = (int) $_REQUEST['eventid']; // Validate the post... require_once $sourcedir . '/Subs-Post.php'; calendarValidatePost(); // If you're not allowed to edit any events, you have to be the poster. if (!allowedTo('calendar_edit_any')) { // Get the event's poster. $request = db_query("\n\t\t\t\tSELECT ID_MEMBER\n\t\t\t\tFROM {$db_prefix}calendar\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}", __FILE__, __LINE__); $row2 = mysql_fetch_assoc($request); mysql_free_result($request); // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...) isAllowedTo('calendar_edit_' . ($row2['ID_MEMBER'] == $ID_MEMBER ? 'own' : 'any')); } // Delete it? if (isset($_REQUEST['deleteevent'])) { db_query("\n\t\t\t\tDELETE FROM {$db_prefix}calendar\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); } else { $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0; $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']); db_query("\n\t\t\t\tUPDATE {$db_prefix}calendar\n\t\t\t\tSET endDate = '" . strftime('%Y-%m-%d', $start_time + $span * 86400) . "',\n\t\t\t\t\tstartDate = '" . strftime('%Y-%m-%d', $start_time) . "',\n\t\t\t\t\ttitle = '" . $func['htmlspecialchars']($_REQUEST['evtitle'], ENT_QUOTES) . "'\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); } updateStats('calendar'); } // Marking read should be done even for editing messages.... if (!$user_info['is_guest']) { // Mark all the parents read. (since you just posted and they will be unread.) if (!empty($board_info['parent_boards'])) { db_query("\n\t\t\t\tUPDATE {$db_prefix}log_boards\n\t\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND ID_BOARD IN (" . implode(',', array_keys($board_info['parent_boards'])) . ")", __FILE__, __LINE__); } } // Turn notification on or off. (note this just blows smoke if it's already on or off.) if (!empty($_POST['notify'])) { if (allowedTo('mark_any_notify')) { db_query("\n\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_notify\n\t\t\t\t\t(ID_MEMBER, ID_TOPIC, ID_BOARD)\n\t\t\t\tVALUES ({$ID_MEMBER}, {$topic}, 0)", __FILE__, __LINE__); } } elseif (!$newTopic) { db_query("\n\t\t\tDELETE FROM {$db_prefix}log_notify\n\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tAND ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__); } // Log an act of moderation - modifying. if (!empty($moderationAction)) { logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['ID_MEMBER'])); } if (isset($_POST['lock']) && $_POST['lock'] != 2) { logAction('lock', array('topic' => $topicOptions['id'])); } if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) { logAction('sticky', array('topic' => $topicOptions['id'])); } // Notify any members who have notification turned on for this topic. if ($newTopic) { notifyMembersBoard(); } elseif (empty($_REQUEST['msg'])) { sendNotifications($topic, 'reply'); } // Returning to the topic? if (!empty($_REQUEST['goback'])) { // Mark the board as read.... because it might get confusing otherwise. db_query("\n\t\t\tUPDATE {$db_prefix}log_boards\n\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tAND ID_BOARD = {$board}", __FILE__, __LINE__); } if (!empty($_POST['announce_topic'])) { redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback')); } if (!empty($_POST['move']) && allowedTo('move_any')) { redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback')); } // Return to post if the mod is on. if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], $context['browser']['is_ie']); } elseif (!empty($_REQUEST['goback'])) { redirectexit('topic=' . $topic . '.new#new', $context['browser']['is_ie']); } else { redirectexit('board=' . $board . '.0'); } }
function removeMessage($message, $decreasePostCount = true) { global $db_prefix, $board, $sourcedir, $modSettings, $ID_MEMBER, $user_info; if (empty($message) || !is_numeric($message)) { return false; } $request = db_query("\n\t\tSELECT\n\t\t\tm.ID_MEMBER, m.icon, m.posterTime, m.subject," . (empty($modSettings['search_custom_index_config']) ? '' : ' m.body,') . "\n\t\t\tt.ID_TOPIC, t.ID_FIRST_MSG, t.ID_LAST_MSG, t.numReplies, t.ID_BOARD,\n\t\t\tt.ID_MEMBER_STARTED AS ID_MEMBER_POSTER,\n\t\t\tb.countPosts\n\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\tWHERE m.ID_MSG = {$message}\n\t\t\tAND t.ID_TOPIC = m.ID_TOPIC\n\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\tLIMIT 1", __FILE__, __LINE__); if (mysql_num_rows($request) == 0) { return false; } $row = mysql_fetch_assoc($request); mysql_free_result($request); if (empty($board) || $row['ID_BOARD'] != $board) { $delete_any = boardsAllowedTo('delete_any'); if (!in_array(0, $delete_any) && !in_array($row['ID_BOARD'], $delete_any)) { $delete_own = boardsAllowedTo('delete_own'); $delete_own = in_array(0, $delete_own) || in_array($row['ID_BOARD'], $delete_own); $delete_replies = boardsAllowedTo('delete_replies'); $delete_replies = in_array(0, $delete_replies) || in_array($row['ID_BOARD'], $delete_replies); if ($row['ID_MEMBER'] == $ID_MEMBER) { if (!$delete_own) { if ($row['ID_MEMBER_POSTER'] == $ID_MEMBER) { if (!$delete_replies) { fatal_lang_error('cannot_delete_replies'); } } else { fatal_lang_error('cannot_delete_own'); } } elseif (($row['ID_MEMBER_POSTER'] != $ID_MEMBER || !$delete_replies) && !empty($modSettings['edit_disable_time']) && $row['posterTime'] + $modSettings['edit_disable_time'] * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER) { if (!$delete_replies) { fatal_lang_error('cannot_delete_replies'); } } else { fatal_lang_error('cannot_delete_any'); } } } else { // Check permissions to delete this message. if ($row['ID_MEMBER'] == $ID_MEMBER) { if (!allowedTo('delete_own')) { if ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('delete_any')) { isAllowedTo('delete_replies'); } elseif (!allowedTo('delete_any')) { isAllowedTo('delete_own'); } } elseif (!allowedTo('delete_any') && ($row['ID_MEMBER_POSTER'] != $ID_MEMBER || !allowedTo('delete_replies')) && !empty($modSettings['edit_disable_time']) && $row['posterTime'] + $modSettings['edit_disable_time'] * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('delete_any')) { isAllowedTo('delete_replies'); } else { isAllowedTo('delete_any'); } } // Delete the *whole* topic, but only if the topic consists of one message. if ($row['ID_FIRST_MSG'] == $message) { if (empty($board) || $row['ID_BOARD'] != $board) { $remove_any = boardsAllowedTo('remove_any'); $remove_any = in_array(0, $remove_any) || in_array($row['ID_BOARD'], $remove_any); if (!$remove_any) { $remove_own = boardsAllowedTo('remove_own'); $remove_own = in_array(0, $remove_own) || in_array($row['ID_BOARD'], $remove_own); } if ($row['ID_MEMBER'] != $ID_MEMBER && !$remove_any) { fatal_lang_error('cannot_remove_any'); } elseif (!$remove_any && !$remove_own) { fatal_lang_error('cannot_remove_own'); } } else { // Check permissions to delete a whole topic. if ($row['ID_MEMBER'] != $ID_MEMBER) { isAllowedTo('remove_any'); } elseif (!allowedTo('remove_any')) { isAllowedTo('remove_own'); } } // ...if there is only one post. if (!empty($row['numReplies'])) { fatal_lang_error('delFirstPost', false); } removeTopics($row['ID_TOPIC']); return true; } // Default recycle to false. $recycle = false; // If recycle topics has been set, make a copy of this message in the recycle board. // Make sure we're not recycling messages that are already on the recycle board. if (!empty($modSettings['recycle_enable']) && $row['ID_BOARD'] != $modSettings['recycle_board'] && $row['icon'] != 'recycled') { // Check if the recycle board exists and if so get the read status. $request = db_query("\n\t\t\tSELECT (IFNULL(lb.ID_MSG, 0) >= b.ID_MSG_UPDATED) AS isSeen\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\tLEFT JOIN {$db_prefix}log_boards AS lb ON (lb.ID_BOARD = b.ID_BOARD AND lb.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE b.ID_BOARD = {$modSettings['recycle_board']}", __FILE__, __LINE__); if (mysql_num_rows($request) == 0) { fatal_lang_error('recycle_no_valid_board'); } list($isRead) = mysql_fetch_row($request); mysql_free_result($request); // Insert a new topic in the recycle board. db_query("\n\t\t\tINSERT INTO {$db_prefix}topics\n\t\t\t\t(ID_BOARD, ID_MEMBER_STARTED, ID_MEMBER_UPDATED, ID_FIRST_MSG, ID_LAST_MSG)\n\t\t\tVALUES ({$modSettings['recycle_board']}, {$row['ID_MEMBER']}, {$row['ID_MEMBER']}, {$message}, {$message})", __FILE__, __LINE__); // Capture the ID of the new topic... $topicID = db_insert_id(); // If the topic creation went successful, move the message. if ($topicID > 0) { db_query("\n\t\t\t\tUPDATE {$db_prefix}messages\n\t\t\t\tSET \n\t\t\t\t\tID_TOPIC = {$topicID},\n\t\t\t\t\tID_BOARD = {$modSettings['recycle_board']},\n\t\t\t\t\ticon = 'recycled'\n\t\t\t\tWHERE ID_MSG = {$message}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); // Mark recycled topic as read. if (!$user_info['is_guest']) { db_query("\n\t\t\t\t\tREPLACE INTO {$db_prefix}log_topics\n\t\t\t\t\t\t(ID_TOPIC, ID_MEMBER, ID_MSG)\n\t\t\t\t\tVALUES ({$topicID}, {$ID_MEMBER}, {$modSettings['maxMsgID']})", __FILE__, __LINE__); } // Mark recycle board as seen, if it was marked as seen before. if (!empty($isRead) && !$user_info['is_guest']) { db_query("\n\t\t\t\t\tREPLACE INTO {$db_prefix}log_boards\n\t\t\t\t\t\t(ID_BOARD, ID_MEMBER, ID_MSG)\n\t\t\t\t\tVALUES ({$modSettings['recycle_board']}, {$ID_MEMBER}, {$modSettings['maxMsgID']})", __FILE__, __LINE__); } // Add one topic and post to the recycle bin board. db_query("\n\t\t\t\tUPDATE {$db_prefix}boards\n\t\t\t\tSET\n\t\t\t\t\tnumTopics = numTopics + 1,\n\t\t\t\t\tnumPosts = numPosts + 1\n\t\t\t\tWHERE ID_BOARD = {$modSettings['recycle_board']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__); // Make sure this message isn't getting deleted later on. $recycle = true; // Make sure we update the search subject index. updateStats('subject', $topicID, $row['subject']); } } // Deleting a recycled message can not lower anyone's post count. if ($row['icon'] == 'recycled') { $decreasePostCount = false; } // This is the last post, update the last post on the board. if ($row['ID_LAST_MSG'] == $message) { // Find the last message, set it, and decrease the post count. $request = db_query("\n\t\t\tSELECT ID_MSG, ID_MEMBER\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\t\tAND ID_MSG != {$message}\n\t\t\tORDER BY ID_MSG DESC\n\t\t\tLIMIT 1", __FILE__, __LINE__); $row2 = mysql_fetch_assoc($request); mysql_free_result($request); db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET\n\t\t\t\tID_LAST_MSG = {$row2['ID_MSG']},\n\t\t\t\tnumReplies = IF(numReplies = 0, 0, numReplies - 1),\n\t\t\t\tID_MEMBER_UPDATED = {$row2['ID_MEMBER']}\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\tLIMIT 1", __FILE__, __LINE__); } else { db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET numReplies = IF(numReplies = 0, 0, numReplies - 1)\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\tLIMIT 1", __FILE__, __LINE__); } db_query("\n\t\tUPDATE {$db_prefix}boards\n\t\tSET numPosts = IF(numPosts = 0, 0, numPosts - 1)\n\t\tWHERE ID_BOARD = {$row['ID_BOARD']}\n\t\tLIMIT 1", __FILE__, __LINE__); // If the poster was registered and the board this message was on incremented // the member's posts when it was posted, decrease his or her post count. if (!empty($row['ID_MEMBER']) && $decreasePostCount && empty($row['countPosts'])) { updateMemberData($row['ID_MEMBER'], array('posts' => '-')); } // Only remove posts if they're not recycled. if (!$recycle) { // Remove the message! db_query("\n\t\t\tDELETE FROM {$db_prefix}messages\n\t\t\tWHERE ID_MSG = {$message}\n\t\t\tLIMIT 1", __FILE__, __LINE__); if (!empty($modSettings['search_custom_index_config'])) { $customIndexSettings = unserialize($modSettings['search_custom_index_config']); $words = text2words($row['body'], $customIndexSettings['bytes_per_word'], true); if (!empty($words)) { db_query("\n\t\t\t\t\tDELETE FROM {$db_prefix}log_search_words\n\t\t\t\t\tWHERE ID_WORD IN (" . implode(', ', $words) . ")\n\t\t\t\t\t\tAND ID_MSG = {$message}", __FILE__, __LINE__); } } // Delete attachment(s) if they exist. require_once $sourcedir . '/ManageAttachments.php'; removeAttachments('a.attachmentType = 0 AND a.ID_MSG = ' . $message); } // Update the pesky statistics. updateStats('message'); updateStats('topic'); updateStats('calendar'); // And now to update the last message of each board we messed with. require_once $sourcedir . '/Subs-Post.php'; if ($recycle) { updateLastMessages(array($row['ID_BOARD'], $modSettings['recycle_board'])); } else { updateLastMessages($row['ID_BOARD']); } return false; }
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; }
/** * Receives the form for moving tickets to topics, and actually handles the move. * * After checking permissions, and so on, begin to actually move posts. * * This is done by invoking SMF's createPost function to make the new thread and repost all the ticket's posts as new thread posts * using defaults for some settings. * * Operations: * - check the user can see the board they are linking to * - move the ticket's text as the opening post * - update the ticket row if the post was modified before * - get the rest of the replies * - step through and post, updating for modified details * - send the notification PM if we're doing that * - update the attachments table * - update the action log * - remove the ticket from the DB * * @see shd_tickettotopic() * @since 1.0 */ function shd_tickettotopic2() { global $smcFunc, $context, $txt, $modSettings, $scripturl, $sourcedir; checkSession(); checkSubmitOnce('check'); if (empty($context['ticket_id'])) { fatal_lang_error('shd_no_ticket'); } if (isset($_POST['send_pm']) && (!isset($_POST['pm_content']) || trim($_POST['pm_content']) == '')) { checkSubmitOnce('free'); fatal_lang_error('shd_move_no_pm', false); } // Just in case, are they cancelling? if (isset($_REQUEST['cancel'])) { redirectexit('action=helpdesk;sa=ticket;ticket=' . $context['ticket_id']); } require_once $sourcedir . '/Subs-Post.php'; // The destination board must be numeric. $_POST['toboard'] = (int) $_POST['toboard']; $msg_assoc = array(); // This is complex, very complex. Hopefully 5 minutes will be enough... @set_time_limit(300); // Make sure they can see the board they are trying to move to (and get whether posts count in the target board). $request = shd_db_query('', ' SELECT b.count_posts, b.name, hdt.subject, hdt.id_member_started, hdtr.body, hdt.id_first_msg, hdtr.smileys_enabled, hdtr.modified_time, hdtr.modified_name, hdtr.poster_time, hdtr.id_msg, hdt.deleted_replies, hdt.id_dept FROM {db_prefix}boards AS b INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdt.id_ticket = {int:ticket}) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdtr.id_msg = hdt.id_first_msg) WHERE {query_see_board} AND {query_see_ticket} AND b.id_board = {int:to_board} AND b.redirect = {string:blank_redirect} LIMIT 1', array('ticket' => $context['ticket_id'], 'to_board' => $_POST['toboard'], 'blank_redirect' => '')); if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_board'); } else { list($pcounter, $board_name, $subject, $owner, $body, $firstmsg, $smileys_enabled, $modified_time, $modified_name, $time, $shd_id_msg, $deleted_replies, $dept) = $smcFunc['db_fetch_row']($request); } $smcFunc['db_free_result']($request); if (!shd_allowed_to('shd_ticket_to_topic', $dept) || !empty($modSettings['shd_helpdesk_only']) || !empty($modSettings['shd_disable_tickettotopic'])) { fatal_lang_error('shd_cannot_move_ticket', false); } // Are we changing the subject? $old_subject = $subject; $subject = !empty($_POST['change_subject']) && !empty($_POST['subject']) ? $_POST['subject'] : $subject; $context['deleted_prompt'] = false; // Hang on... are there any deleted replies? if ($deleted_replies > 0) { if (shd_allowed_to('shd_access_recyclebin')) { $dr_opts = array('abort', 'delete', 'undelete'); $context['deleted_prompt'] = isset($_REQUEST['deleted_replies']) && in_array($_REQUEST['deleted_replies'], $dr_opts) ? $_REQUEST['deleted_replies'] : 'abort'; } else { fatal_lang_error('shd_cannot_move_ticket_with_deleted'); } } if (!empty($context['deleted_prompt']) && $context['deleted_prompt'] == 'abort') { redirectexit('action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'] . ';recycle'); } // Now the madness that is custom fields. First, load the custom fields we might/will be using. $query = $smcFunc['db_query']('', ' SELECT hdcf.id_field, hdcf.field_name, hdcf.field_order, hdcf.field_type, hdcf.can_see, hdcf.field_options, hdcf.bbc, hdcf.placement FROM {db_prefix}helpdesk_custom_fields_depts AS hdd INNER JOIN {db_prefix}helpdesk_custom_fields AS hdcf ON (hdd.id_field = hdcf.id_field) WHERE hdd.id_dept = {int:dept} AND hdcf.active = {int:active} ORDER BY hdcf.field_order', array('dept' => $dept, 'active' => 1)); $context['custom_fields'] = array(); $is_staff = shd_allowed_to('shd_staff', $dept); $is_admin = shd_allowed_to('admin_helpdesk', $dept); while ($row = $smcFunc['db_fetch_assoc']($query)) { list($user_see, $staff_see) = explode(',', $row['can_see']); $context['custom_fields'][$row['id_field']] = array('id_field' => $row['id_field'], 'name' => $row['field_name'], 'type' => $row['field_type'], 'bbc' => !empty($row['bbc']), 'options' => !empty($row['field_options']) ? unserialize($row['field_options']) : array(), 'placement' => $row['placement'], 'visible' => array('user' => $user_see, 'staff' => $staff_see, 'admin' => true), 'values' => array()); } $smcFunc['db_free_result']($query); // Having got all the possible fields for this ticket, let's fetch the values for it. That way if we don't have any values for a field, we don't have to care about showing the user. // But first, we need all the message ids. $context['ticket_messages'] = array(); $query = $smcFunc['db_query']('', ' SELECT id_msg FROM {db_prefix}helpdesk_ticket_replies AS hdtr WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); while ($row = $smcFunc['db_fetch_row']($query)) { $context['ticket_messages'][] = $row[0]; } $smcFunc['db_free_result']($query); // Now get a reference for the field values. $query = $smcFunc['db_query']('', ' SELECT cfv.id_post, cfv.id_field, cfv.post_type, cfv.value FROM {db_prefix}helpdesk_custom_fields_values AS cfv WHERE (cfv.id_post = {int:ticket} AND cfv.post_type = 1)' . (!empty($context['ticket_messages']) ? ' OR (cfv.id_post IN ({array_int:msgs}) AND cfv.post_type = 2)' : ''), array('ticket' => $context['ticket_id'], 'msgs' => $context['ticket_messages'])); while ($row = $smcFunc['db_fetch_assoc']($query)) { if (isset($context['custom_fields'][$row['id_field']])) { $context['custom_fields'][$row['id_field']]['values'][$row['post_type']][$row['id_post']] = $row['value']; } } $smcFunc['db_free_result']($query); // Having now established what fields we do actually have values for, let's proceed to deal with them. foreach ($context['custom_fields'] as $field_id => $field) { // Didn't we have any values? If not, prune it, not interested. if (empty($field['values'])) { unset($context['custom_fields'][$field_id]); } // If the user is an administrator, they can always see the fields. if ($is_admin) { // But users might not be able to, in which case we need to validate that actually, they did need to authorise this one. if (!$field['visible']['user'] || !$field['visible']['staff']) { $context['custom_fields_warning'] = true; } } elseif ($is_staff) { // So they're staff. But the field might not be visible to them; they can't deal with it whatever. if (!$field['visible']['staff']) { fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false); } elseif (!$field['visible']['user']) { $context['custom_fields_warning'] = true; } } else { // Non staff aren't special. They should not be able to make this decision. If someone can't see it, they don't get to make the choice. if (!$field['visible']['user'] || !$field['visible']['staff']) { fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false); } } // Are we ignoring this field? If so, we can now safely get rid of it at this very point. if (isset($_POST['field' . $field_id]) && $_POST['field' . $field_id] == 'lose') { unset($context['custom_fields'][$field_id]); } } // Were there any special fields? We need to check - and check that they ticked the right box! if (!empty($context['custom_fields_warning']) && empty($_POST['accept_move'])) { checkSubmitOnce('free'); fatal_lang_error('shd_ticket_move_reqd_nonselected', false); } // Just before we do this, make sure we call any hooks. $context has lots of interesting things, as does $_POST. call_integration_hook('shd_hook_tickettotopic'); // OK, so we have some fields, and we're doing something with them. First we need to attach the fields from the ticket to the opening post. shd_append_custom_fields($body, $context['ticket_id'], CFIELD_TICKET); // All okay, it seems. Let's go create the topic. $msgOptions = array('subject' => $subject, 'body' => $body, 'icon' => 'xx', 'smileys_enabled' => !empty($smileys_enabled) ? 1 : 0); $topicOptions = array('board' => $_POST['toboard'], 'lock_mode' => 0, 'mark_as_read' => false); $posterOptions = array('id' => $owner, 'update_post_count' => empty($pcounter)); createPost($msgOptions, $topicOptions, $posterOptions); // Keep track of SHD msg id to SMF msg id $msg_assoc[$shd_id_msg] = $msgOptions['id']; // createPost() doesn't handle modified time and name, so we'll fix that here, along with the poster time. if (!empty($modified_time)) { shd_db_query('', ' UPDATE {db_prefix}messages SET modified_time = {int:modified_time}, modified_name = {string:modified_name}, poster_time = {int:poster_time} WHERE id_msg = {int:id_msg}', array('id_msg' => $firstmsg, 'modified_time' => $modified_time, 'modified_name' => $modified_name, 'poster_time' => $time)); } // Topic created, let's dig out the replies and post them in the topic, if there are any. if (isset($topicOptions['id'])) { $request = shd_db_query('', ' SELECT body, id_member, poster_time, poster_name, poster_email, poster_ip, smileys_enabled, modified_time, modified_member, modified_name, poster_time, id_msg, message_status FROM {db_prefix}helpdesk_ticket_replies AS hdtr WHERE id_ticket = {int:ticket} AND id_msg > {int:ticket_msg} ORDER BY id_msg', array('ticket' => $context['ticket_id'], 'ticket_msg' => $firstmsg)); // The ID of the topic we created $topic = $topicOptions['id']; if ($smcFunc['db_num_rows']($request) != 0) { // Now loop through each reply and post it. Hopefully there aren't too many. *looks at clock* while ($row = $smcFunc['db_fetch_assoc']($request)) { if ($row['message_status'] == MSG_STATUS_DELETED && !empty($context['deleted_prompt']) && $context['deleted_prompt'] == 'delete') { // we don't want these replies! continue; } shd_append_custom_fields($row['body'], $row['id_msg'], CFIELD_REPLY); $msgOptions = array('subject' => $txt['response_prefix'] . $subject, 'body' => $row['body'], 'icon' => 'xx', 'smileys_enabled' => !empty($row['smileys_enabled']) ? 1 : 0); $topicOptions = array('id' => $topic, 'board' => $_POST['toboard'], 'lock_mode' => 0, 'mark_as_read' => false); $posterOptions = array('id' => $row['id_member'], 'name' => !empty($row['poster_name']) ? $row['poster_name'] : '', 'email' => !empty($row['poster_email']) ? $row['poster_email'] : '', 'ip' => !empty($row['poster_ip']) ? $row['poster_ip'] : '', 'update_post_count' => empty($pcounter)); createPost($msgOptions, $topicOptions, $posterOptions); // Don't forget to note what id $msg_assoc[$row['id_msg']] = $msgOptions['id']; // Meh, createPost() doesn't have any hooks for modified time and user. Let's fix that now. if (!empty($row['modified_time'])) { shd_db_query('', ' UPDATE {db_prefix}messages SET modified_time = {int:modified_time}, modified_name = {string:modified_name}, poster_time = {int:poster_time} WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id'], 'modified_time' => $row['modified_time'], 'modified_name' => $row['modified_name'], 'poster_time' => $row['poster_time'])); } } } // Topic: check; Replies: check; Notfiy the ticket starter, if desired. if (isset($_POST['send_pm'])) { $request = shd_db_query('pm_find_username', ' SELECT id_member, real_name FROM {db_prefix}members WHERE id_member = {int:user} LIMIT 1', array('user' => $owner)); list($userid, $username) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Fix the content $replacements = array('{user}' => $username, '{subject}' => $old_subject, '{board}' => '[url=' . $scripturl . '?board=' . $_POST['toboard'] . '.0]' . $board_name . '[/url]', '{link}' => $scripturl . '?topic=' . $topic . '.0'); $message = str_replace(array_keys($replacements), array_values($replacements), $_POST['pm_content']); $recipients = array('to' => array($owner), 'bcc' => array()); sendpm($recipients, $txt['shd_ticket_moved_subject'], un_htmlspecialchars($message)); } // Right, time to do all the attachment fussing too if (!empty($msg_assoc)) { $attachIDs = array(); $query = shd_db_query('', ' SELECT id_attach, id_msg FROM {db_prefix}helpdesk_attachments WHERE id_msg IN ({array_int:msgs})', array('msgs' => array_keys($msg_assoc))); while ($row = $smcFunc['db_fetch_assoc']($query)) { $attachIDs[] = $row; } $smcFunc['db_free_result']($query); if (!empty($attachIDs)) { // 1. Update all the attachments in the master table; this is the bit that hurts since it can't be done without // a query per row :( foreach ($attachIDs as $attach) { shd_db_query('', ' UPDATE {db_prefix}attachments SET id_msg = {int:new_msg} WHERE id_attach = {int:attach}', array('attach' => $attach['id_attach'], 'new_msg' => $msg_assoc[$attach['id_msg']])); } // 2. Remove the entries from the SD table since we don't need them no more shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_attachments WHERE id_msg IN ({array_int:msgs})', array('msgs' => array_keys($msg_assoc))); } } // Well, it's possible there are some phantom attachments on deleted replies that need to disappear if (!empty($context['deleted_replies']) && $context['deleted_replies'] == 'delete') { $query = shd_db_query('', ' SELECT id_msg FROM {db_prefix}helpdesk_attachments AS hda INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hda.id_msg = hdtr.id_msg) WHERE id_ticket = {int:ticket} AND hdtr.message_status = {int:deleted}', array('ticket' => $context['ticket_id'], 'deleted' => MSG_STATUS_DELETED)); if ($smcFunc['db_num_rows']($query) > 0) { $msgs = array(); while ($row = $smcFunc['db_fetch_row']($query)) { $msgs[] = $row[0]; } if (!empty($msgs)) { // Get rid of the parents require_once $sourcedir . '/ManageAttachments.php'; $attachmentQuery = array('attachment_type' => 0, 'id_msg' => 0, 'id_attach' => $msgs); removeAttachments($attachmentQuery); // Get rid of the remainder in hda table shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_attachments WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); } } $smcFunc['db_free_result']($query); } // Now we'll add this to the log. $log_params = array('subject' => $subject, 'board_id' => $_POST['toboard'], 'board_name' => $board_name, 'ticket' => $topic); shd_log_action('tickettotopic', $log_params); // Lastly, delete the ticket from the database. shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_tickets WHERE id_ticket = {int:ticket} LIMIT 1', array('ticket' => $context['ticket_id'])); // And the replies, too. shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_ticket_replies WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); // And custom fields. shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_custom_fields_values WHERE (id_post = {int:ticket} AND post_type = 1)' . (!empty($context['ticket_messages']) ? ' OR (id_post IN ({array_int:msgs}) AND post_type = 2)' : ''), array('ticket' => $context['ticket_id'], 'msgs' => $context['ticket_messages'])); } else { fatal_lang_error('shd_move_topic_not_created', false); } // Clear our cache shd_clear_active_tickets($dept); // Send them to the topic. redirectexit('topic=' . $topic . '.0'); }
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; }
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; }