discuz的模板制做与源代码分析

各位网友,你们好!我是德阳热线论坛管理员(http://www.dyrx.net)欢迎你们到我站看看,许多使用discuz的人都会天然的想到论坛的风格、样式和模板,如何修改它,如何让它符合心中的要求,相信你们只要对discuz的模板源代码进行钻研的话,那就确定可以本身独立修改,而且达到本身想要的风格和样式。          可是discuz的源代码极为精简,并且无注释,采用的方法多变,对象、函数等等都不易理解,无疑让你们对模板源代码头痛不已。          俗语说得好,授人以鱼不如授人以渔,我在这里不讲如局具体修改什么,而是讲一讲discuz模板的工做原理和源代码的拆开。          说到模板风格,你们天然想到的就是templates文件夹下的default模板,这里面的文件众多,它是discuz的默认模板。          在这个文件夹里的模板文件不少,最常使用到的,好比说header.htm和footer.htm两个文件,它们分别是论坛的头部和底部,在其它模板里都必须调用这两个文件,是以你们能够看到,在论坛的全部页面里,头部和底部都是相同的。          论坛最多见的三个页面,一个是主页,也就是一般的index.php,还有是主题列表页,以及帖子内容页,下面以index.php来说述discuz模板的原理以及它牵扯到的文件。          首先咱们打开index.php,在这个文件的开头是discuz做者的声明。          而后就是               //定义页面     define('CURSCRIPT', 'index');     //包含common文件和forum函数库     require_once './include/common.inc.php';     require_once DISCUZ_ROOT.'./include/forum.func.php';               你们能够看到这里很重要的两句,就是使用require_once函数来包含两个文件,在common.inc.php里存放的是一些经常使用数据,而在forum.func.php里存放的是有关版块的函数,把这些分离开来单独做为一个文件,是由于这些东西会在多个文件里使用,是觉得了循环利用以及代码的精简性,他们被放在一个单独的文件里。          调用了common.inc.php文件之后,咱们就能够直接在本页面使用其中的变量了,下面的这几句:          //判断页面情况,包括:页面缓存、是否登陆、是否开启了左右分栏等等     if($cacheindexlife && !$discuz_uid && $showoldetails != 'yes' && (!$_DCACHE['settings']['frameon'] || $_DCACHE['settings']['frameon'] && $_GET['frameon'] != 'yes') && empty($gid)) {……}               在这个if大括号里咱们能够看到许多变量,这些变量的值从何而来,就是从common.inc.php里来的,而这个大括号里分别判断页面的各类情况,而且对其进行处理,特别要说的是$discuz_uid这个变量,它表示的是访问者的uid,若是未登陆就是0,因此你们可使用if(!$dicuz){……}来判断用户是否登陆。          后面的也是进行一些判断,咱们直接到第42行,能够看到这里有了一些新变量,他们都是时间的变量。          //第一个变量里的gmdate是返回一个格式化的时间,里面须要指定格式和timestamp格式的时间,timestamp格式就是一连串的×××数字,表明着从格林威治时间1970年1月1日凌晨0点到规定时间的秒数。     $currenttime = gmdate($timeformat, $timestamp + $timeoffset * 3600);     //下面这个变量是把上次访问时间(timestmp格式)格式化成咱们能够明白的时间格式     $lastvisittime = dgmdate("$dateformat $timeformat", $lastvisit + $timeoffset * 3600);               在第一个函数里,gmdate函数后面的($timestamp+$timeoffset*3600)这个$timestamp是返回如今的时间,然后面的$timeoffset倒是时区,由于统一使用格林威治时间,因此要补上时区,这样才能正确显示咱们的时间。          而第二个函数dgmdate不是php自带的,而是discuz里的函数,它存在于何处?并非在forum.func.php里,而是在common.inc.php里面,由于common.inc.php里包含了一个discuz的全局函数库——global.func.php,这个函数库几乎全部页面都会用到,但不须要在页面指定调用,由于在common.inc.php里已经包含了它。          dgmdate也是像gmdate那样格式化一个timestamp的时间,可是它更为强大,更为人性化的时间格式,咱们日常看到的几分钟之前或者几天之前那样的格式就是经过它来转换的,而timestamp只能返回XX年X月X日这种格式的          他们下面的是:          //这个是把用户名转换成非汉字     $memberenc = rawurlencode($lastmember);     //取整时间     $newthreads = round(($timestamp - $lastvisit + 600) / 1000) * 1000;               rawurlencode函数把用户名转换成一串字符,主要是针对汉字或者特殊字符的,好比说     http://www.discuz.net/space.php?username=%B0%B2%B5%D1     %B0%B2%B5%D1这个是用十六进制来表示字符,一个汉字两个字符,使用这个函数把汉字或者特殊字符转换成能够用url传送的字符。          //先定义主题、帖子、今日发帖、版块、短消息数的变量     $threads = $posts = $todayposts = $fids = $announcepm = 0;     //定义发帖数量     $postdata = $historyposts ? explode("\t", $historyposts) : array();               上面的$historyposts是一个字符串,你们能够在cdb_setting数据表里找到它,它存放着两个数据,一个是昨日发帖,一个是历史最高发帖,explode是用来拆分这个字符串而且返回一个数组,若是这个$historyposts变量不存在的话就返回一个空数组,因此$postdata是一个明肯定义的数组。          咱们往下面跳着看,在97行有一个这样的字符串变量:     $sql = !empty($accessmasks) ?      "SELECT f.fid, f.fup, f.type, f.name, f.threads, f.posts, f.todayposts, f.lastpost, f.inheritedmod, f.forumcolumns, f.simple, ff.description, ff.moderators, ff.icon, ff.viewperm, ff.redirect, a.allowview FROM {$tablepre}forums f      LEFT JOIN {$tablepre}forumfields ff ON ff.fid=f.fid      LEFT JOIN {$tablepre}access a ON a.uid='$discuz_uid' AND a.fid=f.fid      WHERE f.status>0 ORDER BY f.type, f.displayorder"      : "SELECT f.fid, f.fup, f.type, f.name, f.threads, f.posts, f.todayposts, f.lastpost, f.inheritedmod, f.forumcolumns, f.simple, ff.description, ff.moderators, ff.icon, ff.viewperm, ff.redirect FROM {$tablepre}forums f      LEFT JOIN {$tablepre}forumfields ff USING(fid)      WHERE f.status>0 ORDER BY f.type, f.displayorder";               这个变量一样使用? :来选择不一样字符串的,你们能够看到,这是一串SQL代码,他们是在cdb_forumfields和cdb_access查找数据,其中cdb_forumfields表存放着版块的各类信息,好比说版块简介,版块图标,访问密码等等,而cdb_access是针对我的的访问控制,好比已经限制了某人访问某个版块,那么就会记录在这张表里,SQL查询就会用到它。          在后面的$query = $db->query($sql); 以及$db->fetch_array($query)等等,这些都是PHP里的对象使用方法,其中$db是一个大对象,而query和fetch_array等都是这个对象的方法函数,这些具体的对象都存放在include/db_mysql.class.php文件夹下,一样,它是在common.inc.php里调用过的,因此在这个页面上能够直接使用。          在这个class文件里,把对于mysql的大多数使用方法都整合成了一个对象包,使用起来极大的方便。               根据上面SQL查询到的信息,咱们获得了许多值,而后再进行对比和判断,从而返回不一样的变量,这些都是版块的信息,咱们就很少看了。               直接跳到180行,咱们能够看到这个是在线人数的统计,由于每个访问的用户,会注册一个session,因此返回全部的session就能够知道在线用户有多少,在$onlinerecord里存放的是最高在线,若是在线人数超过这个数字的话,会自动把新的最高在线存放到数据库里。               在index.php的最后,是     include template('discuz');               它是index.php可以显示的基础。          你们想必已经看到,在index.php里,全都是对变量进行处理,没有一个显示出来的,如何能让这些不一样的变量按照格式显示出来呢?这就须要调用xhtml来完成,通常的php页面会直接含有html文件,也就是把php代码穿插到html里,可是这样以来会让代码可读性下降,维护起来困难许多。          如今比较流行一种叫smarty技术,也就是模板技术,它把xhtml和php分开,这就是所谓的逻辑层与表现层之间的分离,这种方法让前台设计师们更容易表现本身,他们能够没必要彻底精通php,但同样能够作出精美的页面。          dz并非直接使用smarty,而是本身创造了一个小库,你们能够在template.func.php看到dz如何使用文件缓存配合模板。          当你访问一个页面时候,实际上访问的是php页面,在php页面里会有include函数,它用来包含一个显示出来的页面,也就是一般意义上的模板,不过dz采用类smarty技术,因此会使用include template('discuz');这样的语句调用页面。          而后根据用户使用的风格来找到styleid,存储到session和cookie里,而后返回给服务器端,服务器端经过这个来搜索styleid找到制定的缓存文件,若是有的话直接返回文件显示,若是没有的话,就会从新创建,会查找styleid指向的那个模板文件夹,若是里面含有这个模板文件,那么就作成缓存,而若是在这个文件夹里找不到莫个模板文件,好比找不到discuz.htm文件,函数才会去搜default文件,若是在这个文件夹里找到了,就直接作成缓存文件。          php端而后调用缓存文件显示出来,因此并非同时搜索default文件夹和模板文件夹,通常来讲,若是一个模版文件夹里包含全部模板页面,转换成缓存页面的速度是最快的。     咱们下面说说index.php调用的模板页面——discuz.htm          你们打开discuz.htm文件,能够看到最上方就是一句:     {subtemplate header}               而最下方是     {subtemplate footer}               这两句的意思就是分别加载头部和尾部,而头部和尾部的模板就是header.htm和footer.htm,咱们首先看一看header.htm          你们打开header.htm能够看到是经典的html文件格式。     第一句是DTD声明,在标准化页面里这是必需要的。          同时咱们也能够看到在head标签内里有不少meta信息,meta信息是头文件,它用于传递给浏览器或者搜索引擎,其中这两句:                         第一个是关键词,第二个是描述,在不少SEO教程里,你们都会对这个花很大的心思,他是蜘蛛们最容易获取的信息,也是SEO优化所必须考虑的。     $rsshead     $extrahead     {subtemplate css_script}               在上面的一行代码里,$rsshead是rss头信息,$extrahead是额外的头部信息,这个能够在论坛后台的全局,搜索优化里填写。     而下面的{subtemplate css_script}是获取CSS信息,全部的样式都在这里面定义了。     咱们打开css_script.htm文件,能够发现它首先加载了     @import url(forumdata/cache/style_{STYLEID}_common.css?{VERHASH});               这个能够很清楚的看到,它调用了一个css文件,这个css文件是存在于forumdata/cache/文件夹下的,它是一个缓存文件,而根据{STYLEID}的不一样,这些文件也不一样,好比一个风格的STYLEID为5,那么它调用的就是style_5_common.css这个css样式,然后面的{VERHASH}是产生一个hash数,这个hash数用来对文件进行hash校检,每次更新模板缓存后产生的hash值都不同,这样有不少好处。     你们可能会询问,为什么会生成一个style_5_common.css的样式文件呢?它里面的内容又是什么呢?          这里面的内容其实根据两个方面来的:     1.css_common.htm     2.论坛后台设定的风格,好比字体颜色、背景图片等等          由于discuz采用了风格标签的方法,把一些常见的标签放到后台里,能够很容易让你们修改,而这些值会传递给缓存函数,在style_5_common.css里就会使用这些标签来控制样式。          在css_script.htm里还有一些经常使用的css样式,这些都会被header.htm文件选择性的调用。          回到header.htm里,咱们能够看到下面有一段JavaScript代码,这个是控制风格切换以及风格切换时的cookie做用域。          在head标签的结束前,是一段JS的调用     <script type="text/javascript" src="include/js/common.js?{VERHASH}"></script>               这个include/js/common.js就是经常使用的JavaScript代码,咱们常使用的是:浮动窗口,样式改变,列表下滑,按ALT+S或者CTRL+ENTER快捷回复等等一系列的js控制。          body标签开始,就是真正显示在浏览器的内容,由于discuz是标准化的页面,用div+css规划页面的,因此能够看到不少div标签,是用来对页面的各个元素进行样式定义。     首先就是logo信息了,        {BOARDLOGO}                  $indexname是点击logo所返回的页面,title是把鼠标放到logo上所显示的文字,而{BOARDLOGO}则是logo的图片,通常在后台定义。          下面的注意这一句:                    前面说了,这个是表明着已经登陆,因此它后面的代码就是登陆后显示的内容,分别是用户名 | 个人帖子 空间 短消息 论坛任务 | 我的中心 退出 这些字。          你们看不到汉字,是由于这里面的汉字也是使用函数替换的,它们被集合起来,称为语言包,你们能够在template.lang.php里找到这些文字,分别与这里面一一对应。          而在未登陆的时候,你只能看到登陆 | 注册 这两个词,因此后面的else就是这些内容,其中还有一种比较特殊的状况是,未登陆,可是cookie里面有登陆信息,这样的状况下,会显示登陆 | 退出,点击登陆能够直接登陆,退出则是清空cookie               再下面的是广告banner,通常是在页面的右上方,能够在后台添加。          再下面的就是关于分栏模式,这个开启了之后和天涯等相似,在左边会有一个长框,版块都会放在那条框里,这是针对于版块数目较多的论坛而设立的,通常没必要开启它。          下面的是导航栏和风格切换按钮,导航栏由于是在后台设定的,存放到数据库的,因此在这里就是一些变量,它采用循环{loop}来让这些变量逐一展示出来。     好,咱们说完header.htm,再说说footer.htm文件,这个是底部信息,开始的是底部广告,这个能够在后台设定,而下面的是这种经常使用连接(站点全称,站点备案信息,站点邮箱,论坛统计以及Archiver以及WAP统计)     Comsenz Technology Ltd ( 京ICP备05079575号)|联系咱们 |论坛统计|Archiver|WAP          在它旁边是第三方统计代码,你们能够在论坛后台的全局,论坛功能里添加这个第三方统计代码,好比雅虎统计等等。     而这个     !--{if debuginfo()}-->, Processed in $debuginfo[time] second(s), $debuginfo[queries] queries, Gzip enabled.               它是表示论坛执行秒数,这个在你打开页面的刚开始,也就是调用common.inc.php时记录一个开始时间,而在你打开页面之后又记录一个结束时间,这个$debuginfo[queries]就是二者的差,后面的是gzip是否开启的信息,GZIP是压缩传送,通常是不开启的,能够在论坛后台开启它。          再下面就是论坛底部的右边信息,也就是版权信息        Powered by Discuz! $version Licensed              © 2001-2009 Comsenz Inc.                     这个显示结果就是     Powered by Discuz! 7.0.0          © 2001-2009 Comsenz Inc.          版权信息是discuz所看重的,discuz做为开发者,提供这么一个程序,底部版权声明是必须保留的,你们能够参考康盛的协议声明,不要擅自修改版权文字。     再下面的那些代码,是开启了分栏模式的,而最后的那个代码,是discuz把feed事件传送给uchome的JavaScript代码。     看完footer.htm,咱们转过头来讲说discuz.htm文件,这个就是使用index.php里的值来组织成一个首页页面。               能够看到,它分红许多个div块,并且div快里嵌套着div,在刚开始的是相似于这种Discuz! 论坛官方 » 首页,这个是在首页的上方。          下面就是广告显示,若是有广告就会提早出现。          而后是论坛的边栏显示,根据边栏的开启来判断页面宽度。               在论坛的首页公告显示区上方的是,那个大的发帖按钮,以及欢迎信息,它对应的代码就是           {lang home_welcome_guest}           {lang home_welcome} {$discuz_userss}, {lang home_lastvisit} {$lastvisit},               这些lang函数把这串英文字母替换成语言包里的汉字或其它语言。          公告区的右方是发帖量等信息的现实,好比是这样:     今日: 3637, 昨日: 7808, 会员: 1004553          它对应的就是     {lang index_today}: $todayposts, {lang index_yesterday}: $postdata[0], {lang index_members}: $totalmembers               在公告区的下方就是版块列表区,这些版块的排列是用css控制的,而版块也是使用{loop}循环显示出来的。     这些标签和元素比较多,不过你们能够看到table标签,这是使用表格来规划版块里面的信息显示,好比版块名,版块简介,版块发帖量等等,为了让它们工整对齐,因此使用无边框的表格来排版。          由于有横排的板块,因此两种不一样的显示在discuz.htm里表现出来,这里就很少说了。          最下面的是友情连接,有的人会奇怪,友情连接为何如此简单,其实友情连接由于存放在数据库里,并且每访问一次主页,它都要显示出来,而且它的变化不频繁,不会每秒都会变化,因此它是利用数据缓存,把生成好的数据放在缓存文件里,而后用$_DCACHE来使用它。          生成缓存的函数能够在include/cache.func.php里找到。          最下面的是在线人数,咱们以前在index.php里获取了在线人数的值,在这里咱们能够把它展示出来。          综上所说,一个完整的页面所涉及到的文件实际上是很是多的,所使用的技术也很是多。          其中模板分离技术(相似smarty技术)是很重要的,它让htm里可使用{if}、{loop}这类来代替和这类真正的php语言,从而让代码看上去简单许多,又可让语言包从中分离出来,你们能够轻易的改变语言。