标题起的高大上,实际上就是富文本在保存到数据库时,是存储原始标签数据,还是转义后数据的问题。
1、先看实际案例
下图右边是本博客在数据库中默认存储的内容,左边是使用thinkcmf开发是默认存储的内容。

很显然,本博客mysql中存储的是未转义的数据,thinkcmf的mysql中存储的是转义后的数据。
2、两个概念
2.1、html标签
html标签是构成html文档的基本单位,是用尖括号<>包裹的关键词,用于高速浏览器如何解析、渲染页面内容(比如定义标题、段落、图片、链接等),模式HTML的核心语法。
核心特点
- 分双标签(有开始和结束,如
<p></p>)和单标签(自闭合,如<img/><br/>); - 浏览器会识别并执行标签的功能,不会直接显示标签本身;
- 部分标签带属性,补充功能(如
<img src="图片地址" alt="描述"/>)。
2.2、html实体
html实体是用特定编码表示html特殊字符的方式,这些表示以&开头,以;结尾,用于在页面中显示哪些浏览器会被解析为语法的特殊字符(),或显示一些无法直接输入的特殊字符(例如空格、版权符©)。
核心特点
- 浏览器会将实体编码还原为对应的原始字符并显示,不会当作 HTML 语法解析;
- 解决「特殊字符被浏览器误解析」的问题(比如想显示
<,直接写会被认作标签开头,必须用实体<); - 分命名实体(如
<)和数字实体(如<),效果一致,命名实体更易记。
2.3、测试代码
<!-- 情况1:直接写< >,浏览器认作HTML标签,解析功能 -->
<p>这是<h1>测试</h1>文本</p>
<!-- 页面效果:这是【大号加粗的测试】文本(<h1>被解析为标题标签) -->
<!-- 情况2:用HTML实体写< >,浏览器显示原始字符,不解析 -->
<p>这是<h1>测试</h1>文本</p>
<!-- 页面效果:这是<h1>测试</h1>文本(直接显示尖括号和h1,无标题效果) -->
显示效果:

当使用html实体时,浏览器直接显示原始字符,不解析。
3、htmlspecialchars() 函数
htmlspecialchars($str) 的作用:把字符串中的 HTML 特殊字符()转换成对应的 HTML 实体;目的是:让浏览器只显示字符,不解析为HTML标签,这样既避免页面布局错乱,又防止XSS攻击(比如用户输入<script>,转成<script>后就不会被执行)。
例如:
<?php
$str = '<script>alert("XSS")</script>';
// 转义:把< > " & 转成实体
$escaped = htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
echo $escaped;
// 输出的内容:<script>alert("XSS")</script>
// 浏览器效果:直接显示<string>alert("XSS")</string>,不会执行弹窗
?>
4、htmlspecialchars_decode() 函数
htmlspecialchars_decode() 函数用于还原转义后的文本(比如后台编辑、数据还原)。和htmlspecialchars() 函数是互逆操作。
| 函数 | 核心作用 | 常用场景 |
|---|---|---|
| htmlspecialchars | 特殊字符→HTML 实体(编码) | 纯文本输出到页面(防 XSS、防标签解析) |
| htmlspecialchars_decode | HTML 实体→特殊字符(解码) | 还原转义后的文本(如后台编辑、数据还原) |
xss攻击实战:
<?php
// 用户恶意输入的评论
$userComment = '<script>alert("XSS攻击")</script>';
// 转义后输出(安全,浏览器仅显示文本,不执行脚本)
echo htmlspecialchars($userComment, ENT_QUOTES, 'UTF-8');
// 输出:<script>alert("XSS攻击")</script>
// 若需要将转义后的评论还原为原始内容(比如后台编辑)
$editComment = htmlspecialchars_decode(htmlspecialchars($userComment));
echo $editComment; // 输出:<script>alert("XSS攻击")</script>
?>
5、htmlentities() 函数
htmlentities()会转义所有 HTML 实体(包括中文),实战中极少用,容易导致乱码;而htmlspecialchars() 只会处理<、>、&、"、' 这5个字符。
6、最终结论
这是豆包给的结论
-
绝对不能用
htmlspecialchars()转义富文本后存库富文本本身就是带<p>、<img>、<div>等 HTML 标签的内容,用这个函数会把标签转成<p>,取出来展示时就变成纯文本了,富文本直接失效。 -
必须做【数据库转义】(防 SQL 注入)富文本里可能包含单引号
'、双引号"、反斜杠\等字符,直接拼接 SQL 会导致注入漏洞,必须转义后再入库。 -
展示到页面时:不需要二次转义直接输出富文本即可(如果是用户提交的富文本,需要额外做 XSS 过滤,和数据库转义是两回事)。
很明显,thinkcmf的做法和豆包给的结论是完全相反的。