ThinkPHP 8.0 入口点是 public/index.php,这是框架强制约定的唯一 Web 入口,源于“Web 目录隔离”设计,不可重命名或移动,否则导致自动加载失败、路由失效及配置错误。

ThinkPHP 8.0 的入口点在哪?先定位路由和控制器
TP8 的代码审计不是从 index.php 开始乱翻,而是必须先确认请求如何落到具体类方法上。框架路由不再只是靠文件路径推断,app/route.php 和 route/route.php 是主路由定义处;若用了注解路由(如 @Route),得查 app/controller/ 下各控制器类的 PHPDoc 注释。常见错误是把 /admin/user/edit?id=123 直接对应到 admin/user/edit.php,实际它大概率落在 app/admin/controller/User.php 的 edit 方法里。漏掉这步,后面全在审计“空气”。
哪些函数调用必须人工逐行盯?eval、system、file_get_contents 的危险组合
静态扫描工具会标出 eval()、assert()、system()、shell_exec()、unserialize(),但真正要命的是它们和用户输入的耦合方式。比如:
-
eval($_GET['code'])是明牌后门,一眼毙命 -
file_get_contents($_GET['file'])没做路径过滤,配合../../config/database.php就是任意文件读取 -
include $_POST['template'] . '.php'是典型的任意文件包含,TP8 的自动加载机制也救不了这种写法
尤其注意 TP8 新增的 think\facade\Cache::tag() 或 think\facade\Log::write() 如果参数来自未过滤的 input(),可能触发反序列化链或日志注入——这类间接调用容易被忽略。
PHPStan + Psalm 怎么配才不漏报?绕过框架魔术方法的配置要点
默认跑 phpstan analyse 会大量报 Call to an undefined method,因为 TP8 大量使用魔术方法(如 __call、__get)和 Facade 动态代理。必须加配置:
立即学习“PHP免费学习笔记(深入)”;
- 在
phpstan.neon中启用phpstan-phpunit和phpstan-deprecation-rules插件 - 添加
includes:指向vendor/topthink/framework/src/think/facade/下的 Facade 类定义 - 对模型类加
@property-read注解,否则$user->name会被判为未定义属性
Psalm 同理,需在 psalm.xml 中 <ignorefiles></ignorefiles> 排除 runtime/ 和 vendor/,但要保留 app/ 和 config/ —— 配置文件里的数据库密码硬编码、调试模式开启('debug' => true)都是高危项,不能被忽略。
input() 和 request()->param() 的过滤差异,为什么不能无脑信任?
TP8 默认的 input() 函数会走全局过滤器(filter 参数控制),但开发者常犯两个错:
- 写成
input('id')而没指定类型,导致返回字符串,后续直接拼 SQL 或传给intval()前没校验,仍可能被绕过 - 用
request()->param('file')获取文件名,却没调用pathinfo()拆解后缀,也没进白名单校验,就直接传给file_put_contents()
更隐蔽的是 input('data/a.*') 这种批量取值,如果 a 是数组且含恶意键名(如 __destruct),可能触发反序列化利用。别信“框架自动过滤”,得看过滤器是否启用、是否覆盖了所有入口($_GET、$_POST、$_COOKIE、$_REQUEST)。
TP8 的安全审计难点不在工具不会用,而在于框架层抽象掩盖了真实数据流向。一个 validate() 校验通过的参数,未必干净;一个 Db::table()->where() 看似用了预编译,但如果 where 条件是拼接的字符串而非绑定参数,照样 SQL 注入。盯住输入源、盯住敏感函数、盯住中间态变量,三者缺一不可。



















