← PHP html_entity_decode()函数:HTML实体还原字符教程 PHP htmlspecialchars_decode()函数:HTML实体还原字符教程 →

PHP htmlspecialchars()函数:特殊字符转HTML实体教程

著
原创 2026-10-10 PHP 已有人查阅

一、函数定位与核心作用

htmlspecialchars()是PHP内置的字符串函数,把具有HTML语法意义的特殊字符转换成对应的HTML实体。它处理的字符范围是固定的五个:

原字符 转换后实体 说明
& & 和号
" " 双引号
' ' 单引号
< &lt; 小于号
> &gt; 大于号

这五个字符在HTML里承担标签边界、属性定界、实体起始等职责。如果用户提交的内容里带了<script>,不做处理直接输出,浏览器会当代码执行。转义之后,页面显示的是文本<script>,而不是可执行的脚本。这就是输出转义防XSS的基本思路。

它的逆操作是htmlspecialchars_decode(),把上面这五个实体还原回字符。

函数签名:

htmlspecialchars(
    string $string,
    int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,
    ?string $encoding = null,
    bool $double_encode = true
): string

四个参数里只有$string必填。

二、参数逐项拆解

$string(必填)

待转义的输入字符串。通常来自用户输入、数据库读取、接口返回等不可信来源。

$flags(可选)

控制引号处理、无效编码序列处理、文档类型三个方面。可以组合使用,用|连接。

引号相关:

  • ENT_COMPAT:只转双引号,保留单引号。适合属性用双引号的HTML。

  • ENT_QUOTES:双引号和单引号都转。推荐在不确定上下文时使用。

  • ENT_NOQUOTES:两者都不转。仅适合确认不会出现在属性值里的场景。

编码处理相关:

  • ENT_IGNORE:丢弃无效编码序列,返回结果可能缺字符,不推荐。

  • ENT_SUBSTITUTE:用Unicode替换字符U+FFFD替代无效序列,比ENT_IGNORE安全。

  • ENT_DISALLOWED:把指定文档类型中不允许的码点替换成U+FFFD。

文档类型相关:

  • ENT_HTML401:按HTML4.01处理,默认值。

  • ENT_HTML5:按HTML5处理。

  • ENT_XHTML:按XHTML处理。

  • ENT_XML1:按XML1.0处理。

$encoding(可选)

指定字符集,如UTF-8、ISO-8859-1。PHP5.6及以上默认取default_charset配置项,PHP5.4和5.5默认UTF-8。中文项目建议显式写UTF-8,避免依赖环境配置。

$double_encode(可选)

布尔值,默认true。表示是否对已有的HTML实体再次编码。设为false时,字符串里已经存在的&amp;不会被二次转成&amp;amp;。

三、代码号学习编程示例

先看基础转义,把带标签的字符串输出成文本:

<?php
$str = "这是 <i>斜体</i> 文本。";
echo htmlspecialchars($str, ENT_QUOTES);
?>

浏览器输出:

这是 <i>斜体</i> 文本。

页面源码里实际是:

这是 &lt;i&gt;斜体&lt;/i&gt; 文本。

浏览器把实体渲染成可见的尖括号,标签没有被解析。

再看引号处理差异:

<?php
$str = "这是 'PHP' & 'Java' 程序。";

echo htmlspecialchars($str, ENT_COMPAT);
echo "<br>";
echo htmlspecialchars($str, ENT_QUOTES);
echo "<br>";
echo htmlspecialchars($str, ENT_NOQUOTES);
?>

输出:

这是 'PHP' &amp; 'Java' 程序。
这是 &#039;PHP&#039; &amp; &#039;Java&#039; 程序。
这是 'PHP' &amp; 'Java' 程序。

ENT_COMPAT只动双引号,单引号保留;ENT_QUOTES把单引号转成&#039;;ENT_NOQUOTES两个引号都不动。注意三种模式下&都被转成&amp;,因为和号始终要处理。

double_encode的效果:

<?php
$stored = "&lt;b&gt;代码号学习编程&lt;/b&gt;";

echo htmlspecialchars($stored, ENT_QUOTES, "UTF-8", true);
echo "<br>";
echo htmlspecialchars($stored, ENT_QUOTES, "UTF-8", false);
?>

输出:

&amp;lt;b&amp;gt;代码号学习编程&amp;lt;/b&amp;gt;
&lt;b&gt;代码号学习编程&lt;/b&gt;

true会把已有的&再转一次,页面显示成&lt;b&gt;字面量;false保留原有实体,浏览器渲染出加粗效果。

四、与htmlentities()、htmlspecialchars_decode()的关系

htmlspecialchars()与htmlentities()

两者都做字符到实体的转换,区别在范围。htmlspecialchars()只转那五个有语法意义的字符;htmlentities()会把所有能匹配到实体的字符都转,包括中文、重音字母等。

日常防XSS输出转义,用htmlspecialchars()就够。htmlentities()范围过宽,中文项目里容易把正常字符也转成实体,反而带来乱码和体积问题。

htmlspecialchars()与htmlspecialchars_decode()

两者互为逆操作。前者把字符转实体,后者把实体还原成字符。解码后的内容如果重新输出到页面,需要再次转义,否则等于绕过了防护。

五、项目反思与踩坑经历

踩坑一:只转<不转引号,属性里被注入

早期写搜索框回显时,只依赖默认flags处理,结果单引号没转,用户构造'onmouseover='alert(1)这类payload在属性里生效。后来统一改成ENT_QUOTES,双引号和单引号都处理,问题消失。属性上下文里引号逃逸是很常见的注入路径。

踩坑二:先入库转义,导致数据重复转义

有项目在写库前调htmlspecialchars(),输出时又调一次,结果页面显示&amp;lt;。正确做法是存原始数据,输出时按上下文转义。入库转义会让数据失去原始形态,搜索、导出、二次处理都受影响。

踩坑三:用htmlentities()替代,中文被转成实体

处理中文昵称时用了htmlentities(),页面里出现大量&#x4ee3;这类实体。改用htmlspecialchars($name,ENT_QUOTES,'UTF-8')后正常。中文输出场景,htmlspecialchars()是更合适的选择。

踩坑四:忽略encoding,默认字符集不一致

同份代码在测试环境正常,生产环境中文偶发乱码。排查发现两边的default_charset配置不同。显式传'UTF-8'后稳定。依赖默认值省事,但跨环境会埋隐患。

个人建议

  • 输出到HTML正文或属性,默认用htmlspecialchars($str,ENT_QUOTES,'UTF-8')。

  • 不要用ENT_IGNORE,无效序列被静默丢弃,数据悄悄变短,排查困难。

  • 解码后的内容视同不可信,输出前重新转义。

  • JSON输出、URL参数、SQL语句各有对应的转义方式,不要拿HTML转义套用所有场景。

六、本节课程知识要点

  • htmlspecialchars()把&、"、'、<、>五个字符转成HTML实体。

  • 四个参数:字符串、flags、编码、是否重复编码,仅字符串必填。

  • ENT_COMPAT转双引号,ENT_QUOTES转双引号和单引号,ENT_NOQUOTES都不转。

  • ENT_SUBSTITUTE处理无效编码序列,比ENT_IGNORE安全。

  • double_encode=false避免对已有实体二次转义。

  • 与htmlentities()的区别在转义范围,防XSS通常用htmlspecialchars()。

  • 与htmlspecialchars_decode()互为逆操作。

  • 中文项目显式指定UTF-8。

七、扩展应用场景

场景一:用户评论输出

评论内容含<、>、引号,输出前统一转义,页面按文本呈现,标签不解析。

场景二:表单回显

搜索关键词回填到value属性里,用ENT_QUOTES同时处理两种引号,避免属性被提前闭合。

场景三:日志与调试页面展示

把请求参数打印到页面时,先转义再输出,防止参数里的标签破坏页面结构。

场景四:邮件模板变量填充

HTML邮件里插入用户名等变量,用htmlspecialchars($name,ENT_QUOTES,'UTF-8')处理,避免名字里的特殊字符影响邮件渲染。

htmlspecialchars()是PHP输出转义里使用频率很高的函数。它的价值在于用固定的五个字符转换,覆盖HTML上下文里的主要注入路径,同时不影响其他字符。理解flags对引号的控制、encoding对中文的影响、double_encode对已有实体的处理,以及它与htmlentities()的范围差异,才能在项目里用得准确。记住一条原则:入库存原始数据,输出按上下文转义,解码后的内容重新当不可信数据处理。

← PHP html_entity_decode()函数:HTML实体还原字符教程 PHP htmlspecialchars_decode()函数:HTML实体还原字符教程 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号