ThinkPHP 6.0企业级CMS开发实战:从入门到精通 | PHP框架教程

2025-08-23 0 349

发布日期: 2023年12月15日

作者: ThinkPHP开发专家

ThinkPHP 6.0简介与新特性

ThinkPHP是一款国内领先的PHP开源框架,6.0版本在之前版本的基础上进行了全面重构,引入了更多现代化特性:

  • 完全支持PHP 7.1+特性
  • 采用更加严谨的PSR规范
  • 引入中间件机制替代原有的行为扩展
  • 依赖注入和支持更加完善
  • 改进了数据库查询和模型功能
  • 提供了更强大的命令行工具

本教程将通过开发一个完整的企业级内容管理系统(CMS),深入讲解ThinkPHP 6.0的核心功能和最佳实践。

环境搭建与项目初始化

环境要求

PHP >= 7.1.0
PDO PHP Extension
MBstring PHP Extension
JSON PHP Extension
Composer
                

使用Composer创建项目

# 创建ThinkPHP项目
composer create-project topthink/think tp-cms

# 进入项目目录
cd tp-cms

# 启动内置服务器
php think run
                

基础配置修改

修改config目录下的配置文件:

// config/database.php 数据库配置
return [
    'default'     => 'mysql',
    'connections' => [
        'mysql' => [
            'type'     => 'mysql',
            'hostname' => '127.0.0.1',
            'database' => 'tp_cms',
            'username' => 'root',
            'password' => 'password',
            'charset'  => 'utf8mb4',
            'prefix'   => 'cms_',
        ],
    ],
];

// config/app.php 应用配置
return [
    'app_debug'              => true,
    'default_lang'           => 'zh-cn',
    'default_timezone'       => 'Asia/Shanghai',
    'url_html_suffix'        => 'html',
];
                

系统架构设计

目录结构规划

tp-cms/
├── app/                    # 应用目录
│   ├── controller/         # 控制器层
│   │   ├── admin/          # 后台控制器
│   │   └── home/           # 前台控制器
│   ├── model/              # 模型层
│   │   ├── admin/          # 后台模型
│   │   └── home/           # 前台模型
│   ├── view/               # 视图层
│   │   ├── admin/          # 后台模板
│   │   └── home/           # 前台模板
│   └── middleware/         # 中间件
├── config/                 # 配置目录
├── public/                 # web入口目录
├── route/                  # 路由定义
├── database/               # 数据库文件
└── extend/                 # 扩展类库
                

多应用模式配置

ThinkPHP 6.0支持多应用模式,我们需要创建后台管理应用:

# 安装多应用扩展
composer require topthink/think-multi-app

# 创建admin应用目录结构
php think build admin
                

路由规划

// route/app.php
use thinkfacadeRoute;

// 前台路由
Route::get('/', 'home/Index/index');
Route::get('article/:id', 'home/Article/detail');
Route::get('category/:id', 'home/Category/index');

// 后台路由组
Route::group('admin', function() {
    Route::get('/', 'admin/Index/index');
    Route::get('login', 'admin/Login/index');
    Route::post('login', 'admin/Login/check');
})->prefix('admin/');
                

数据库设计与模型实现

数据库表设计

// 用户表
CREATE TABLE `cms_user` (
  `id` int(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
  `password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
  `email` varchar(100) NOT NULL DEFAULT '' COMMENT '邮箱',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',
  `create_time` int(11) NOT NULL DEFAULT '0',
  `update_time` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

// 文章表
CREATE TABLE `cms_article` (
  `id` int(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `category_id` int(11) NOT NULL DEFAULT '0' COMMENT '分类ID',
  `title` varchar(255) NOT NULL DEFAULT '' COMMENT '标题',
  `content` text COMMENT '内容',
  `author` varchar(50) NOT NULL DEFAULT '' COMMENT '作者',
  `keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键词',
  `description` varchar(500) NOT NULL DEFAULT '' COMMENT '描述',
  `thumb` varchar(255) NOT NULL DEFAULT '' COMMENT '缩略图',
  `views` int(11) NOT NULL DEFAULT '0' COMMENT '浏览量',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',
  `create_time` int(11) NOT NULL DEFAULT '0',
  `update_time` int(11) NOT NULL DEFAULT '0',
  `publish_time` int(11) NOT NULL DEFAULT '0' COMMENT '发布时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';

// 分类表
CREATE TABLE `cms_category` (
  `id` int(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '' COMMENT '分类名称',
  `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父级ID',
  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',
  `create_time` int(11) NOT NULL DEFAULT '0',
  `update_time` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分类表';
                

模型实现

// app/model/User.php
namespace appmodel;

use thinkModel;
use thinkmodelconcernSoftDelete;

class User extends Model
{
    use SoftDelete;
    
    protected $name = 'user';
    protected $autoWriteTimestamp = true;
    protected $deleteTime = 'delete_time';
    
    // 密码自动加密
    public function setPasswordAttr($value)
    {
        return password_hash($value, PASSWORD_DEFAULT);
    }
    
    // 状态获取器
    public function getStatusTextAttr($value, $data)
    {
        $status = [0 => '禁用', 1 => '正常'];
        return $status[$data['status']];
    }
}

// app/model/Article.php
namespace appmodel;

use thinkModel;

class Article extends Model
{
    protected $name = 'article';
    protected $autoWriteTimestamp = true;
    
    // 分类关联
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
    
    // 发布状态获取器
    public function getStatusTextAttr($value, $data)
    {
        $status = [0 => '草稿', 1 => '已发布'];
        return $status[$data['status']];
    }
}
                

使用迁移和填充

// 创建迁移文件
php think migrate:create CreateCmsTables

// database/migrations/20231215000000_create_cms_tables.php
use thinkmigrationMigrator;

class CreateCmsTables extends Migrator
{
    public function change()
    {
        $table = $this->table('user', ['comment' => '用户表', 'engine' => 'InnoDB']);
        $table->addColumn('username', 'string', ['limit' => 50, 'default' => '', 'comment' => '用户名'])
              ->addColumn('password', 'string', ['limit' => 255, 'default' => '', 'comment' => '密码'])
              ->addTimestamps()
              ->create();
    }
}
                

后台管理系统实现

后台登录实现

// app/admin/controller/Login.php
namespace appadmincontroller;

use thinkfacadeView;
use appmodelUser;

class Login
{
    public function index()
    {
        return View::fetch();
    }
    
    public function check()
    {
        $username = input('post.username');
        $password = input('post.password');
        $captcha = input('post.captcha');
        
        // 验证码验证
        if (!captcha_check($captcha)) {
            return json(['code' => 0, 'msg' => '验证码错误']);
        }
        
        // 用户验证
        $user = User::where('username', $username)->find();
        if (!$user || !password_verify($password, $user->password)) {
            return json(['code' => 0, 'msg' => '用户名或密码错误']);
        }
        
        // 登录成功
        session('admin_user', $user->toArray());
        return json(['code' => 1, 'msg' => '登录成功', 'url' => url('admin/index')]);
    }
}
                

后台中间件实现

// app/admin/middleware/Auth.php
namespace appadminmiddleware;

use thinkfacadeSession;

class Auth
{
    public function handle($request, Closure $next)
    {
        // 排除登录页面
        if (!preg_match('/admin/login/', $request->url())) {
            if (!Session::has('admin_user')) {
                return redirect('/admin/login');
            }
        }
        
        return $next($request);
    }
}

// 注册中间件 app/admin/middleware.php
return [
    appadminmiddlewareAuth::class
];
                

文章管理CRUD实现

// app/admin/controller/Article.php
namespace appadmincontroller;

use thinkfacadeView;
use appmodelArticle;
use appmodelCategory;

class Article extends Base
{
    public function index()
    {
        $page = input('page', 1);
        $limit = input('limit', 15);
        $keyword = input('keyword', '');
        
        $map = [];
        if ($keyword) {
            $map[] = ['title', 'like', "%{$keyword}%"];
        }
        
        $list = Article::with('category')
                ->where($map)
                ->order('id', 'desc')
                ->paginate(['page' => $page, 'list_rows' => $limit]);
        
        return View::fetch('index', [
            'list' => $list,
            'page' => $list->render(),
            'keyword' => $keyword
        ]);
    }
    
    public function add()
    {
        if (request()->isPost()) {
            $data = input('post.');
            $data['publish_time'] = strtotime($data['publish_time']);
            
            $result = Article::create($data);
            if ($result) {
                return json(['code' => 1, 'msg' => '添加成功', 'url' => url('admin/article/index')]);
            } else {
                return json(['code' => 0, 'msg' => '添加失败']);
            }
        }
        
        $categories = Category::where('status', 1)->select();
        return View::fetch('add', ['categories' => $categories]);
    }
    
    public function edit($id)
    {
        $article = Article::find($id);
        if (!$article) {
            $this->error('文章不存在');
        }
        
        if (request()->isPost()) {
            $data = input('post.');
            $data['publish_time'] = strtotime($data['publish_time']);
            
            if ($article->save($data)) {
                return json(['code' => 1, 'msg' => '更新成功', 'url' => url('admin/article/index')]);
            } else {
                return json(['code' => 0, 'msg' => '更新失败']);
            }
        }
        
        $categories = Category::where('status', 1)->select();
        return View::fetch('edit', [
            'article' => $article,
            'categories' => $categories
        ]);
    }
    
    public function delete($id)
    {
        $article = Article::find($id);
        if (!$article) {
            return json(['code' => 0, 'msg' => '文章不存在']);
        }
        
        if ($article->delete()) {
            return json(['code' => 1, 'msg' => '删除成功']);
        } else {
            return json(['code' => 0, 'msg' => '删除失败']);
        }
    }
}
                

前端展示功能实现

首页控制器实现

// app/home/controller/Index.php
namespace apphomecontroller;

use thinkfacadeView;
use appmodelArticle;
use appmodelCategory;

class Index
{
    public function index()
    {
        // 获取推荐文章
        $featuredArticles = Article::where('status', 1)
                                ->order('views', 'desc')
                                ->limit(5)
                                ->select();
        
        // 获取最新文章
        $latestArticles = Article::with('category')
                                ->where('status', 1)
                                ->order('publish_time', 'desc')
                                ->paginate(10);
        
        return View::fetch('index', [
            'featuredArticles' => $featuredArticles,
            'latestArticles' => $latestArticles,
            'page' => $latestArticles->render()
        ]);
    }
}
                

文章详情页实现

// app/home/controller/Article.php
namespace apphomecontroller;

use thinkfacadeView;
use appmodelArticle;

class Article
{
    public function detail($id)
    {
        $article = Article::with('category')->find($id);
        if (!$article || $article->status != 1) {
            abort(404, '文章不存在');
        }
        
        // 增加浏览量
        $article->views = ['inc', 1];
        $article->save();
        
        // 获取相关文章
        $relatedArticles = Article::where('category_id', $article->category_id)
                                ->where('id', '', $id)
                                ->where('status', 1)
                                ->order('publish_time', 'desc')
                                ->limit(5)
                                ->select();
        
        return View::fetch('detail', [
            'article' => $article,
            'relatedArticles' => $relatedArticles
        ]);
    }
}
                

分类页面实现

// app/home/controller/Category.php
namespace apphomecontroller;

use thinkfacadeView;
use appmodelArticle;
use appmodelCategory;

class Category
{
    public function index($id)
    {
        $category = Category::find($id);
        if (!$category) {
            abort(404, '分类不存在');
        }
        
        // 获取分类下的文章
        $articles = Article::where('category_id', $id)
                        ->where('status', 1)
                        ->order('publish_time', 'desc')
                        ->paginate(15);
        
        return View::fetch('index', [
            'category' => $category,
            'articles' => $articles,
            'page' => $articles->render()
        ]);
    }
}
                

安全防护与性能优化

安全措施实现

// 表单令牌防护
// 在模板中添加
<input type="hidden" name="__token__" value="{:token()}">

// 在控制器中验证
$check = $request->checkToken('__token__');
if (false === $check) {
    throw new ValidateException('令牌验证错误');
}

// XSS过滤
public function add()
{
    $data = input('post.');
    // 过滤HTML标签
    $data['content'] = clean($data['content']);
    // 或者使用HTMLPurifier等专业库
}

// SQL注入防护
// 使用查询构造器自动参数绑定
$list = Article::where('title', 'like', "%{$keyword}%")->select();

// 或者使用预处理
$list = Db::query('SELECT * FROM cms_article WHERE title LIKE ?', ["%{$keyword}%"]);
                

性能优化策略

// 使用缓存
public function index()
{
    $cacheKey = 'home_index_data';
    $data = cache($cacheKey);
    
    if (!$data) {
        $data = [
            'featuredArticles' => Article::where('status', 1)
                                    ->order('views', 'desc')
                                    ->limit(5)
                                    ->select(),
            'latestArticles' => Article::with('category')
                                    ->where('status', 1)
                                    ->order('publish_time', 'desc')
                                    ->paginate(10)
        ];
        // 缓存10分钟
        cache($cacheKey, $data, 600);
    }
    
    return View::fetch('index', $data);
}

// 数据库索引优化
// 为常用查询字段添加索引
ALTER TABLE `cms_article` ADD INDEX `idx_category_status` (`category_id`, `status`);
ALTER TABLE `cms_article` ADD INDEX `idx_publish_time` (`publish_time`);

// 使用延迟关联优化分页
public function index()
{
    $page = input('page', 1);
    $limit = input('limit', 15);
    
    // 先获取主键ID
    $ids = Article::where('status', 1)
                ->order('publish_time', 'desc')
                ->page($page, $limit)
                ->column('id');
    
    // 再获取完整数据
    $list = Article::with('category')
                ->whereIn('id', $ids)
                ->order('publish_time', 'desc')
                ->select();
}
                

项目部署与总结

生产环境部署

# 关闭调试模式
// config/app.php
'app_debug' => false,
'app_trace' => false,

# 优化路由缓存
php think optimize:route

# 生成配置缓存
php think optimize:config

# 类库映射优化
php think optimize:autoload

# 使用Composer优化自动加载
composer dump-autoload --optimize

# 设置目录权限
chmod -R 755 public/uploads
chmod -R 755 runtime
                

Nginx配置示例

server {
    listen 80;
    server_name example.com;
    root /path/to/tp-cms/public;
    index index.php index.html;
    
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php?s=$1 last;
            break;
        }
    }
    
    location ~ .php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ /.ht {
        deny all;
    }
}
                

项目总结

通过本教程,我们完成了一个基于ThinkPHP 6.0的企业级内容管理系统,涵盖了:

  1. ThinkPHP 6.0框架的核心特性使用
  2. 多应用模式的配置与开发
  3. 数据库设计与模型关系处理
  4. 完整的后台管理系统实现
  5. 响应式前端展示页面
  6. 安全防护与性能优化策略
  7. 生产环境部署配置

这个CMS系统可以作为企业网站、博客系统、新闻发布系统的基础框架,根据实际需求进行功能扩展和定制开发。

进一步学习建议

  • 学习使用ThinkPHP的门面模式和依赖注入
  • 掌握更多中间件的应用场景
  • 深入了解事件系统和钩子行为
  • 学习API接口开发与身份认证
  • 掌握队列处理和定时任务
  • 学习Docker容器化部署

ThinkPHP 6.0企业级CMS开发实战:从入门到精通 | PHP框架教程
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 thinkphp ThinkPHP 6.0企业级CMS开发实战:从入门到精通 | PHP框架教程 https://www.taomawang.com/server/thinkphp/953.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务