本书实战性很强,没有冗长的概念讲解,都是实际项目中使用的实用技术,比如验证码、文件上传、图像处理、调试、安全、缓存等。留言板、博客、论坛、微信公众平台开发4个实战项目案例,使读者尽快切入ThinkPHP企业级项目开发。
夏磊,目前从事软件开发工作。精通PHP服务器脚本语言技术,善于把握运用新技术,如LAMP&LNMP平台以及Node.js平台下Web软件的开发、软件架构、设计模式等。作者博客上大量的PHP相关技术文章,深受读者好评。
第 12 章
博客系统项目实战 ?
12.1 项目目的
本博客系统项目目的如下:
记载个人学习、工作、生活上一些值得回味的事情,以及一些值得分享或者探讨的技术。
用于社会沟通和交友,和他人分享自己的成功。
自我学习、自我提高。
12.2 需求分析
提到博客,大部分人都不会陌生,毕竟大名鼎鼎的wordpress可是业界神话。本章需要实现的也是一个博客系统。当然,并没有wordpress那么强大,不过“麻雀虽小、五脏俱全”,一个博客应有的功能还是需要有的。
写作。博客的核心功能就是写作,而且是独自写作,有写作就有文章,有文章就涉及文章的分类、发表、编辑、删除。
评论。既然项目目的中有“用于社会沟通和交友”,那么社会上的读者如何与作者互动呢?所以,评论功能必不可少。有了评论就需要发表评论、管理评论。
友情链接。好文章如何让别人知道呢?单凭自己的力量是不够的,所以合理地与他人交换友情链接是博客的一种推广手段。
12.3 功能设计
通过需求分析的结果,可以总结出博客系统需要以下功能:
? 管理员登录、修改密码、退出登录。
? 文章分类添加、编辑、删除。
? 文章添加、编辑、删除。
? 发表评论、管理评论。
? 添加友情链接、删除友情链接、展示友情链接。
12.4 数据库设计
根据需求分析以及功能设计,设计出如图12-1所示数据库模型。
图12-1
可以看到分类表、文章表、评论表之间存在关系。
12.5 数据库字典
1. 文章分类(blog_category)
文章分类表设计如表12-1所示。
表12-1
字段名称 类型 说明
categoryId int(10) 主键,自增
name varchar(20) 分类名称
isNav tinyint(1) 是否显示在导航栏
total int 文章总数
sort tinyint(4) 排序
2. 文章表(blog_article)
文章表设计如表12-2所示。
表12-2
字段名称 类型 说明
articleId int(11) 主键,自增
Title varchar(40) 文章标题
Description varchar(100) 文章简介
Image varchar(128) 文章封面
Hits int(11) 点击数
createdAt int(11) 文章发布时间(时间戳)
updateAt int(11) 文章更新时间
Status tinyint(1) 状态(发表,不发表)
Sort int 文章排序
Content text 文章正文
categoryId int 分类ID
3. 文章评论表(blog_comment)
文章评论表设计如表12-3所示。
表12-3
字段名称 字段类型 说明
commentId int 主键,自增
nickname varchar(20) 昵称
createdAt int(11) 评论时间
createdIp varchar(15) 评论IP(只考虑IPV4)
content text 评论内容
articleId int 文章ID
4. 管理员表(blog_admin)
管理员表设计如表12-4所示。
表12-4
字段名称 字段类型 说明
adminId int 管理员ID
username varchar(20) 用户名
password char(32) 密码(md5加密后密文)
createdAt int 账号添加时间
loginAt int *近登录时间
loginIp int *近登录IP
5. 友情链接表(blog_link)
友情链接表设计如表12-5所示。
表12-5
字段名称 字段类型 说明
linkId int 主键,自增
name varchar(20) 网站名称
link varchar(100) 链接地址
status tinyint(1) 状态
sort int 排序
12.6 模块设计
12.6.1 Admin模块
admin为后台管理模块,需要管理文章、分类、评论、友情链接等功能。所以根据功能应该分开4个Controller进行处理。Controller如下:
? ArticleController,文章控制器。
? CategoryController,分类控制器。
? CommentController,评论控制器。
? LinkController,友情链接控制器。
1. 权限检测
由于admin模块属于受保护的模块,所以以上4个控制器必须登录后才能正常访问,为了不写重复代码,需要新建一个控制器处理登录检测,以上4个控制器继承该基本控制器实现统一权限检测。
在Admin模块新建BaseController.class.php,添加_initialize方法,代码如下:
protected function _initialize()
{
if (session('admin.adminId') === null)
{
$this->error('请登录', U('admin/index/login'));
}
C('LAYOUT_NAME', 'admin');
}
需要进行权限检测的控制器继承BaseController即可。
2. 分页处理
由于该博客系统是一直在线上运行的,所以数据量不可预测,在列表页需要进行分页处理。以下是友情链接主页的分页代码:
public function index()
{
$model = new Model('Link');
$count = $model->count();
$page = new Page($count);
$show = $page->show();
$list = $model->order('linkId DESC')->limit($page->firstRow . ',' . $page->listRows)->select();
$this->assign('list', $list);
$this->assign('page', $show);
$this->display();
}
3. 文章-分类模型
文章是属于分类的,所以读取文章列表的时候需要将分类信息同时查询处理,这里使用ThinkPHP提供的ViewModel,在Common模块新建Model文件夹,在Model文件夹下新建ArticleCategoryViewModel.class.php,代码如下:
namespace Common\Model;
use Think\Model\ViewModel;
class ArticleCategoryViewModel extends ViewModel
{
public $viewFields = array(
'Article' => array('articleId', 'title', 'description', 'image', 'hits', 'createdAt', 'updateAt', 'status', 'sort', 'content'),
'Category' => array('categoryId', 'name', '_on' => 'Article.categoryId=Category.categoryId')
);
}
ViewModel的知识可以在第5章第9节查看。
4. 文件上传
在设计文章表的时候,有个封面字段,这个字段是用来保存文章封面的,所以需要做一个图片上传的功能。为了贯彻“模块化”的思想,笔者特地将上传模块抽象出来,只要在需要上传的页面include即可。
在Admin模块的View文件夹添加Common文件夹,在Common文件夹下添加upload.html,代码如下:
点击上传
该段代码与一般代码区别不大,但是重点在于:
uploadCallback && uploadCallback(data.url);
如果当前页面定义了uploadCallback函数,则将上传后的结果回调到该函数。
上传代码,编辑Admin模块下的Index控制器,添加upload方法,代码如下:
public function upload()
{
$upload = new Upload();// 实例化上传类
$upload->maxSize = 1024 * 1024 * 2;// 设置附件上传大小
$upload->exts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = __DIR__ . '/../../../upload/'; // 设置附件上传根目录
$upload->savePath = ''; // 设置附件上传(子)目录
// 上传文件
$info = $upload->upload();
if (!$info)
{
$this->ajaxReturn(array(
'error' => $upload->getError()
));
}
else
{
$path = $upload->rootPath . $info['file']['savepath'] . $info['file']['savename'];
$image = new Image();
$image->open($path);
$image->thumb(200, 200, Image::IMAGE_THUMB_CENTER)->save($path);
$this->ajaxReturn(array(
'url' => U('/', '', false, true) . 'upload/' . $info['file']['savepath'] . $info['file']['savename']
));
}
}
使用时直接使用以下代码引入即可(示例代码在Application/Admin/View/Article/post.html中):
由于回调函数已经写死了“uploadCallback”,所以目前来说该上传组件一个页面只能使用一个。
Admin模块比较重要的功能就是以上列出来的,其他功能基本上都是添加、编辑、列表、删除功能,由于篇幅关系这里不再赘述,有需要的读者可以前往github下载源码:
https://github.com/xialeistudio/thinkphp-inaction/tree/master/blog
12.6.2 Common模块
1. 分类处理
Common模块是公用模块,其他模块公用的功能可以放在该模块下,比如上文中的“文章-分类模型”就是公用Model,所以放在Common/Model下。
博客系统在设计文章分类时有“isNav”字段,该字段用来标识分类是否是导航栏中的分类,所以可以明确出来的需求有:
? 读取属于导航栏的分类(status为1)
? 读取不属于导航栏的分类(status为0)
? 读取全部分类
而以上需求返回值都是一致的,也就是分类列表,所以可以将以上三个需求封装成一个函数,根据传入的status来决定返回数据。
编辑Application/Common/Common/function.php,添加如下代码:
/**
* 获取分类
* @param int $isNav
* @return mixed
……