ThinkPHP中间件中应通过$request->post()或$request->get()精准获取参数,JSON请求需用$request->json(true);敏感词过滤须在路由前执行,避免缓存污染,并统一返回JSON错误响应。

ThinkPHP 中间件里怎么接住用户输入
中间件拿到的是 $request 对象,不是原始 $_POST 或 $_GET。直接读取 input() 方法返回的数据才可靠,否则可能绕过验证、漏过滤。
-
$request->param()会合并 GET/POST/ROUTE,适合通用场景;但敏感词需区分来源时,用$request->post()或$request->get()更精准 - 如果用了 JSON 请求体(
Content-Type: application/json),必须调用$request->json(true),否则param()拿不到数据 - 注意:中间件执行顺序影响结果——必须放在路由调度前(比如
app/middleware.php中靠前位置),否则控制器已处理完输入,过滤就失效了
敏感词匹配用 strpos 还是 preg_match
简单关键词用 strpos 足够,快且无正则开销;但要支持模糊、通配或大小写不敏感,就得上 preg_match,代价是性能下降明显,尤其词库大时。
- 纯文本匹配推荐
stripos(忽略大小写)+ 预加载敏感词数组,避免每次 fopen 读文件 - 别在中间件里实时读取
./config/sensitive_words.php,IO 会拖慢所有请求;启动时用think\facade\Config::load()加载到内存更稳 - 正则模式下,词库含特殊字符(如
.、*)必须preg_quote($word, '/')转义,否则报PregException: Compilation failed
过滤后怎么让控制器知道出错了
不能只 dump() 或 exit,那样前端收不到结构化响应。ThinkPHP 推荐统一返回 json 格式错误,并中断后续流程。
- 调用
$response = response(['code' => 400, 'msg' => '含敏感词'], 400)->contentType('application/json')后,必须return $response - 别用
throw new \think\Exception('xxx'),它会触发全局异常处理,可能被日志捕获但前端得不到明确提示 - 若需保留原始参数供调试,可在响应里加
'rejected_field' => $field_name,但生产环境建议关掉,防信息泄露
为什么有些请求永远过不了过滤中间件
常见原因是表单用了 enctype="multipart/form-data" 且含文件上传字段,此时 $request->post() 默认为空——ThinkPHP 把这类请求的 body 解析逻辑锁死了,必须手动提取。
立即学习“PHP免费学习笔记(深入)”;
- 检测是否为文件上传请求:
$request->isPost() && $request->file()存在时,改用$request->param(false, false)(第二个false表示不自动过滤 XSS) - 某些 API 客户端(如 Postman)发 JSON 时没设 header,
$request->isJson()返回false,导致走错分支,建议加兜底逻辑:if (!$data) $data = json_decode(file_get_contents('php://input'), true) ?: []; - 缓存中间件(如
CacheMiddleware)若放在敏感词中间件之前,会导致脏数据被缓存——顺序错了,问题就藏得深
真正麻烦的不是写过滤逻辑,而是各种输入来源的解析差异和中间件加载时机。一个没注意,$request->post('content') 就是空的,你还以为词库没生效。



















