function xthreads_uninstall() { global $db, $cache, $mybb, $plugins; if ($mybb->input['no']) { admin_redirect(xthreads_admin_url('config', 'plugins')); exit; } if (!$mybb->input['confirm_uninstall']) { $link = 'index.php?confirm_uninstall=1&' . htmlspecialchars($_SERVER['QUERY_STRING']); $GLOBALS['page']->output_confirm_action($link, $GLOBALS['lang']->xthreads_confirm_uninstall); exit; } else { unset($mybb->input['confirm_uninstall']); } $plugins->run_hooks('xthreads_uninstall_start'); $query = $db->simple_select('adminoptions', 'uid,permissions'); while ($adminopt = $db->fetch_array($query)) { $perms = @unserialize($adminopt['permissions']); if (empty($perms)) { continue; } // inherited or just messed up unset($perms['config']['threadfields']); $db->update_query('adminoptions', array('permissions' => $db->escape_string(serialize($perms))), 'uid=' . $adminopt['uid']); } $db->free_result($query); if ($db->table_exists('threadfields_data')) { $db->write_query('DROP TABLE ' . $db->table_prefix . 'threadfields_data'); } if ($db->table_exists('threadfields')) { $db->write_query('DROP TABLE ' . $db->table_prefix . 'threadfields'); } if ($db->table_exists('xtattachments')) { // remove attachments first require_once MYBB_ROOT . 'inc/xthreads/xt_updatehooks.php'; $query = $db->simple_select('xtattachments', 'aid,indir,attachname'); while ($xta = $db->fetch_array($query)) { xthreads_rm_attach_fs($xta); } $db->free_result($query); $db->write_query('DROP TABLE ' . $db->table_prefix . 'xtattachments'); } // remove any indexes added on the threads table foreach (array('uid', 'lastposteruid', 'prefix', 'icon') as $afe) { if ($afe == 'uid') { continue; } // we won't remove this from the above array $db->write_query('ALTER TABLE `' . $db->table_prefix . 'threads` DROP KEY `xthreads_' . $afe . '`', true); } $fields = array('xthreads_grouping', 'xthreads_firstpostattop', 'xthreads_inlinesearch', 'xthreads_tplprefix', 'xthreads_langprefix', 'xthreads_allow_blankmsg', 'xthreads_nostatcount', 'xthreads_fdcolspan_offset', 'xthreads_settingoverrides', 'xthreads_postsperpage', 'xthreads_hideforum', 'xthreads_hidebreadcrumb', 'xthreads_defaultfilter', 'xthreads_addfiltenable', 'xthreads_wol_announcements', 'xthreads_wol_forumdisplay', 'xthreads_wol_newthread', 'xthreads_wol_attachment', 'xthreads_wol_newreply', 'xthreads_wol_showthread'); foreach ($fields as $k => &$f) { if (!$db->field_exists($f, 'forums')) { unset($fields[$k]); } } if (!empty($fields)) { switch ($db->type) { case 'sqlite3': case 'sqlite2': case 'sqlite': $db->alter_table_parse($db->table_prefix . 'forums', 'DROP ' . implode(', DROP COLUMN ', $fields) . ''); break; case 'pgsql': foreach ($fields as &$f) { $db->write_query('ALTER TABLE ' . $db->table_prefix . 'forums DROP COLUMN ' . $f); } break; default: $db->write_query('ALTER TABLE ' . $db->table_prefix . 'forums DROP COLUMN ' . implode(', DROP COLUMN ', $fields)); } } // remove any custom default sorts and reduce size of sorting column back to original $db->update_query('forums', array('defaultsortby' => ''), 'defaultsortby LIKE "tf_%" OR defaultsortby LIKE "tfa_%"'); $db->write_query('ALTER TABLE `' . $db->table_prefix . 'forums` MODIFY `defaultsortby` varchar(10) NOT NULL default \'\''); $cache->update_forums(); xthreads_delete_datacache('threadfields'); @unlink(MYBB_ROOT . 'cache/xthreads.php'); @unlink(MYBB_ROOT . 'cache/xthreads_evalcache.php'); $db->delete_query('templates', 'title IN ("' . implode('","', array_keys(xthreads_new_templates())) . '") AND sid=-2'); // revert QuickThread modification if (function_exists('quickthread_uninstall')) { $tpl = $db->fetch_array($db->simple_select('templates', 'tid,template', 'title="forumdisplay_quick_thread" AND sid=-1', array('limit' => 1))); if ($tpl && strpos($tpl['template'], '{$GLOBALS[\'extra_threadfields\']}') !== false) { $newtpl = preg_replace('~\\{\\$GLOBALS\\[\'extra_threadfields\'\\]\\}' . "\r?(\n\t{0,3})?" . '~is', '', $tpl['template'], 1); if ($newtpl != $tpl['template']) { $db->update_query('templates', array('template' => $db->escape_string($newtpl)), 'tid=' . $tpl['tid']); } } } // try to determine and remove stuff added to the custom moderation table $query = $db->simple_select('modtools', 'tid,threadoptions'); while ($tool = $db->fetch_array($query)) { $opts = unserialize($tool['threadoptions']); if (isset($opts['edit_threadfields'])) { unset($opts['edit_threadfields']); $db->update_query('modtools', array('threadoptions' => $db->escape_string(serialize($opts))), 'tid=' . $tool['tid']); } } $plugins->run_hooks('xthreads_uninstall_end'); }
function xthreads_upload_attachments() { global $xta_cache, $threadfield_cache, $mybb, $db, $lang, $fid; // only ever execute this function once per page static $done = false; if ($done) { return; } $done = true; if (!$fid) { if ($GLOBALS['forum']['fid']) { $fid = $GLOBALS['forum']['fid']; } elseif ($GLOBALS['foruminfo']['fid']) { $fid = $GLOBALS['foruminfo']['fid']; } elseif ($mybb->input['pid']) { // editpost - not good to trust user input, but should be fine $post = get_post((int) $mybb->input['pid']); if ($post['pid']) { $fid = $post['fid']; } } elseif ($mybb->input['fid']) { // newthread $fid = (int) $mybb->input['fid']; } // we _should_ now have an fid } if (!isset($threadfield_cache)) { $threadfield_cache = xthreads_gettfcache($fid); } // remove uneditable fields xthreads_filter_tfeditable($threadfield_cache, $fid); // NOTE: modifies the global tfcache! if (empty($threadfield_cache)) { return; } if (!is_array($xta_cache)) { $xta_cache = array(); } // first, run through to see if we have already uploaded some attachments // this code totally relies on the posthash being unique... if ($GLOBALS['thread']['tid']) { $attachwhere = 'tid=' . (int) $GLOBALS['thread']['tid']; } else { $attachwhere = 'posthash="' . $db->escape_string($mybb->input['posthash']) . '"'; } $query = $db->simple_select('xtattachments', '*', $attachwhere); $attach_fields = array(); while ($attach = $db->fetch_array($query)) { $xta_cache[$attach['aid']] = $attach; $attach_fields[$attach['field']][] = $attach['aid']; } $db->free_result($query); @ignore_user_abort(true); $errors = array(); $xta_remove = $threadfield_updates = array(); foreach ($threadfield_cache as $k => &$v) { if ($v['inputtype'] != XTHREADS_INPUT_FILE && $v['inputtype'] != XTHREADS_INPUT_FILE_URL) { continue; } $aid =& $mybb->input['xthreads_' . $k]; if ($v['inputtype'] != XTHREADS_INPUT_FILE_URL || is_numeric($mybb->input['xthreads_' . $k])) { $singleval = xthreads_empty($v['multival']); // now, we're ignoring what the user sends us, totally... if ($attach_fields[$k]) { if ($singleval) { $aid = (int) reset($attach_fields[$k]); } else { $aid = array_unique(array_map('intval', $attach_fields[$k])); // re-ordering support if (is_array($mybb->input['xtaorder'])) { $aid_order = array_unique(array_map('intval', $mybb->input['xtaorder'])); if (count($aid) == count($aid_order) && $aid != $aid_order && !count(array_diff($aid, $aid_order))) { $aid = $aid_order; $threadfield_updates[$k] = implode(',', $aid); } } $aid = array_combine($aid, $aid); } } else { $aid = 0; } } // handle file upload $ul = null; if ($singleval) { if (!empty($_FILES['xthreads_' . $k]) && !xthreads_empty($_FILES['xthreads_' . $k]['name']) && is_string($_FILES['xthreads_' . $k]['name'])) { $ul = $_FILES['xthreads_' . $k]; } elseif ($v['inputtype'] == XTHREADS_INPUT_FILE && XTHREADS_ALLOW_URL_FETCH && !xthreads_empty($mybb->input['xtaurl_' . $k])) { // the preg_match is just a basic prelim check - the real URL checking is done later; we need this prelim check to stop it erroring out on the defalt "http://" string if (preg_match('~^[a-z0-9\\-]+\\://[^/?#]+(?:/.*)?$~', $mybb->input['xtaurl_' . $k])) { $ul = $mybb->input['xtaurl_' . $k]; } } !isset($ul) or $ul = array($ul); } else { $ul = array(); if (is_array($mybb->input['xtaurl_' . $k])) { $input_urls = $mybb->input['xtaurl_' . $k]; $input_key_match = true; // if URL input is an array, we'll match with equivalent file input keys } else { $input_urls = explode("\n", str_replace("\r", '', $mybb->input['xtaurl_' . $k])); $input_key_match = false; } if (!empty($_FILES['xthreads_' . $k]) && is_array($_FILES['xthreads_' . $k])) { foreach ($_FILES['xthreads_' . $k]['name'] as $file_k => $filename) { if (!xthreads_empty($filename)) { $file_v = array(); // why does PHP does this and make our life difficult? foreach ($_FILES['xthreads_' . $k] as $fvkey => $fvval) { $file_v[$fvkey] = $fvval[$file_k]; } if ($input_key_match && is_numeric($file_k) || preg_match('~^aid\\d+$~', $file_k)) { $ul[$file_k] = $file_v; } else { $ul[] = $file_v; } } } } if ($v['inputtype'] == XTHREADS_INPUT_FILE && XTHREADS_ALLOW_URL_FETCH && !empty($input_urls) && is_array($input_urls)) { foreach ($input_urls as $url_k => $url_v) { $url_v = trim($url_v); if (preg_match('~^[a-z0-9\\-]+\\://[a-z0-9_\\-@:.]+(?:/.*)?$~', $url_v)) { if ($input_key_match && is_numeric($url_k) || preg_match('~^aid\\d+$~', $url_k)) { isset($ul[$url_k]) or $ul[$url_k] = $url_v; } else { $ul[] = $url_v; } } } } } unset($mybb->input['xtaurl_' . $k], $_FILES['xthreads_' . $k]); // remove files from list first (so we can properly measure the correct final number of attachments when uploading) // fix the threadfield_updates array later on if ($singleval) { if (empty($ul) && $mybb->input['xtarm_' . $k] && $v['editable'] != XTHREADS_EDITABLE_REQ) { // user wants to remove attachment $xta_remove[$aid] = $aid; $aid = 0; } } elseif (!empty($mybb->input['xtarm_' . $k]) && is_array($mybb->input['xtarm_' . $k])) { foreach ($mybb->input['xtarm_' . $k] as $rm_aid => $rm_confirm) { if (!$rm_confirm) { continue; } // double-check they really do want to remove this $xta_remove[$rm_aid] = $rm_aid; unset($aid[$rm_aid]); } } // upload new stuff if (!empty($ul)) { require_once MYBB_ROOT . 'inc/xthreads/xt_upload.php'; $update_aid = is_array($aid) ? 0 : $aid; $failed_urls = array(); // list of any URLs that failed to fetch foreach ($ul as $ul_key => $ul_file) { // hard limit number of files to at least 20 if (!$singleval && is_array($aid)) { // hard limit if (strlen(implode(',', $aid)) >= 245) { if (!$lang->xthreads_xtaerr_error_attachhardlimit) { $lang->load('xthreads'); } $errors[] = $lang->sprintf($lang->xthreads_xtaerr_error_attachhardlimit, htmlspecialchars_uni($v['title'])); break; } // admin defined limit if ($v['multival_limit'] && count($aid) >= $v['multival_limit']) { if (!$lang->xthreads_xtaerr_error_attachnumlimit) { $lang->load('xthreads'); } $errors[] = $lang->sprintf($lang->xthreads_xtaerr_error_attachnumlimit, $v['multival_limit'], htmlspecialchars_uni($v['title'])); break; } } // allow updating a specific attachment in a multi-field thing $update_aid2 = $update_aid; if (!$update_aid2 && is_array($aid) && substr($ul_key, 0, 3) == 'aid') { $update_aid2 = (int) substr($ul_key, 3); if (!in_array($update_aid2, $aid)) { $update_aid2 = 0; } } $attachedfile = upload_xtattachment($ul_file, $v, $mybb->user['uid'], $update_aid2, $GLOBALS['thread']['tid']); if ($attachedfile['error']) { if (!$lang->xthreads_threadfield_attacherror) { $lang->load('xthreads'); } $errors[] = $lang->sprintf($lang->xthreads_threadfield_attacherror, htmlspecialchars_uni($v['title']), $attachedfile['error']); if (is_string($ul_file)) { $failed_urls[] = $ul_file; } } else { //unset($attachedfile['posthash'], $attachedfile['tid'], $attachedfile['downloads']); $xta_cache[$attachedfile['aid']] = $attachedfile; if ($singleval) { unset($mybb->input['xtarm_' . $k]); // since successful upload, don't tick remove box $aid = $attachedfile['aid']; } else { if (is_array($mybb->input['xtarm_' . $k])) { unset($mybb->input['xtarm_' . $k][$attachedfile['aid']]); } is_array($aid) or $aid = array(); // if no aid already set, it will be 0, so turn into array if necessary $aid[$attachedfile['aid']] = $attachedfile['aid']; } // if we were going to remove this file, don't if (isset($xta_remove[$attachedfile['aid']])) { unset($xta_remove[$attachedfile['aid']]); } if ($attachedfile['aid'] != $update_aid2) { // adding a new attachment $threadfield_updates[$k] = $singleval ? $aid : true; } } } // list failed URLs in textboxes if (!empty($failed_urls)) { $mybb->input['xtaurl_' . $k] = implode("\n", $failed_urls); unset($failed_urls); } } // fix threadfield update if removing an item and not already done if (!empty($xta_remove) && !isset($threadfield_updates[$k])) { $threadfield_updates[$k] = $singleval ? 0 : true; } // fix placeholder value if ($threadfield_updates[$k] === true) { $threadfield_updates[$k] = implode(',', $aid); } unset($aid); } if (!empty($xta_remove)) { $db->delete_query('xtattachments', 'aid IN (' . implode(',', $xta_remove) . ')'); foreach ($xta_remove as $aid) { xthreads_rm_attach_fs($xta_cache[$aid]); } } $is_editing = $GLOBALS['current_page'] == 'editpost.php'; // if editing post, also commit change to thread field immediately (waiting for user to submit is unreliable) if (($is_editing || $GLOBALS['thread']['tid'] && $GLOBALS['current_page'] == 'newthread.php') && !empty($threadfield_updates)) { xthreads_db_update_replace('threadfields_data', $threadfield_updates, 'tid', $GLOBALS['thread']['tid']); } @ignore_user_abort(false); if (!empty($errors)) { global $plugins; $is_mybb_18 = $mybb->version_code >= 1700; // MyBB 1.4 - 1.5 // and MyBB 1.6 is inconsistent (does different things on newthread/editpost)... if ($mybb->version_code < 1600 || $is_editing) { // can't find a better way to check other than to check version numbers global $theme, $templates; $errstr = '<li>' . implode('</li><li>', $errors) . '</li>'; if ($is_editing && $is_mybb_18) { // special workaround for MyBB 1.8 $GLOBALS['xt_attach_errors'] =& $errstr; $templates->cache['__xt_orig_error_attacherror'] = $templates->cache['error_attacherror']; function xthreads_upload_attachments_error() { global $theme, $templates, $attacherror, $mybb, $lang, $fid; if ($attacherror) { return; } // already handled by template cache hack $attachedfile = array('error' => '<ul>' . $GLOBALS['xt_attach_errors'] . '</ul>'); eval('$attacherror = "' . $templates->get('__xt_orig_error_attacherror') . '";'); } $plugins->add_hook('editpost_action_start', 'xthreads_upload_attachments_error'); } else { $attachedfile = array('error' => '<ul>' . $errstr . '</ul>'); eval('$GLOBALS[\'attacherror\'] .= "' . $templates->get('error_attacherror') . '";'); } // if there's going to be a MyBB attachment error, and it's not been evaluated yet, shove it in the template to force it through - safe since this function is guaranteed to run only once $templates->cache['error_attacherror'] = str_replace('{$attachedfile[\'error\']}', '<ul>' . strtr($errstr, array('\\' => '\\\\', '$' => '\\$', '{' => '\\{', '}' => '\\}')) . '<li>{$attachedfile[\'error\']}</li></ul>', $templates->cache['error_attacherror']); } elseif ($is_mybb_18) { // for MyBB 1.8 $GLOBALS['xt_attach_errors'] =& $errors; function xthreads_upload_attachments_error() { if (empty($GLOBALS['errors'])) { $GLOBALS['errors'] =& $GLOBALS['xt_attach_errors']; } else { $GLOBALS['errors'] = array_merge($GLOBALS['errors'], $GLOBALS['xt_attach_errors']); } } $plugins->add_hook('newthread_start', 'xthreads_upload_attachments_error'); } else { // for MyBB 1.6 if (empty($GLOBALS['errors'])) { $GLOBALS['errors'] =& $errors; } else { $GLOBALS['errors'] = array_merge($GLOBALS['errors'], $errors); } } $mybb->input['action'] = $is_editing ? 'editpost' : 'newthread'; // block the preview, since a failed upload can stuff it up // lower priority to go before inputdisp function (contention, the function checks for 'previewpost') $plugins->add_hook('newthread_start', 'xthreads_newthread_ulattach_blockpreview', 5); $plugins->add_hook('editpost_start', 'xthreads_editthread_ulattach_blockpreview', 5); } }
function do_upload_xtattachment($attachment, &$tf, $update_attachment = 0, $tid = 0, $timestamp = TIME_NOW) { global $db, $mybb, $lang; $posthash = $db->escape_string($mybb->input['posthash']); $tid = (int) $tid; // may be possible for this to be null, if so, change to 0 $path = $mybb->settings['uploadspath'] . '/xthreads_ul/'; if (!$lang->xthreads_threadfield_attacherror) { $lang->load('xthreads'); } if (is_array($attachment)) { if (isset($attachment['error']) && $attachment['error']) { if ($attachment['error'] == 2) { return array('error' => $lang->sprintf($lang->xthreads_xtaerr_error_attachsize, get_friendly_size($tf['filemaxsize']))); } elseif ($attachment['error'] >= 1 && $attachment['error'] <= 7) { $langvar = 'error_uploadfailed_php' . $attachment['error']; $langstr = $lang->{$langvar}; } else { $langstr = $lang->sprintf($lang->error_uploadfailed_phpx, $attachment['error']); } return array('error' => $lang->error_uploadfailed . $lang->error_uploadfailed_detail . $langstr); } if (!is_uploaded_file($attachment['tmp_name']) || empty($attachment['tmp_name'])) { return array('error' => $lang->error_uploadfailed . $lang->error_uploadfailed_php4); } $file_size = $attachment['size']; // @filesize($attachment['tmp_name']) $attachment['name'] = strtr($attachment['name'], array('/' => '', "" => '')); if ($error = xthreads_validate_attachment($attachment, $tf)) { @unlink($attachment['tmp_name']); return array('error' => $error); } $movefunc = 'move_uploaded_file'; } elseif ($mybb->usergroup['cancp'] == 1 && substr($attachment, 0, 7) == 'file://') { // admin file move $filename = strtr(substr($attachment, 7), array('/' => '', DIRECTORY_SEPARATOR => '', "" => '')); $file = $path . 'admindrop/' . $filename; if (xthreads_empty($filename) || !file_exists($file)) { return array('error' => $lang->sprintf($lang->xthreads_xtaerr_admindrop_not_found, htmlspecialchars_uni($filename), htmlspecialchars_uni($file))); } if (!is_writable($file)) { return array('error' => $lang->sprintf($lang->xthreads_xtaerr_admindrop_file_unwritable, htmlspecialchars_uni($filename))); } if (strtolower($file) == 'index.html') { return array('error' => $lang->xthreads_xtaerr_admindrop_index_error); } $attachment = array('name' => $filename, 'tmp_name' => $file, 'size' => @filesize($file)); unset($file, $filename); if ($error = xthreads_validate_attachment($attachment, $tf)) { return array('error' => $error); } $file_size = $attachment['size']; $movefunc = 'rename'; } else { // fetch URL if (!empty($tf['filemagic'])) { $magic =& $tf['filemagic']; } else { $magic = array(); } $attachment = xthreads_fetch_url($attachment, $tf['filemaxsize'], $tf['fileexts'], $magic); db_ping($db); if ($attachment['error']) { return array('error' => $attachment['error']); } $file_size = $attachment['size']; if (xthreads_empty($attachment['name']) || $file_size < 1) { return array('error' => $lang->error_uploadfailed); } $attachment['name'] = strtr($attachment['name'], array('/' => '', "" => '')); $movefunc = 'rename'; } if ($tf['fileimage']) { $img_dimensions = @getimagesize($attachment['tmp_name']); if (empty($img_dimensions) || !in_array($img_dimensions[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { @unlink($attachment['tmp_name']); return array('error' => $lang->error_attachtype); } if (preg_match('~^([0-9]+)x([0-9]+)(\\|([0-9]+)x([0-9]+))?$~', $tf['fileimage'], $match)) { // check if image exceeds max/min dimensions if ($img_dimensions[0] < $match[1] || $img_dimensions[1] < $match[2] || $match[3] && ($img_dimensions[0] > $match[4] || $img_dimensions[1] > $match[5])) { @unlink($attachment['tmp_name']); return array('error' => $lang->sprintf($lang->xthreads_xtaerr_error_imgdims, $img_dimensions[0], $img_dimensions[1])); } } /* // convert WBMP -> PNG (saves space, bandwidth and works with MyBB's thumbnail generator) // unfortunately, although this is nice, we have a problem of filetype checking etc... if($img_dimensions[2] == IMAGETYPE_WBMP) { if(function_exists('imagecreatefromwbmp') && $img = @imagecreatefromwbmp($attachment['tmp_name'])) { @unlink($attachment['tmp_name']); @imagepng($img, $attachment['tmp_name'], 6); // use zlib's recommended compression level imgdestroy($img); unset($img); // double check that we have a file if(!file_exists($attachment['tmp_name'])) return array('error' => $lang->error_attachtype); // get user to upload a non-WBMP file, lol // change extension + update filesize, do MIME as well if(strtolower(substr($attachment['name'], -5)) == '.wbmp') $attachment['name'] = substr($attachment['name'], 0, -5).'.png'; $file_size = @filesize($attachment['tmp_name']); if(strtolower($attachment['type']) == 'image/wbmp') $attachment['type'] = 'image/png'; // update type too $img_dimensions[2] = IMAGETYPE_PNG; } else { // can't do much, error out @unlink($attachment['tmp_name']); return array('error' => $lang->error_attachtype); } } */ // we won't actually bother checking MIME types - not a big issue anyway } if (!XTHREADS_UPLOAD_LARGEFILE_SIZE || $file_size < XTHREADS_UPLOAD_LARGEFILE_SIZE) { @set_time_limit(30); // as md5_file may take a while $md5_start = time(); $file_md5 = @md5_file($attachment['tmp_name'], true); if (strlen($file_md5) == 32) { // perhaps not PHP5 $file_md5 = pack('H*', $file_md5); } if (time() - $md5_start > 2) { // ping DB if process took longer than 2 secs db_ping($db); } unset($md5_start); } if ($update_attachment) { $prevattach = $db->fetch_array($db->simple_select('xtattachments', 'aid,attachname,indir,md5hash', 'aid=' . (int) $update_attachment)); if (!$prevattach['aid']) { $update_attachment = false; } } /* else { // Check if attachment already uploaded // TODO: this is actually a little problematic - perhaps verify that this is attached to this field (or maybe rely on checks in xt_updatehooks file) if(isset($file_md5)) $md5check = ' OR md5hash='.xthreads_db_escape_binary($file_md5); else $md5check = ''; $prevattach = $db->fetch_array($db->simple_select('xtattachments', 'aid', 'filename="'.$db->escape_string($attachment['name']).'" AND (md5hash IS NULL'.$md5check.') AND filesize='.$file_size.' AND (posthash="'.$posthash.'" OR (tid='.$tid.' AND tid!=0))')); if($prevattach['aid']) { @unlink($attachment['tmp_name']); // TODO: maybe return aid instead? return array('error' => $lang->error_alreadyuploaded); } } */ // We won't use MyBB's nice monthly directories, instead, we'll use a more confusing system based on the timestamps // note, one month = 2592000 seconds, so if we split up by 1mil, it'll be approx 11.5 days // If safe_mode is enabled, don't attempt to use the monthly directories as it won't work if (ini_get('safe_mode') == 1 || strtolower(ini_get('safe_mode')) == 'on') { $month_dir = ''; } else { $month_dir = 'ts_' . floor(TIME_NOW / 1000000) . '/'; if (!@is_dir($path . $month_dir)) { @mkdir($path . $month_dir); // Still doesn't exist - oh well, throw it in the main directory if (@is_dir($path . $month_dir)) { // write index file if ($index = fopen($path . $month_dir . 'index.html', 'w')) { fwrite($index, '<html><body></body></html>'); fclose($index); @my_chmod($path . $month_dir . 'index.html', 0644); } @my_chmod($path . $month_dir, 0755); } else { $month_dir = ''; } } } // All seems to be good, lets move the attachment! $basename = substr(md5(uniqid(mt_rand(), true) . substr($mybb->post_code, 16)), 12, 8) . '_' . preg_replace('~[^a-zA-Z0-9_\\-%]~', '', str_replace(array(' ', '.', '+'), '_', $attachment['name'])) . '.upload'; $filename = 'file_' . ($prevattach['aid'] ? $prevattach['aid'] : 't' . TIME_NOW) . '_' . $basename; @ignore_user_abort(true); // don't let the user break this integrity between file system and DB if (isset($GLOBALS['xtfurl_tmpfiles'])) { // if using url fetch, remove this from list of temp files unset($GLOBALS['xtfurl_tmpfiles'][$attachment['tmp_name']]); } while (!@$movefunc($attachment['tmp_name'], $path . $month_dir . $filename)) { if ($month_dir) { // try doing it again without the month_dir $month_dir = ''; } else { // failed @ignore_user_abort(false); return array('error' => $lang->error_uploadfailed . $lang->error_uploadfailed_detail . $lang->error_uploadfailed_movefailed); } } // Lets just double check that it exists if (!file_exists($path . $month_dir . $filename)) { @ignore_user_abort(false); return array('error' => $lang->error_uploadfailed . $lang->error_uploadfailed_detail . $lang->error_uploadfailed_lost); } // Generate the array for the insert_query $attacharray = array('posthash' => $posthash, 'tid' => $tid, 'uid' => (int) $mybb->user['uid'], 'field' => $tf['field'], 'filename' => strval($attachment['name']), 'uploadmime' => strval($attachment['type']), 'filesize' => $file_size, 'attachname' => $basename, 'indir' => $month_dir, 'downloads' => 0, 'uploadtime' => $timestamp, 'updatetime' => $timestamp); if (isset($file_md5)) { $attacharray['md5hash'] = new xthreads_db_binary_value($file_md5); } else { $attacharray['md5hash'] = null; } if (!empty($img_dimensions)) { $origdimarray = array('w' => $img_dimensions[0], 'h' => $img_dimensions[1], 'type' => $img_dimensions[2]); $attacharray['thumbs'] = serialize(array('orig' => $origdimarray)); } if ($update_attachment) { unset($attacharray['downloads'], $attacharray['uploadtime']); //$attacharray['updatetime'] = TIME_NOW; xthreads_db_update('xtattachments', $attacharray, 'aid=' . $prevattach['aid']); $attacharray['aid'] = $prevattach['aid']; // and finally, delete old attachment xthreads_rm_attach_fs($prevattach); $new_file = $path . $month_dir . $filename; } else { $attacharray['aid'] = xthreads_db_insert('xtattachments', $attacharray); // now that we have the aid, move the file $new_file = $path . $month_dir . 'file_' . $attacharray['aid'] . '_' . $basename; @rename($path . $month_dir . $filename, $new_file); if (!file_exists($new_file)) { // oh dear, all our work for nothing... @unlink($path . $month_dir . $filename); $db->delete_query('xtattachments', 'aid=' . $attacharray['aid']); @ignore_user_abort(false); return array('error' => $lang->error_uploadfailed . $lang->error_uploadfailed_detail . $lang->error_uploadfailed_lost); } } @my_chmod($new_file, '0644'); @ignore_user_abort(false); if (!empty($img_dimensions) && !empty($tf['fileimgthumbs'])) { // generate thumbnails $attacharray['thumbs'] = xthreads_build_thumbnail($tf['fileimgthumbs'], $attacharray['aid'], $tf['field'], $new_file, $path, $month_dir, $img_dimensions); $attacharray['thumbs']['orig'] = $origdimarray; $attacharray['thumbs'] = serialize($attacharray['thumbs']); } return $attacharray; }
function xthreads_rm_attach_query($where) { global $db; $has_attach = $successes = 0; $query = $db->simple_select('xtattachments', 'aid,indir,attachname', $where); $rmaid = ''; while ($xta = $db->fetch_array($query)) { if (xthreads_rm_attach_fs($xta)) { if ($successes) { $rmaid .= ','; } $rmaid .= $xta['aid']; ++$successes; } ++$has_attach; } $db->free_result($query); if ($has_attach) { if ($has_attach == $successes) { $db->delete_query('xtattachments', $where); } elseif ($successes) { $db->delete_query('xtattachments', 'aid IN (' . $rmaid . ')'); } } return $successes; }