V4if 's Blogwebsite

Discuz_thought

发表于2016-08-22
默认

现在大部分网站后台程序都采用了Model-View-Control架构,数据、前端界面和逻辑控制相分离,开发速度更加高效。同时将动态页面静态化,部分程度上缓解了服务器的请求。本文主要是为了最近在Discuz系统上做的一个二次开发,然后写下自己对dz系统的理解。

相关概念

这也是我第一次接触Discuz系统,先说说我感触最深的两点,一是MVC架构,二是动态页面静态化。
我们先接触一下MVC框架是什么样子的,然后再去简单剖析一下Discuz系统的渲染流程。形象理解一下Model负责获取整理数据,View负责将取得的数据组织、美化,并最终向用户终端输出,而Controller主要作为一个M和V的桥梁,负责将M产生的数据交给V去显示。
整个工作流程如下图:
discuz_thought
实现了数据和模板视图的隔离,两者通过Controller进行连接。
接下来说一下PHP页面静态化,先看一下概念解释:

PHP静态化分为:纯静态化 和 伪静态化;纯静态化又分为:局部静态化 和 完全静态化

纯静态化:是把PHP生成的动态页面保存成静态的html文件,用户访问该静态页面,而不是用户每一次访问都重新生成一张相同的网页,优点就是减小服务器开销,
  局部静态化:是生成的静态文件中,有局部的数据还是通过ajax技术动态获取的;
  完全静态化:即不存在动态获取数据的情况,所以内容都来自静态的html页面

伪静态化:其实还是动态访问,其实质是动态生成数据,你访问的网址类似于http://yourhost.com/index/post/12,是一个静态地址,该地址多见于博客地址,但伪静态化中,你访问的网址实际上经过服务器解析,还是会解析成类似于http://yourhost.com/?c=index&a=post&id=12的地址,所以称之为伪静态化
  伪静态的优点:美观;便于搜索引擎收录

形象来说就是把不经常变动的数据一次动态获取之后写到静态的htm文件中,在允许的时间范围内就可以直接访问静态的htm文件,减小服务器的请求量,局部需要更新的数据可以采用ajax请求技术进行异步更新。

简单框架实现

这里简单实现了一个框架,代码目录结构如下:

/--
 -- cache/
     test_show_static.htm
 -- libs/
     -- Controller/
        testController.class.php
     -- Model/
        testModel.class.php
     -- View/
        testView.class.php
function.php
index.php
index_cache.php

/为html文件的根目录,cache目录下存储的是PHP页面静态化之后的静态htm文件,libs目录下是我们MVC架构的主要代码。
function.php放置一些常用函数,这里就简单实现了MVC分别对应的函数。
index.php没有PHP页面静态化的入口文件
index_cache.php添加了PHP页面静态化的入口文件
在框架下面写代码命名要非常规范,因为到底调用哪个控制器、数据、模板视图都是通过文件的名字去进行查找的,而且要放置在对应的目录下面。
到了该上代码的时间了orz,一个一个来贴吧。
test_show_static.htm这个文件是PHP页面静态化自动生成的htm数据。
testController.class.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 11:40:18
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 12:02:54
 */
class testController
{

    function show()
    {
        $testModel = M('test');
        $data = $testModel->get();

        $testView = V('test');
        $testView->display($data);
    }
}
?>

testModel.class.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 11:40:05
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 11:42:47
 */
class testModel
{
    function get()
    {
        return "v4if";
    }
}
?>

testView.class.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 11:39:50
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 11:43:51
 */
class testView
{
    function display($data)
    {
        echo $data;
    }
}
?>

function.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 11:45:38
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 14:55:46
 */

function C($name, $method)
{
    require_once('libs/Controller/'.$name.'Controller.class.php');
    eval('$obj = new '.$name.'Controller();$obj ->'.$method.'();');
}

function M($name)
{
    require_once('libs/Model/'.$name.'Model.class.php');
    eval('$obj = new '.$name.'Model();');
    return $obj;
}

function V($name)
{
    require_once('libs/View/'.$name.'View.class.php');
    eval('$obj = new '.$name.'View();');
    return $obj;
}
?>

index.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 11:38:33
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 14:54:09
 */

error_reporting(E_ALL);
ini_set('display_errors','On');

//url形式  index.php?c=控制器名&m=方法名
require_once('function.php');

$controller = $_GET['c'];
$method = $_GET['m'];

C($controller, $method);
?>

index_cache.php文件:

<?php
/**
 * @Author: v4if
 * @Date:   2016-08-31 15:06:23
 * @Last Modified by:   root
 * @Last Modified time: 2016-08-31 15:15:17
 */
error_reporting(E_ALL);
ini_set('display_errors','On');

//url形式  index.php?c=控制器名&m=方法名
$controller = $_GET['c'];
$method = $_GET['m'];

$static_tpl = 'cache/'.$controller.'_'.$method.'_static.htm';
if (is_file($static_tpl) && (time() - fileatime($static_tpl) < 1200)) {
    require_once($static_tpl);
} else {
    ob_start();
    require_once('function.php');
    C($controller, $method);
    $html = ob_get_contents();
    file_put_contents($static_tpl, $html);
}
?>

对Discuz的简单流程剖析

先列一下经常用到的几个比较重要的目录

/--
 -- data/             附件数据、数据库与文件缓存
 -- source/             程序模块功能处理目录
     -- module/         程序功能模块程序包
     -- function/         DX自定义函数库
     -- class/         核心类库
 -- template/            模板目录
 admin.php             后台入口文件
 forum.php             论坛频道入口文件
 index.php             首页
 portal.php             门户入口文件

上面基本上都是我们经常需要改动测试的目录或文件。
在安装Discuz系统的时候需要注意一下X3.2不兼容PHP7的版本,如果PHP环境是7.0及以上的,请从这里下载兼容版本 discuz-x32-php7。还有就是对Discuz根目录赋予可读可写权限,linux下可以通过执行chmod -R 777 /var/www/html命令即可。
接下来我们尝试跟踪一个具体的网址来看看Discuz的渲染流程,就以默认页面http://localhost/forum.php主页为例。
这里需要明确一点,Discuz的入口地址是index.php文件,forum.php文件是index.php通过重定向然后访问到的。
然后打开fourm.php文件我们可以看到结尾有这样一句话:
require DISCUZ_ROOT.'./source/module/forum/forum_'.$mod.'.php';
也就是说是通过传递进来的$mod参数决定我们将要调用的控制器页面,可以修改一下Discuz的源码,看看$mod参数具体是什么值,可以在require前面加一句echo $mod;将$mod的值输出到页面上,然后刷新页面可以看到输出的index
即接下来调用的是/source/module/forum/forum_index.php'文件,可以看到在forum_index.php文件的433行有一个template的模板调用
discuz_thought
继续跟踪下去我们可以找到template函数的声明文件,在/source/function/function_core.php文件的519行可以看到template函数的定义
discuz_thought
然后可以在template函数里面插入我们自己的输出语句,在function_core.php文件的630行插入echo 'v4if+'.$tplfile.'+v4if';语句,看看具体调用了哪些模板文件进行的页面渲染,然后刷新页面可以看到页面输出内容:

v4if+./template/default/forum/discuz.htm+v4if
v4if+./template/default/common/header.htm+v4if
v4if+./template/default/common/header_userstatus.htm+v4if
v4if+./template/default/member/login_simple.htm+v4if
v4if+./template/default/common/footer.htm+v4if

到这里之后具体调用了哪些模板文件就一目了然了,可以根据自己的业务需求对相应的php或者htm文件进行修改。