ThinkPHP的input()函数默认不自动过滤,需显式指定规则;推荐用Validate验证器统一过滤校验,避免手动调用遗漏,并按输出场景(HTML/JSON/DB)精准选择过滤方式。

ThinkPHP 的 input() 函数默认不自动过滤,必须显式指定过滤规则
很多人误以为 ThinkPHP 会像旧版那样对所有 input() 数据做全局转义或 HTML 过滤,实际上从 ThinkPHP 5.1 开始,默认行为是「原样返回」,不做任何处理。这是安全设计的倒退还是进步?取决于你怎么用——它把过滤责任明确交还给开发者,避免隐式过滤导致的二次转义或逻辑错误。
正确做法是:每次调用 input() 时,主动传入过滤函数或标识。例如:
// 获取字符串并去除两端空格、转义特殊字符(等价于 htmlspecialchars)
$name = input('name', '', 'htmlspecialchars|trim');
// 获取整数,自动类型转换 + 范围校验
$uid = input('id', 0, 'intval|abs');
// 获取数组并递归过滤每个值(注意:filter_var 不支持递归,需自定义)
$data = input('post.', [], 'array_map:htmlspecialchars');
-
input()第三个参数是过滤器,支持函数名、管道符分隔的多个函数、或function:arg形式 - 内置过滤器如
htmlspecialchars、strip_tags、intval可直接用,但注意它们不处理数组嵌套 - 不要依赖框架配置项
default_filter(TP6 已移除),它在多入口或 CLI 场景下不可靠
用 validate() 做结构化过滤比手动 input() 更可靠
单纯靠 input() 过滤容易漏字段、难复用、无法统一错误提示。真实业务中,推荐用验证器(Validate 类)完成输入过滤+校验一体化。
示例:定义一个 UserValidate 验证器
立即学习“PHP免费学习笔记(深入)”;
class UserValidate extends Validate
{
protected $rule = [
'username' => 'require|alphaNum|length:3,16',
'email' => 'email',
'content' => 'require|safeHtml', // 自定义过滤规则
];
protected $filter = [
'username' => 'htmlspecialchars|trim',
'email' => 'strtolower|trim',
'content' => 'htmlspecialchars_decode|strip_tags|trim',
];
}
-
$filter数组会在验证通过后自动对对应字段执行过滤,且顺序执行,支持链式 - 自定义过滤函数(如
safeHtml)需注册到Validate的extendFilter中,不能直接写函数名 - 验证器过滤发生在数据入库前,天然适配模型层,避免控制器里散落大量
input()调用
警惕 htmlspecialchars 在 JSON/AJAX 场景下的双重编码问题
前端用 fetch 或 axios 提交 JSON 数据时,如果后端仍对整个 input('post.') 执行 htmlspecialchars,会导致 JSON 字符串里的引号、斜杠被反复转义,最终解析失败。
- 错误现象:
JSON.parse()报错Unexpected token & in JSON at position 0,实际是"被转成了" - 解决方案:对非 HTML 渲染场景(如 API 接口),禁用 HTML 类过滤,改用
filter_var($val, FILTER_SANITIZE_STRING)或更严格的白名单正则 - TP6 中可配合中间件识别请求类型:
request()->isAjax() && request()->header('content-type') === 'application/json',跳过 HTML 过滤
自定义过滤函数必须考虑 NULL/空数组/资源类型的边界情况
自己写的过滤函数(比如用于清理富文本、过滤 XSS 标签)常忽略输入类型异常,导致 PHP Warning 或静默失败。
例如这个常见错误写法:
function clean_html($value) {
return strip_tags(htmlspecialchars_decode($value)); // 当 $value 是 null 或 [] 时会警告
}
- 务必在自定义过滤函数开头加类型判断:
if (!is_string($value)) { return $value; } - 对数组输入,需递归处理(但注意避免深度过大导致栈溢出)
- 不要在过滤函数里抛异常——
input()和validate()都不会捕获,会直接中断流程 - 测试时用
input('data/a/b', null, 'clean_html')模拟深层键缺失,确认是否返回默认值而非报错
过滤不是加一层保险,而是按输出场景精准裁剪。HTML 输出用 htmlspecialchars,数据库写入用预处理绑定,JSON 返回用类型校验——混用规则只会让漏洞藏得更深。



















