【思路解析】discuz 帖子设置封面 setthreadcover 表pre_forum_threadimage
在Discuz 中有一项就是给帖子设置封面,很多情况下只能通过手动的方式去设置或者用提交POST请求的式去设置; 但是这都是调用DISCUZ的功能设置的; 有的时候并非万能的,也有用不到的时候;下面就给大家讲一下DISCUZ在设计封面的设计思路; 知道了思路,就可以自己用代码去实现;
好开始:
在设置了封面后,会在 pre_forum_threadimage 中插入一条这样的数据;
tid 是贴子的ID 后面的是对应的附件的地址;
在点击设置封面的时候会看到,程序会请求一个地址如下图
对是他:
http://localhost/dz/forum.php?mod=ajax&action=setthreadcover&aid=1&fid=36&infloat=yes&handlekey=setcover1&inajax=1&ajaxtarget=fwin_content_setcover1
在这个请求的连接中对我们重要的有 mod /action/fid/aid这几个参数; 请求的是Forum.php 那我们去找。
在Forum.php的最后,我们发现了下面一句代码:
require DISCUZ_ROOT.'./source/module/forum/forum_'.$mod.'.php';
根据这句代码和请求参数,我们找到了:source/module/forum/forum_ajax.php 这个文件,并在里面找到了setthreadcover的处理代码如下:
elseif($_GET['action'] == 'setthreadcover') { $aid = intval($_GET['aid']); $imgurl = $_GET['imgurl']; require_once libfile('function/post'); if($_G['forum'] && ($aid || $imgurl)) { if($imgurl) { $tid = intval($_GET['tid']); $pid = intval($_GET['pid']); } else { $threadimage = C::t('forum_attachment_n')->fetch('aid:'.$aid, $aid); $tid = $threadimage['tid']; $pid = $threadimage['pid']; } if($tid && $pid) { $thread =get_thread_by_tid($tid); } else { $thread = array(); } if(empty($thread) || (!$_G['forum']['ismoderator'] && $_G['uid'] != $thread['authorid'])) { if($_GET['newthread']) { showmessage('set_cover_faild', '', array(), array('msgtype' => 3)); } else { showmessage('set_cover_faild', '', array(), array('closetime' => 3)); } } if(setthreadcover($pid, $tid, $aid, 0, $imgurl)) { if(empty($imgurl)) { C::t('forum_threadimage')->delete_by_tid($threadimage['tid']); C::t('forum_threadimage')->insert(array( 'tid' => $threadimage['tid'], 'attachment' => $threadimage['attachment'], 'remote' => $threadimage['remote'], )); } if($_GET['newthread']) { showmessage('set_cover_succeed', '', array(), array('msgtype' => 3)); } else { showmessage('set_cover_succeed', '', array(), array('alert' => 'right', 'closetime' => 1)); } } } if($_GET['newthread']) { showmessage('set_cover_faild', '', array(), array('msgtype' => 3)); } else { showmessage('set_cover_faild', '', array(), array('closetime' => 3)); } }
在这一段代码中,最重要的一段代码是:if(setthreadcover($pid, $tid, $aid, 0, $imgurl)) 不用看下面的代码怎么处理的,但是我们可以猜到在调用过setthreadcover 这个函数之后,封面已经设置完成了;
那setthreadcover 这个函数到底在哪呢?我也找也半天,最后终于在:source/function/function_post.php 这个文件里找到了它,代码如下:
function setthreadcover($pid, $tid = 0, $aid = 0, $countimg = 0, $imgurl = '') { global $_G; $cover = 0; if(empty($_G['uid']) || !intval($_G['setting']['forumpicstyle']['thumbheight']) || !intval($_G['setting']['forumpicstyle']['thumbwidth'])) { return false; } if(($pid || $aid) && empty($countimg)) { if(empty($imgurl)) { if($aid) { $attachtable = 'aid:'.$aid; $attach = C::t('forum_attachment_n')->fetch('aid:'.$aid, $aid, array(1, -1)); } else { $attachtable = 'pid:'.$pid; $attach = C::t('forum_attachment_n')->fetch_max_image('pid:'.$pid, 'pid', $pid); } if(!$attach) { return false; } if(empty($_G['forum']['ismoderator']) && $_G['uid'] != $attach['uid']) { return false; } $pid = empty($pid) ? $attach['pid'] : $pid; $tid = empty($tid) ? $attach['tid'] : $tid; $picsource = ($attach['remote'] ? $_G['setting']['ftp']['attachurl'] : $_G['setting']['attachurl']).'forum/'.$attach['attachment']; } else { $attachtable = 'pid:'.$pid; $picsource = $imgurl; } $basedir = !$_G['setting']['attachdir'] ? (DISCUZ_ROOT.'./data/attachment/') : $_G['setting']['attachdir']; $coverdir = 'threadcover/'.substr(md5($tid), 0, 2).'/'.substr(md5($tid), 2, 2).'/'; dmkdir($basedir.'./forum/'.$coverdir); require_once libfile('class/image'); $image = new image(); if($image->Thumb($picsource, 'forum/'.$coverdir.$tid.'.jpg', $_G['setting']['forumpicstyle']['thumbwidth'], $_G['setting']['forumpicstyle']['thumbheight'], 2)) { $remote = ''; if(getglobal('setting/ftp/on')) { if(ftpcmd('upload', 'forum/'.$coverdir.$tid.'.jpg')) { $remote = '-'; } } $cover = C::t('forum_attachment_n')->count_image_by_id($attachtable, 'pid', $pid); if($imgurl && empty($cover)) { $cover = 1; } $cover = $remote.$cover; } else { return false; } } if($countimg) { if(empty($cover)) { $thread = C::t('forum_thread')->fetch($tid); $oldcover = $thread['cover']; $cover = C::t('forum_attachment_n')->count_image_by_id('tid:'.$tid, 'pid', $pid); if($cover) { $cover = $oldcover < 0 ? '-'.$cover : $cover; } } } if($cover) { C::t('forum_thread')->update($tid, array('cover' => $cover)); return true; } }
整个这个函数就是处理设置封面的处理函数,处理过程不过多解释,只讲思路,在这个函数中有一句重要的代码是这样的:
if(ftpcmd('upload', 'forum/'.$coverdir.$tid.'.jpg')) {
在查看封面请求地址的时候,会感觉到封面缩略图存放的地址很怪异如下:
c4/ca? 看起来是随机的,与上面提到的封面数据库存储的完全不一样,到底是怎么样对应上的呢;
那我们还得看上面我们提到的函数 setthreadcover 了,上面我们说if(ftpcmd('upload', 'forum/'.$coverdir.$tid.'.jpg')) { //这句代码很重要
ftpcmd 这个什么作用,看到后面的upload我们有理由猜到,这句代码是实现的是一个上传图片的操作; 那能在这个函数里面处理的,肯定是上传缩略图到新的路径了。
那路径在哪呢 'forum/'.$coverdir.$tid.' //对就是后面这一句就是上传的路径。
$tid 不用说,那肯定是贴子的ID也就是这个封面图的文件名;至于 $coverdir 这个我们不难发现,这个就是路径,通过这个我们往上找;找到了这段代码:
$coverdir = 'threadcover/'.substr(md5($tid), 0, 2).'/'.substr(md5($tid), 2, 2).'/';
到此就真相大白了,他生成目录的方式是截取$tid MD5加密后的前两位作为一个目录和第三、四位做了一个目录;为了证明我们的猜测,做如下比较:
再看我们的目录:
完全稳合,知道了DISCUZ的设置思路,那我们就算以后自己给自己的论坛开接口的时候就可以用程序的试实现自动发贴并设置封面了。
总结:很明显DISCUZ使用了新建目录的方式用来存放贴子的封面,不知道他们为何会这么设计 ,感觉很蛋疼,个人认为完全没必要;