不积跬步无以至千里

记录精彩的程序人生

  • 首页
  • Java
  • Golang
  • PHP
  • Python
  • Nodejs
  • Lua
  • Docker
  • DevOps
  • 文章归档
  • 默认分类
  • 关于
  • 标签

  • 搜索
PostgreSQL hbase 时间同步 nexus 开机启动 nexus, 开机启动 jenkins安装配置 gitlab安装配置 gitlab安装 文件系统 fastdfs gcc切换 gcc升级 mysql8 交换空间 虚拟内存 tcp thrift lua tag test VPN SoftEtherVPN homebrew asm spring tomcat maven jdk ios mac 图案字符 figlet mysql半同步复制 mysql主从同步 一主多从 一主一从 主从同步 反向代理 密码重置 test 虚拟机扩容 swap 虚拟空间 docker ldocker grpc-gateway protobuf 微服务 go grp GRPC 授权登录 OAuth2.0 SOA supervisord supervisor RPC CentOS rabbitmq 环境变量 php-fpm php.ini error php7 lnmp 编译安装 mysql nginx linux java php python redis 字符串操作 mysql5.7 Solo

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

发表于 2020-03-23 | 分类于 默认分类 | 0 | 阅读次数 4739

许多使用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文件,可以看到最上方就是一句:

而最下方是

这两句的意思就是分别加载头部和尾部,而头部和尾部的模板就是header.htm和footer.htm,我们首先看一看header.htm

大家打开header.htm可以看到是经典的html文件格式。
第一句是DTD声明,在标准化页面里这是必须要的。

同时我们也可以看到在head标签内里有很多meta信息,meta信息是头文件,它用于传递给浏览器或者搜索引擎,其中这两句:

第一个是关键词,第二个是描述,在很多SEO教程里,大家都会对这个花很大的心思,他是蜘蛛们最容易获取的信息,也是SEO优化所必须考虑的。
$rsshead
$extrahead

在上面的一行代码里,$rsshead是rss头信息,$extrahead是额外的头部信息,这个可以在论坛后台的全局,搜索优化里填写。
而下面的
是获取CSS信息,所有的样式都在这里面定义了。
我们打开css_script.htm文件,可以发现它首先加载了
@import url(forumdata/cache/style_
_common.css?);

这个可以很清楚的看到,它调用了一个css文件,这个css文件是存在于forumdata/cache/文件夹下的,它是一个缓存文件,而根据 的不同,这些文件也不同,比如一个风格的STYLEID为5,那么它调用的就是style_5_common.css这个css样式, 而后面的是产生一个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?
"></script>

这个include/js/common.js就是常用的JavaScript代码,我们常使用的是:浮动窗口,样式改变,列表下滑,按ALT+S或者CTRL+ENTER快捷回复等等一系列的js控制。

body标签开始,就是真正显示在浏览器的内容,因为discuz是标准化的页面,用div+css规划页面的,所以可以看到很多div标签,是用来对页面的各个元素进行样式定义。
首先就是logo信息了,

$indexname是点击logo所返回的页面,title是把鼠标放到logo上所显示的文字,而则是logo的图片,一般在后台定义。

下面的注意这一句:

前面说了,这个是代表着已经登录,所以它后面的代码就是登录后显示的内容,分别是用户名 | 我的帖子 空间 短消息 论坛任务 | 个人中心 退出 这些字。

大家看不到汉字,是因为这里面的汉字也是使用函数替换的,它们被集合起来,称为语言包,大家可以在template.lang.php里找到这些文字,分别与这里面一一对应。

而在未登录的时候,你只能看到登录 | 注册 这两个词,所以后面的else就是这些内容,其中还有一种比较特殊的情况是,未登录,但是cookie里面有登录信息,这样的情况下,会显示登录 | 退出,点击登录可以直接登录,退出则是清空cookie

再下面的是广告banner,一般是在页面的右上方,可以在后台添加。

再下面的就是关于分栏模式,这个开启了以后和天涯等类似,在左边会有一个长框,版块都会放在那条框里,这是针对于版块数目较多的论坛而设立的,一般不必开启它。

下面的是导航栏和风格切换按钮,导航栏因为是在后台设定的,存放到数据库的,所以在这里就是一些变量,它采用循环来让这些变量逐一展现出来。
好,我们说完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! 论坛官方 » 首页,这个是在首页的上方。

下面就是广告显示,如果有广告就会提前出现。

然后是论坛的边栏显示,根据边栏的开启来判断页面宽度。

在论坛的首页公告显示区上方的是,那个大的发帖按钮,以及欢迎信息,它对应的代码就是

{$discuz_userss}, {$lastvisit},

这些lang函数把这串英文字母替换成语言包里的汉字或其它语言。

公告区的右方是发帖量等信息的现实,比如是这样:
今日: 3637, 昨日: 7808, 会员: 1004553

它对应的就是
: $todayposts, : $postdata[0], : $totalmembers

在公告区的下方就是版块列表区,这些版块的排列是用css控制的,而版块也是使用循环显示出来的。
这些标签和元素比较多,不过大家可以看到table标签,这是使用表格来规划版块里面的信息显示,比如版块名,版块简介,版块发帖量等等,为了让它们工整对齐,所以使用无边框的表格来排版。

因为有横排的板块,所以两种不同的显示在discuz.htm里表现出来,这里就不多说了。

最下面的是友情链接,有的人会奇怪,友情链接为什么如此简单,其实友情链接因为存放在数据库里,而且每访问一次主页,它都要显示出来,并且它的变化不频繁,不会每秒都会变化,所以它是利用数据缓存,把生成好的数据放在缓存文件里,然后用$_DCACHE来使用它。

生成缓存的函数可以在include/cache.func.php里找到。

最下面的是在线人数,我们之前在index.php里获取了在线人数的值,在这里我们可以把它展现出来。

综上所说,一个完整的页面所涉及到的文件其实是非常多的,所使用的技术也非常多。

其中模板分离技术(类似smarty技术)是很重要的,它让htm里可以使用、这类来代替和这类真正的php语言,从而让代码看上去简单许多,又可以让语言包从中分离出来,大家可以轻易的改变语言。

DISCUZ模板编译原理
Discuz7X默认模板的目录文件结构
  • 文章目录
  • 站点概览
ken

ken

记录精彩的程序人生

498 日志
9 分类
77 标签
RSS
Creative Commons
Links
  • 酷壳
0%
© 2010 — 2025 ken
由 Halo 强力驱动
鄂ICP备18013899号-1