thinkphp中input()和request::param()不自动过滤,无全局开关;default_filter仅影响已弃用的i()函数,真正有效过滤需分场景:单字段用input('x', '', 'filter')、批量用param()+array_map()+merge()、验证器内显式配置filter规则,命令行须手动解析$_server['argv']。

input() 和 Request::param() 不自动过滤,ThinkPHP 没有“一键开启全局参数过滤”的配置项。所谓“配置”,本质是选对位置、用对方法、明确作用域——不是开关,而是策略。
为什么 DEFAULT_FILTER 配置基本失效
TP6 中 'DEFAULT_FILTER' => 'htmlspecialchars' 仅影响旧版 I() 函数(已不推荐),对 input()、request()->param()、验证器、中间件完全不生效。它不递归、不处理嵌套字段(如 user.name)、不修改原始数据,也不触发日志或模型赋值环节。你改了这个配置,控制器里 input('content') 还是原样返回带 <script></script> 的字符串。
真正有效的过滤入口只有三个地方
必须按使用场景选,不能混用:
- 单字段临时清洗:用
input('name', '', 'htmlspecialchars')或input('name', '', 'trim|htmlspecialchars')—— 注意第三个参数只对当前调用生效,且不支持数组路径(input('data.title')加 filter 会失效) - 批量字段统一处理:在控制器或中间件里手动清洗
request()->param()返回的数组,例如:$params = request()->param(); $params = array_map(fn($v) => is_string($v) ? htmlspecialchars(trim($v)) : $v, $params); request()->merge($params);
⚠️ 必须调用merge(),否则后续所有input()调用仍读原始值 - 验证器内过滤:只在
(new MyValidate())->check($data)执行时生效,且需显式写规则:'content' => 'require|filter:htmlspecialchars'
静态调用$this->validate($data, MyValidate::class)不走 filter 流程
命令行请求(think 命令)必须绕开 Request 对象
input() 和 $this->request->param() 在 CLI 下永远为空——因为框架根本没解析 $_SERVER['argv']。想过滤 php think user:create --name=jack --email=test@x.com,只能手动处理:
- 用
array_slice($_SERVER['argv'], 2)拿到参数片段 - 逐个
explode('=', $arg, 2)拆出 key/value - 用
array_map('trim', $value)清洗,再传给Validate::filter()或自定义逻辑 - 别依赖
default_filter或中间件,它们在命令行模式下压根不加载
最容易被忽略的点:过滤 ≠ 校验 ≠ 脱敏 ≠ 日志安全
你在一个地方做了 htmlspecialchars,不代表 XSS 就防住了:日志里还记着原始参数,模型 save() 时可能直接入库,缓存键用未过滤值生成,前端回显又忘了二次转义……真正的安全是每个环节都明确自己拿的是“清洗后”还是“原始”数据。不要假设某个函数“应该已经处理过了”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











