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_admin_rebuildthumbs() { global $mybb, $db; if ($mybb->request_method == 'post') { if (isset($mybb->input['do_rebuildxtathumbs'])) { $page = (int) $mybb->input['page']; if ($page < 1) { $page = 1; } $perpage = (int) $mybb->input['xtathumbs']; if (!$perpage) { $perpage = 500; } global $lang; if (!$lang->xthreads_rebuildxtathumbs_nofields) { $lang->load('xthreads'); } $thumbfields = xthreads_admin_getthumbfields(); if (empty($thumbfields)) { flash_message($lang->xthreads_rebuildxtathumbs_nofields, 'error'); admin_redirect(xthreads_admin_url('tools', 'recount_rebuild')); return; } $where = 'field IN ("' . implode('","', array_keys($thumbfields)) . '")'; // AND tid!=0 $num_xta = $db->fetch_field($db->simple_select('xtattachments', 'count(*) as n', $where), 'n'); @set_time_limit(1800); require_once MYBB_ROOT . 'inc/xthreads/xt_upload.php'; require_once MYBB_ROOT . 'inc/xthreads/xt_updatehooks.php'; include_once MYBB_ROOT . 'cache/xthreads_evalcache.php'; // for thumbnail code $xtadir = $mybb->settings['uploadspath'] . '/xthreads_ul/'; if ($xtadir[0] != '/') { $xtadir = '../' . $xtadir; } // TODO: perhaps check for absolute Windows paths as well? but then, who uses Windows on a production server? :> $query = $db->simple_select('xtattachments', '*', $where, array('order_by' => 'aid', 'limit' => $perpage, 'limit_start' => ($page - 1) * $perpage)); while ($xta = $db->fetch_array($query)) { // remove thumbs, then rebuild $name = xthreads_get_attach_path($xta); // unfortunately, we still need $xtadir if ($thumbs = @glob(substr($name, 0, -6) . '*.thumb')) { foreach ($thumbs as &$thumb) { @unlink($xtadir . $xta['indir'] . basename($thumb)); } } $thumb = xthreads_build_thumbnail($thumbfields[$xta['field']], $xta['aid'], $xta['field'], $name, $xtadir, $xta['indir']); // TODO: perhaps check for errors? but then, what to do? } $db->free_result($query); ++$page; check_proceed($num_xta, $page * $perpage, $page, $perpage, 'xtathumbs', 'do_rebuildxtathumbs', $lang->xthreads_rebuildxtathumbs_done); } } else { $GLOBALS['plugins']->add_hook('admin_formcontainer_end', 'xthreads_admin_rebuildthumbs_show'); } }