简介:这份资源是从官方渠道获取的ThinkPHP 3.1.3完整版本,包含框架本体及全部可用扩展,面向PHP初学者、旧版系统维护者以及需要研究早期MVC框架实现的技术人员。它解决了开发者四处搜集扩展、反复配置环境的问题,可直接用于搭建Web应用、学习框架底层原理或维护遗留项目。压缩包为zip格式,整体约1.39MB,文件总数与类型明细上游暂未提供,但按完整版惯例应涵盖框架核心库、扩展插件及配套资源。目前已有438人学习下载,说明该版本在旧项目维护与入门教学中仍有一定关注度。资源价值在于:内置MVC架构、自动路由、模型操作与模板引擎,支持MySQL、SQLite、PostgreSQL等多种数据库;同时集成缓存管理、SQL注入防护、XSS防范、错误日志处理及命令行工具,让读者无需额外寻找扩展即可完成数据库CRUD、视图渲染与安全防护等任务。对于想理解ThinkPHP早期设计思路或维护旧系统的开发者,这是一份开箱即用的参考包。
1. 从官方下载的 ThinkPHP 3.1.3 完整版本:一个老项目的环境复原与二次开发起点
手上拿到一个十年前的老系统,客户说“就跑在 ThinkPHP 3.1.3 上,你帮我加两个报表功能”,你打开压缩包一看,目录里躺着 ThinkPHP 核心、Extend 扩展、Examples 示例,还有一堆 .php 文件命名风格停留在 PHP 5.2 时代。这时候最怕的不是写业务代码,而是环境跑不起来——PHP 版本一换,mysql_connect直接报废弃,preg_replace的/e修饰符被移除,整个项目白屏。从官方下载的 ThinkPHP 3.1.3 完整版本(含所有扩展)这个包,本质上是一个“时间胶囊”:它把当年框架核心、常用扩展、示例代码一次性打包,适合两类人——需要维护遗留系统的工程师,以及想理解早期 MVC 框架设计思路的学习者。这一章先把这个包的结构和它能解决的问题讲清楚,后面几章再一步步把它跑起来、改起来、避坑。
2. 拆开完整版压缩包:目录结构、扩展分类与版本选择理由
拿到一个完整版压缩包,第一件事不是急着往 web 根目录扔,而是先看清楚里面有什么。ThinkPHP 3.1.3 的完整版通常包含核心框架目录、扩展目录、示例入口文件,以及一些配套的配置文件模板。很多人从官方下载后直接解压到项目根目录,结果发现入口文件路径不对、扩展加载失败,这就是没先理清目录结构导致的。
2.1 核心目录与扩展目录的职责划分
完整版解压后,典型结构是这样的:
ThinkPHP3.1.3/ ├── ThinkPHP/ # 框架核心 │ ├── Common/ # 公共函数 │ ├── Conf/ # 默认配置 │ ├── Core/ # 核心类库 │ ├── Extend/ # 官方扩展 │ │ ├── Driver/ # 数据库、缓存、模板驱动 │ │ ├── Library/ # 扩展类库 │ │ └── Function/ # 扩展函数 │ ├── Lang/ # 语言包 │ ├── Mode/ # 模式定义 │ └── Tpl/ # 模板引擎 ├── Extend/ # 应用扩展(第三方) ├── Examples/ # 示例代码 ├── index.php # 入口文件示例 └── README.md核心目录ThinkPHP/是框架本体,不要随意改动。Extend/是官方扩展,里面按 Driver、Library、Function 分类。Driver 下又有 Db、Cache、Template 等子目录,分别对应数据库驱动、缓存驱动、模板驱动。完整版的价值就在这里——它把 MySQL、SQLite、Oracle 等数据库驱动,File、Memcache、Redis 等缓存驱动,以及 Smarty、Think 等模板驱动都打包好了,不需要你再去单独找。
应用扩展目录Extend/是给你放第三方类库的,比如 PHPExcel、PHPMailer 这类。入口文件index.php是示例,实际项目里通常会自己写一个入口,定义APP_PATH和THINK_PATH后引入框架。
2.2 为什么选 3.1.3 而不是 3.2 或 5.x
这个问题在遗留系统维护场景下很现实。3.1.3 和 3.2 的目录结构、命名规范、自动加载机制都有差异。3.2 引入了命名空间,核心类库路径变了,很多 3.1.3 的扩展在 3.2 下不能直接用。5.x 更是完全重写,API 兼容性几乎为零。
如果你接手的是一个已经在跑 3.1.3 的系统,升级框架的成本远高于在 3.1.3 上继续开发。完整版的意义在于:你不需要去 composer 找依赖,不需要处理版本冲突,所有当年能用的扩展都在包里。常见做法是,先确认生产环境的 PHP 版本,再决定用哪个版本的框架。3.1.3 官方推荐 PHP 5.2 以上,实际在 PHP 5.3 到 5.6 之间最稳定。PHP 7 以上会遇到大量兼容性问题,后面避坑章节会详细说。
2.3 入口文件与目录权限的最小配置
把完整版跑起来,第一步是写入口文件。在项目根目录新建index.php:
<?php // 定义项目路径 define('APP_PATH', './App/'); // 定义框架路径 define('THINK_PATH', './ThinkPHP/'); // 开启调试模式 define('APP_DEBUG', true); // 引入框架入口文件 require THINK_PATH . 'ThinkPHP.php';这段代码做了三件事:指定应用目录、指定框架目录、开启调试。APP_PATH是你要开发的应用代码存放位置,THINK_PATH是框架核心位置。调试模式开启后,页面底部会显示运行时间、内存占用、SQL 日志,开发阶段必开,上线后关掉。
目录权限方面,App/Runtime/需要可写,这是编译缓存和日志目录。Linux 下执行:
chmod -R 755 ./App/Runtime chmod -R 755 ./ThinkPHP如果 Runtime 不可写,页面会报“缓存目录不可写”错误。这是新手最容易忽略的一步,尤其是从 Windows 搬到 Linux 的时候。
提示:完整版里的 Examples 目录可以直接作为入口示例,但不要把它当成项目目录用,建议单独建 App 目录,保持框架和应用分离。
3. 在 PHP 5.6 环境跑通第一个控制器:配置、路由与数据库连接
环境跑起来之后,下一步是让框架响应一个请求。ThinkPHP 3.1.3 的 MVC 流程很直接:入口文件 → 应用初始化 → 路由解析 → 控制器 → 模型 → 视图。这一章用一个最小示例把整条链路走通,重点讲配置文件和数据库连接,因为这两个地方最容易翻车。
3.1 应用配置文件的分层与常用参数
在App/Conf/下新建config.php:
<?php return array( // 数据库配置 'DB_TYPE' => 'mysql', 'DB_HOST' => '127.0.0.1', 'DB_NAME' => 'test_db', 'DB_USER' => 'root', 'DB_PWD' => '123456', 'DB_PORT' => '3306', 'DB_PREFIX' => 'tp_', // 默认模块和控制器 'DEFAULT_MODULE' => 'Home', 'DEFAULT_CONTROLLER' => 'Index', 'DEFAULT_ACTION' => 'index', // URL 模式 'URL_MODEL' => 1, // 模板配置 'TMPL_TEMPLATE_SUFFIX' => '.html', 'TMPL_FILE_DEPR' => '/', );DB_*系列参数控制数据库连接,DB_PREFIX是表前缀,框架会自动拼接到表名前面。URL_MODEL设为 1 表示 PATHINFO 模式,URL 形如/index.php/Home/Index/index。如果服务器不支持 PATHINFO,改成 0 用普通模式,或者 2 用 rewrite 模式。
DEFAULT_MODULE、DEFAULT_CONTROLLER、DEFAULT_ACTION三个参数决定默认访问哪个模块、控制器、方法。不配置的话,默认是 Home/Index/index。
3.2 控制器与模型的创建步骤
在App/Home/Controller/下新建UserController.class.php:
<?php namespace Home\Controller; use Think\Controller; class UserController extends Controller { public function index() { // 实例化模型 $user = M('User'); // 查询所有用户 $list = $user->select(); // 分配变量到模板 $this->assign('list', $list); // 渲染模板 $this->display(); } public function add() { if (IS_POST) { $data = array( 'username' => I('post.username'), 'email' => I('post.email'), ); $result = M('User')->add($data); if ($result) { $this->success('添加成功', U('User/index')); } else { $this->error('添加失败'); } } else { $this->display(); } } }M('User')实例化模型,对应数据库表tp_user。select()查询所有记录。I('post.username')是框架的输入过滤函数,比直接用$_POST安全。$this->success()和$this->error()是框架内置的跳转方法,会自动渲染提示页面。
模型文件可以不用单独建,M()函数会直接实例化基础模型。如果需要自定义方法,在App/Home/Model/下建UserModel.class.php,继承Think\Model。
3.3 数据库连接失败的排查顺序
数据库连不上是最高频的问题。按这个顺序排查:
第一,检查DB_HOST是127.0.0.1还是localhost。localhost走 socket,127.0.0.1走 TCP,两者在权限配置上可能不同。
第二,确认数据库用户有远程连接权限。如果数据库不在本机,需要授权:
GRANT ALL PRIVILEGES ON test_db.* TO 'root'@'%' IDENTIFIED BY '123456'; FLUSH PRIVILEGES;第三,检查 PHP 的 MySQL 扩展是否开启。在php.ini里确认extension=mysqli.so或extension=pdo_mysql.so没有被注释。ThinkPHP 3.1.3 默认用 mysqli 驱动,如果只有 PDO,需要在配置里改DB_TYPE为pdo。
第四,打开调试模式看具体错误。APP_DEBUG为 true 时,数据库错误会直接显示在页面上,包括 SQL 语句和错误码。常见错误码 1045 是用户名密码错误,1049 是数据库不存在,2002 是 socket 连接失败。
注意:生产环境一定要关掉
APP_DEBUG,否则数据库账号密码会暴露在错误页面里。
4. 扩展加载与模板渲染:把完整版里的 Driver 和 Library 用起来
完整版最大的价值是扩展齐全。但扩展不是自动生效的,需要在配置里指定,或者手动引入。这一章讲清楚扩展的加载机制,以及模板渲染的配置方法。
4.1 数据库驱动与缓存驱动的切换配置
ThinkPHP 3.1.3 支持多种数据库驱动,切换方式是在config.php里改DB_TYPE:
// 使用 PDO 驱动 'DB_TYPE' => 'pdo', // 使用 SQLite 'DB_TYPE' => 'sqlite', 'DB_NAME' => './data/test.db',缓存驱动同理,在config.php里配置:
'DATA_CACHE_TYPE' => 'Redis', 'REDIS_HOST' => '127.0.0.1', 'REDIS_PORT' => 6379,如果配置了 Redis 但页面报“缓存初始化失败”,先确认 PHP 的 redis 扩展是否安装。php -m | grep redis能看到 redis 就说明扩展正常。没装的话,完整版里没有自带 PHP 扩展,需要单独编译安装。
文件缓存是最稳妥的,不需要额外扩展:
'DATA_CACHE_TYPE' => 'File', 'DATA_CACHE_PATH' => './App/Runtime/Cache/',4.2 模板引擎配置与变量输出
ThinkPHP 3.1.3 自带 Think 模板引擎,也支持 Smarty。默认用 Think,模板文件放在App/Home/View/User/index.html。模板里输出变量:
<!DOCTYPE html> <html> <head> <title>用户列表</title> </head> <body> <table> <volist name="list" id="vo"> <tr> <td>{$vo.id}</td> <td>{$vo.username}</td> <td>{$vo.email}</td> </tr> </volist> </table> </body> </html><volist>是框架的循环标签,name是分配的变量名,id是循环变量。{$vo.username}输出字段值,框架会自动转义 HTML 特殊字符。如果不想转义,用{$vo.username|raw}。
模板里还可以用<if>、<foreach>、<switch>等标签,语法和 PHP 类似。模板编译后的文件在App/Runtime/Cache/下,修改模板后如果没生效,删掉缓存目录再刷新。
4.3 第三方 Library 的引入方式
完整版的Extend/Library/下有一些官方扩展类,比如ORG.Util.Page分页类。引入方式:
import('ORG.Util.Page'); $count = M('User')->count(); $Page = new \Org\Util\Page($count, 10); $show = $Page->show(); $list = M('User')->limit($Page->firstRow . ',' . $Page->listRows)->select(); $this->assign('list', $list); $this->assign('page', $show);import()是框架的类导入函数,ORG.Util.Page对应ThinkPHP/Extend/Library/ORG/Util/Page.class.php。如果类文件放在Extend/Library/下,路径要相应调整。
第三方类库比如 PHPExcel,放到Extend/Library/下,然后import('PHPExcel.PHPExcel')引入。注意目录名和类名大小写要匹配,Linux 下区分大小写,Windows 下不区分,跨平台部署时容易在这里翻车。
5. 避坑与常见问题:PHP 版本、路径大小写与缓存陷阱
这一章集中讲踩过的坑。ThinkPHP 3.1.3 是个老框架,在新环境下跑会遇到各种兼容性问题,有些是 PHP 版本导致的,有些是框架自身的设计缺陷。
5.1 PHP 7 下大量函数废弃与替代方案
现象:页面白屏,日志里报Deprecated: mysql_connect(): The mysql extension is deprecated或者Fatal error: Uncaught Error: Call to undefined function mysql_connect()。
原因:PHP 7 移除了mysql_*系列函数,ThinkPHP 3.1.3 的默认数据库驱动用的是 mysqli,但如果配置成mysql就会调用已移除的函数。另外,preg_replace的/e修饰符在 PHP 7 中被移除,框架里如果有用到的地方会直接报错。
解决:把DB_TYPE改成mysqli或pdo。如果框架核心里有preg_replace带/e的代码,改成preg_replace_callback。更稳妥的做法是用 PHP 5.6 跑这个框架,PHP 7 不是不能跑,但需要改的地方比较多,维护成本高。
5.2 路径大小写导致的类加载失败
现象:Windows 下开发正常,部署到 Linux 后报Class 'Home\Controller\UserController' not found。
原因:Linux 文件系统区分大小写,框架的自动加载机制按类名拼路径,如果目录名或文件名大小写和类名不一致,就找不到文件。
解决:统一规范,控制器文件名用UserController.class.php,目录名用Controller,首字母大写。模板目录同理,View/User/index.html里User要大写。部署前用find . -name "*.php"检查一遍文件名。
5.3 Runtime 缓存目录权限与清理时机
现象:修改了配置文件或模板,刷新页面没变化,或者报“缓存文件写入失败”。
原因:App/Runtime/目录不可写,或者缓存没及时清理。框架会把配置、模板、数据缓存都放在这个目录下,调试阶段频繁修改时,旧缓存会干扰。
解决:开发阶段每次改配置后手动删除App/Runtime/下的文件,或者开启APP_DEBUG让框架每次重新编译。Linux 下确保Runtime目录权限为 755,属主和 web 服务用户一致。上线后保留缓存,提升性能。
5.4 数据库前缀与表名大小写问题
现象:M('User')查询失败,报“表 tp_user 不存在”,但数据库里明明有这张表。
原因:MySQL 在 Linux 下默认表名区分大小写,Windows 下不区分。如果数据库里表名是tp_User,而框架拼出来的是tp_user,就会找不到。
解决:建表时统一用小写,或者在 MySQL 配置里设置lower_case_table_names=1。另外,DB_PREFIX配置要和实际表前缀一致,不要多空格或少字符。
5.5 扩展加载顺序与命名空间冲突
现象:引入第三方类库后,报Cannot redeclare class或者类方法找不到。
原因:完整版里已经有同名类,或者import()引入的类文件和框架核心类命名空间冲突。
解决:第三方类库统一放到Extend/Library/下,用import()引入时带上完整路径。如果类名和框架核心类重复,改第三方类名或者用class_alias做别名。加载顺序上,先引入框架核心,再引入扩展,避免覆盖。
提示:遇到白屏先看 PHP 错误日志,再开
APP_DEBUG看框架日志。日志位置在App/Runtime/Logs/下,按日期分文件。
6. 在 3.1.3 上做二次开发:从加字段到写自定义扩展的实操技巧
接手老项目,最常见的需求是加字段、加报表、对接外部接口。这一章讲几个具体技巧,都是在 3.1.3 上验证过的做法。
6.1 给现有模型加字段与自动验证
假设要给用户表加一个mobile字段,先在数据库执行:
ALTER TABLE tp_user ADD COLUMN mobile VARCHAR(20) DEFAULT '' AFTER email;然后在模型里加自动验证:
<?php namespace Home\Model; use Think\Model; class UserModel extends Model { protected $_validate = array( array('username', 'require', '用户名不能为空'), array('email', 'email', '邮箱格式不正确'), array('mobile', '/^1[3-9]\d{9}$/', '手机号格式不正确', 0, 'regex'), ); protected $_auto = array( array('create_time', 'time', 1, 'function'), ); }$_validate定义验证规则,$_auto定义自动填充。create_time在新增时自动写入当前时间戳。控制器里用D('User')实例化模型,create()方法会触发验证和自动填充:
$user = D('User'); if (!$user->create()) { $this->error($user->getError()); } else { $user->add(); }D()和M()的区别是,D()会加载自定义模型类,M()直接实例化基础模型。需要验证和自动填充时用D()。
6.2 自定义扩展类的编写与注册
如果完整版里的扩展不够用,可以自己写。在Extend/Library/下新建My/Util/ExcelHelper.class.php:
<?php namespace My\Util; class ExcelHelper { public static function export($data, $filename) { header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment; filename="' . $filename . '"'); echo implode("\t", array_keys($data[0])) . "\n"; foreach ($data as $row) { echo implode("\t", array_values($row)) . "\n"; } exit; } }控制器里引入:
import('My.Util.ExcelHelper'); \My\Util\ExcelHelper::export($list, 'user_list.xls');import()的路径用点号分隔,对应目录层级。命名空间要和目录结构一致,My/Util/对应My\Util。
6.3 用行为扩展做统一登录校验
ThinkPHP 3.1.3 支持行为扩展(Behavior),可以在请求前后插入逻辑。比如统一登录校验,在App/Home/Behavior/下建AuthBehavior.class.php:
<?php namespace Home\Behavior; class AuthBehavior { public function run(&$params) { $noAuth = array('Home/User/login', 'Home/User/register'); $current = MODULE_NAME . '/' . CONTROLLER_NAME . '/' . ACTION_NAME; if (in_array($current, $noAuth)) { return; } if (!session('?user_id')) { redirect(U('Home/User/login')); } } }在App/Conf/tags.php里注册:
<?php return array( 'action_begin' => array('Home\\Behavior\\AuthBehavior'), );这样每个请求开始前都会执行AuthBehavior的run方法,白名单里的地址跳过校验,其他地址检查 session。行为扩展的好处是不用改每个控制器,统一入口处理。
6.4 调试技巧:SQL 日志与性能分析
开发阶段想看 SQL 执行情况,在config.php里开:
'SHOW_PAGE_TRACE' => true, 'LOG_RECORD' => true, 'LOG_LEVEL' => 'SQL',页面右下角会出现调试面板,显示所有 SQL 语句、执行时间、内存占用。如果只想看 SQL 日志,在App/Runtime/Logs/下按日期找日志文件。
性能分析方面,G('start')和G('end')可以打点计时:
G('start'); // 业务代码 G('end'); echo G('start', 'end', 4) . '秒';这个技巧在排查慢查询时很有用,能定位到具体哪段代码耗时。
6.5 老项目升级的边界与取舍
最后说一个现实问题:什么时候该继续在 3.1.3 上开发,什么时候该重构。我的经验是,如果项目还在稳定运行,只是加功能,就在 3.1.3 上做,成本最低。如果遇到 PHP 版本必须升级、安全漏洞无法修复、性能瓶颈明显,那就考虑重构。
重构不一定要一步到位,可以先把新功能用新框架写,老功能保持不动,通过接口对接。这样风险可控,也能逐步迁移。但不管怎么选,先把完整版的环境跑通,把现有系统的行为摸清楚,再动手。我一般会先在本地用 PHP 5.6 把完整版跑起来,把数据库导一份,把主要流程走一遍,确认没有隐藏的兼容问题,再开始改代码。这个习惯帮我省了很多后悔药。
希望帮到你。
本文还有配套的精品资源,点击获取