在thinkphp 5.1+模板中输出变量时,应优先使用内置过滤器{:$name|html}(tp6)或{:$name|htmlspecialchars}(tp5.1),其底层调用htmlspecialchars($str, ent_quotes, 'utf-8'),仅转义 " ' &五个关键字符,兼顾xss防护与中文兼容性,比htmlentities更轻量、不易乱码。

ThinkPHP 5.1+ 中 html 标签过滤用 htmlspecialchars 还是 htmlentities
直接说结论:在 ThinkPHP 模板中输出变量时,{$name} 默认不转义,必须显式用 {:htmlspecialchars($name)} 或开启模板自动转义;但更推荐用内置的 {:$name|htmlspecialchars} 过滤器,它底层调用的是 htmlspecialchars($str, ENT_QUOTES, 'UTF-8'),能正确处理中文和单双引号,比 htmlentities 更轻量、兼容性更好。
常见错误是直接写 {:$name|htmlentities} —— 它会把所有可表示的 Unicode 字符都转成实体(比如中文“你好”变成 你好),导致页面显示乱码或 SEO 不友好。
-
htmlspecialchars只转义<code>>"'&这 5 个关键字符,够防 XSS 且不影响可读性 - ThinkPHP 6 默认模板引擎(ThinkTemplate)已内置
html修饰符,等价于htmlspecialchars,写法更简洁:{:$name|html} - 若变量含换行需转
<br>,不能只靠htmlspecialchars,得组合nl2br:{:$content|htmlspecialchars|nl2br}
ThinkPHP 控制器里对用户输入做预过滤:用 filter_var 还是 strip_tags
入库前清理 HTML 标签,别用 strip_tags 简单粗暴删——它无法防御 <img src="x" onerror="alert(1)"> 这类无闭合标签的 XSS。
真正安全的做法是「白名单过滤」:只保留你需要的标签和属性。ThinkPHP 自带 think\helper\Str::cleanHtml()(TP6.1+),但默认未启用;更通用的是用 filter_var 配合自定义回调,或引入 HTMLPurifier 库。
- 简单场景(如仅允许
<p><br><strong></strong></p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML"><img src="https://img.php.cn/upload/skill/000/000/081/178998486916110.jpg" alt="Doc To HTML" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML" class="overflowclass">Doc To HTML</a> <p class="overflowclass">使用 MinerU 文档处理引擎将 Word 文档(.doc、.docx)转换为保留结构和格式的干净 HTML。</p> </div> <a rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>):用strip_tags($str, ['p','br','strong'])+ 再过一遍htmlspecialchars - 生产环境富文本(如编辑器内容):必须用
HTMLPurifier,配置白名单:$config->set('HTML.Allowed', 'p,b,i,br,a[href|title]'); - TP5.1 中
input('post.content/s')的/s修饰符只是调用htmlspecialchars,**不删标签**,别误以为它能防 XSS
模板中 {:} 和 {$} 在 HTML 上下文里的行为差异
这是最容易踩坑的地方:你以为写了 {:$name} 就安全,其实它等于原样 echo,浏览器会把其中的 <script></script> 当代码执行。
{:} 是执行 PHP 表达式,{$} 是输出变量,两者都不自动转义。唯一自动转义的是 {|} 修饰符语法(即 {:$name|html})。
- 错误写法:
<div>{$user_input}</div>→ XSS 风险 - 正确写法:
<div>{$user_input|html}</div>或<div>{:htmlspecialchars($user_input)}</div> - 注意:如果变量已是 HTML 实体(比如数据库里存了
<script>),再套一次|html会变成双重编码(显示为),此时应先 <code>html_entity_decode再过滤
全局开启模板自动转义后,哪些地方必须关掉
ThinkPHP 6 支持在 config/template.php 中设置 'default_filter' => 'html',让所有 {$var} 自动过 htmlspecialchars。但这个开关一开,就会影响所有输出——包括你明确需要渲染 HTML 的字段(如后台富文本内容、Markdown 渲染结果)。
- 必须关闭自动转义的场景:
{:raw($html_content)}(TP6)、{:$html_content|raw}(TP5.1)、或直接用<?php echo $html_content; ?> - 别用
{:$html_content|htmlspecialchars|raw}——raw会取消之前所有过滤,等于白干 - 更稳妥的做法:只对用户昵称、简介等纯文本字段开启自动过滤,富文本字段统一走
htmlpurifier处理并标记为可信,输出时用raw
真正麻烦的不是怎么转义,而是分不清「哪里该转」「哪里不该转」「转了几遍」。线上出 XSS,八成是因为某个 {$xxx} 漏了修饰符,或者富文本字段被自动过滤了两次。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










