ThinkPHP 5.1 视图过滤须通过控制器 filter() 方法或 view() 助手函数链式调用实现,禁止全局函数干预;filter 作用于整个 HTML 字符串,单变量过滤应在 assign 前处理;模板中使用 {:} 修饰符需显式指定 ENT_QUOTES 和 UTF-8 参数防 XSS。

ThinkPHP 5.1 中视图过滤不再支持全局函数或 I() 方式直接干预输出内容,必须通过控制器 assign 后、fetch 前的 filter() 方法或 view 助手函数链式调用完成,否则变量原样输出将导致 XSS 漏洞。
用控制器 filter() 方法做变量级过滤
第一步:在控制器方法中调用 assign() 赋值后,立即链式调用 filter(),传入一个闭包函数处理 $content 参数。
第二步:闭包内对整个模板渲染前的字符串做替换,例如去除所有数字:$this->assign('title', '公告123')->filter(function($content) { return str_replace(['0','1','2','3','4','5','6','7','8','9'], '', $content); })->fetch();
注意:filter() 作用于整个模板最终生成的 HTML 字符串,不是单个变量;若只希望过滤某变量,应在 assign 前处理,而非用此方式。
立即学习“PHP免费学习笔记(深入)”;
用 view() 助手函数一次性赋值+过滤
方法一:直接在 view() 后链式调用 filter(),再 fetch():
return view('index', ['name' => '张三'])->filter(function($content) { return htmlspecialchars($content, ENT_QUOTES, 'UTF-8'); })->fetch();
方法二:用 view() 的第二个参数传入闭包作为过滤器(TP5.1 支持):
return view('index', ['name' => '<script>alert(1)</script>'], function($content) { return htmlspecialchars($content, ENT_QUOTES, 'UTF-8'); });
这一步操作起来很简单,直接把闭包当第三个参数传进去就行。但【必须确保闭包返回的是处理后的字符串,不能返回 void 或 null】,否则页面会空白。
全局初始化过滤(适用于全站统一处理)
在控制器基类的 initialize() 方法中写入 filter(),后续所有继承该基类的方法都会自动套用:
protected function initialize(){ $this->filter(function($content) { return preg_replace('/<script>]*?>.*?<\/script>/is', '', $content); }); }</script>
这种写法适合清除全部 script 标签,但【无法防御 onerror=alert(1) 这类内联事件】,仅作基础清理;真正需要富文本,请改用 HTMLPurifier。
模板层不推荐的“伪过滤”写法
错误做法:在模板里写 {:$data|htmlspecialchars} 却没配好编码参数——默认不传 ENT_QUOTES 会导致单引号不转义,攻击者仍可闭合属性触发 XSS。
正确写法必须显式指定:{:$data|htmlspecialchars=ENT_QUOTES,UTF-8}。
更简洁安全的替代是使用 TP6 兼容写法 {:$data|html},但 TP5.1 需确认模板引擎已加载 html 修饰符别名。



















