PHP htmlentities()函数用法讲解
前言htmlentities()和htmlspecialchars()长得几乎一样同样的四个参数、同样的标志位常量、同样的返回类型。手册对它的定义也很干脆——「这个函数在所有方面都与htmlspecialchars()相同区别在于htmlentities()会把所有具有 HTML 字符实体对应物的字符都转换成实体」。正因为只有这一个区别很多教程把它描述成「htmlspecialchars()的增强版」「更安全的那个」。这个说法不准确而且会误导人做出错误的技术选择。事实是在防 XSS 这件事上两者是等价的。真正危险的字符是、、、、这五个htmlspecialchars()在设了对应标志位后全都会转换htmlentities()一个也不少。多转换的那些字符比如带重音字母本身并没有 HTML 语法含义。htmlentities()真正多做的事是把「本来可以原样输出」的字符也换成实体。Café会变成Cafeacute;这在某些场景是必要的在多数场景只是让输出变长、可读性变差。两者用的是同一份转换表。手册明确写着get_html_translation_table()返回的就是这两个函数内部使用的表可以用它亲眼确认某个字符在给定文档类型下会不会被转换。本文把「什么情况下用哪个」这个决策讲清楚并给出查看转换表、反向解码、生成数字实体的具体写法。一、签名与唯一的区别官方手册给出的签名是htmlentities(string $string,int $flags ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,?string $encoding null,bool $double_encode true): string参数含义与htmlspecialchars()逐项对应参数说明与 htmlspecialchars 的差异$string待处理的字符串无$flags引号策略、非法序列策略、文档类型无同一批常量$encoding字符编码省略时取default_charset无$double_encode是否对已有实体再次编码无默认标志的版本差异同样存在ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401是PHP 8.1.0 起的默认值在那之前默认是ENT_COMPAT单引号不会被转换遇到非法编码序列还会返回空字符串。所以和htmlspecialchars()一样建议把标志显式写全不要依赖默认值。两者放在一起对比最直观?php // 适用于 PHP 8.0$s Café 版权 © 2026中文保持原样;echo htmlentities : , htmlentities($s, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, UTF-8), PHP_EOL;echo htmlspecialchars: , htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, UTF-8), PHP_EOL;输出对比htmlentities : Cafeacute; amp; 版权 copy; 2026中文保持原样htmlspecialchars: Café amp; 版权 © 2026中文保持原样可以看到htmlentities()把é变成eacute;、©变成copy;而htmlspecialchars()只动了。两者对的处理完全一致——这一点很关键它说明两者对 XSS 的防护能力没有差别。二、哪些字符会被转换取决于文档类型和编码「所有具有 HTML 字符实体对应物的字符」这句话里的「对应物」来自一张按文档类型组织的命名实体表。所以能不能被转换要看两件事字符本身有没有命名实体以及你选的文档类型里有没有收录它。文档类型标志命名实体规模典型效果ENT_HTML401HTML 4.01 实体集拉丁字母带重音符号如é、常用符号如©会被转换ENT_XML1/ENT_XHTMLXML 预定义实体 少量转换范围比 HTML 4.01 窄很多ENT_HTML5HTML5 命名引用表条目远多于 HTML 4.01能被转换的符号字符更多还有一点要特别说明汉字CJK 统一表意文字在 HTML 的命名实体表里没有对应项所以无论选哪个文档类型、用哪种编码中文都会被原样保留。上例里的「版权」「中文保持原样」都不变这不是漏掉了而是本来就没有某汉字;这种写法可用。另外要分清「命名实体」和「数字实体」这两件事htmlentities()只产出命名实体形如eacute;它不会产出数字实体形如#233;或#xE9;。需要把字符一律转成数字实体时要用mb_encode_numericentity()手册在htmlspecialchars()页面里也是这样指引的。它的签名是mb_encode_numericentity(string $string, array $map, ?string $encoding null, bool $hex false): string第二个参数指定要转换的码点区间。?php // 适用于 PHP 7.0需要 mbstring 扩展$s Café — 测试;// 0x80 到 0x10FFFF 全部转成十进制数字实体$map [0x80, 0x10FFFF, 0, 0x10FFFF];echo mb_encode_numericentity($s, $map, UTF-8), PHP_EOL;用 get_html_translation_table() 亲眼看转换表与其猜某个字符会不会被转换不如把表打印出来。get_html_translation_table()的签名是get_html_translation_table(int $table HTML_SPECIALCHARS,int $flags ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,string $encoding UTF-8): array第一个参数取HTML_SPECIALCHARS时返回htmlspecialchars()用的表取HTML_ENTITIES时返回htmlentities()用的表。?php // 适用于 PHP 8.0$special get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, UTF-8);$entities get_html_translation_table(HTML_ENTITIES, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, UTF-8);printf(HTML_SPECIALCHARS 条目数: %d%s, count($special), PHP_EOL);printf(HTML_ENTITIES 条目数: %d%s, count($entities), PHP_EOL);// 看几个具体字符foreach ([, , , , , é, ©, 中] as $c) {printf(%-4s - special: %-10s entities: %-10s%s,$c,$special[$c] ?? (无),$entities[$c] ?? (无),PHP_EOL);}注意返回数组的键是被转换的原字符值是替换后的实体字符串。这个脚本跑一遍「哪些字符会被转换」这个问题就再也不用靠记忆了。三、什么时候用哪个结论很明确绝大多数场景用htmlspecialchars()。场景选择原因把用户输入输出到 HTML 页面htmlspecialchars()五个危险字符都处理了输出保持可读输出到 HTML 属性htmlspecialchars()带ENT_QUOTES即可页面本身声明为 UTF-8内容含中文 / emojihtmlspecialchars()汉字与大多数非拉丁字符本来就没有命名实体转不转都一样输出的页面是纯 ASCII 环境、终端/邮件设备不支持 UTF-8htmlentities()把带重音字符降级成实体能提高兼容性需要严格「全 ASCII」的 HTML 输出htmlentities()配合mb_encode_numericentity()后者能覆盖前者转不了的字符输出到 URL、JavaScript、SQL都不用分别用rawurlencode()/json_encode()/ 参数化查询选htmlentities()有一个可以量化的代价把字符换成实体必然让字符串变长。一个é在 UTF-8 里是 2 字节写成eacute;是 8 字节©在 UTF-8 里是 2 字节写成copy;是 6 字节。转换的字符种类越多、出现得越频繁输出体积增长就越明显而且转换过程本身也要多做查表工作。这不是「快几倍慢几倍」的问题而是一个可以自己算清楚的字节账。还需要提醒一点htmlentities()的转换范围依赖$encoding参数。如果输入数据的实际编码和传入的$encoding不一致转换表就会对不上结果是既没转对、还可能触发非法序列处理逻辑。所以无论用哪个函数都显式传UTF-8并确保数据真的是 UTF-8。四、实战一个统一的输出转义工具下面这段代码把前面几节的要点收拢成一个可直接运行的小示例给出两个转义入口HTML 文本 / 属性统一用h()并把转换表条目数打印出来做环境自检。?php // 适用于 PHP 8.0declare(strict_types1);const HTML_FLAGS ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401;const CHARSET UTF-8;/** 输出到 HTML 文本或属性时统一走这里 */function h(?string $s): string{return htmlspecialchars((string) $s, HTML_FLAGS, CHARSET);}/** 仅在需要「全 ASCII 兼容输出」时才用 */function h_all(?string $s): string{return htmlentities((string) $s, HTML_FLAGS, CHARSET, true);}$samples [plain Hello World,metachars a b c d e \f\,accented Café résumé,cjk 中文测试,];foreach ($samples as $name $value) {printf([%s]%s, $name, PHP_EOL);printf( 原文 : %s%s, $value, PHP_EOL);printf( htmlspecial… : %s%s, h($value), PHP_EOL);printf( htmlentities : %s%s, h_all($value), PHP_EOL);}// 反向把实体还原回字符$encoded h(a b c d);var_dump(htmlspecialchars_decode($encoded, ENT_QUOTES));var_dump(html_entity_decode($encoded, HTML_FLAGS, CHARSET));运行这个脚本一次就能看清两个函数的全部差别也能确认「汉字在这两张表里都没有对应项」这个事实。反向操作需要注意一点htmlspecialchars_decode()只还原htmlspecialchars()处理过的那几个实体而html_entity_decode()会还原所有命名实体。如果你用htmlentities()编码过数据解码时应该用html_entity_decode()并传入同样的文档类型标志和编码。常见坑点❌ 认为htmlentities()比htmlspecialchars()「更安全」于是全项目统一用它✅ 两者对 XSS 的防护是等价的危险字符集合相同。区别只在「是否顺带转换所有有命名实体的字符」。默认选htmlspecialchars()只有在明确需要 ASCII 兼容输出时才用htmlentities()。❌ 以为汉字会被转成实体✅ 汉字在 HTML 的命名实体表里没有对应项用任何文档类型都会原样保留。想要「全 ASCII 输出」还得配合mb_encode_numericentity()。❌ 以为htmlentities()会输出数字实体如#233;✅ 它只产出命名实体。数字实体要用mb_encode_numericentity()。❌ 只写htmlentities($s)依赖默认标志✅ PHP 8.1 之前默认是ENT_COMPAT单引号不转换非法序列还会返回空字符串。显式写ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401并传UTF-8。❌ 传入的$encoding和数据实际编码不一致✅ 转换表是按编码查的对不上就会转错或触发非法序列处理。统一在项目里用UTF-8并在数据入口做编码校验。❌ 在入库前用htmlentities()处理用户输入✅ 转义只在输出到 HTML 时做。入库前转义会让导出 CSV、调接口、做搜索时全是实体符号还会导致重复转义。❌ 用htmlentities()处理要放进 URL 或 JavaScript 的值✅ 它只管 HTML 上下文。URL 参数用rawurlencode()JavaScript 数据用json_encode()。❌ 用htmlentities($s) $s判断「有没有特殊字符」✅ 当字符串里本来就有实体文本时会误判而且松散比较容易出问题。直接比较用或者用htmlspecialchars($s, ...) ! $s判断是否需要转义。总结项目htmlspecialchars()htmlentities()转换范围5 个字符引号受标志控制所有具有命名实体对应物的字符防 XSS 能力足够与前者等价不多不少输出长度基本不变被转换的字符变长é从 2 字节变 8 字节汉字原样保留原样保留无对应命名实体数字实体不产出不产出要用mb_encode_numericentity()转换表查询get_html_translation_table(HTML_SPECIALCHARS, ...)get_html_translation_table(HTML_ENTITIES, ...)反向函数htmlspecialchars_decode()html_entity_decode()默认标志PHP 8.1 起为 ENT_QUOTES \ENT_SUBSTITUTE \把htmlentities()理解成「htmlspecialchars()加上把所有拉丁字母和符号也换成实体」就足够了。它不是一个更安全的版本只是一个转换范围更广的版本而转换范围广在中文为主的页面里既不会带来安全收益也不会碰到汉字唯一的实际影响是输出体积和可读性。默认用htmlspecialchars()把htmlentities()留给「必须输出纯 ASCII HTML」这一种明确需求是更省心的选择。

相关新闻

大模型Agent开发入门:从工具调用循环到落地避坑指南

大模型Agent开发入门:从工具调用循环到落地避坑指南

这两年“大模型Agent开发”的热度一直没降,我自己从零跑通第一个Agent项目之后,最深的感受是:Agent和单纯调大模型接口完全是两条技术路线。你写几十行代码问模型几个问题,那只是最基础的API调用;只有让模型自己拆解目…

2026/10/9 0:02:51 阅读更多 →
多模态大模型全栈能力拆解:从数据对齐到弹性推理

多模态大模型全栈能力拆解:从数据对齐到弹性推理

1. 这不是选“哪家服务商”,而是看清楚“全栈”到底在解决什么问题多模态大模型这个词,最近半年在技术圈和企业客户侧的热度,已经从“听说有这么个东西”变成了“我们业务卡点是不是能靠它破局”。但很多人一搜“多模态大模型服务商推荐”&am…

2026/10/9 0:02:51 阅读更多 →
AI编程智能体实战:从写代码到指挥代码的架构与落地

AI编程智能体实战:从写代码到指挥代码的架构与落地

1. 从“写代码”到“指挥代码”:AI编程智能体到底改变了什么这两年但凡还在写代码的人,多少都听过“AI编程智能体”这个词。但很多人对它的理解还停留在“帮我补全一行代码”的层面,这就好比把一台挖掘机当成了铲子用。AI编程智能体&#xff…

2026/10/9 0:02:51 阅读更多 →

最新新闻

Docker部署OpenClaw并接入飞书机器人:Windows实践指南

Docker部署OpenClaw并接入飞书机器人:Windows实践指南

这周我在Windows上把OpenClaw完整跑通了,并且成功接上了飞书机器人,整体链路还算顺。今天就把整套方案整理出来,从Docker环境的准备工作,到docker compose部署OpenClaw,再到飞书开放平台的应用配置和消息联调&#xff…

2026/10/9 3:28:11 阅读更多 →
软件测试技术文件实战:从测试计划到Word排版的完整指南

软件测试技术文件实战:从测试计划到Word排版的完整指南

1. 为什么软件测试的产出物,最后都落在Word上做软件测试这些年,我经手的软件测试技术文件,绝大多数都是Word格式。测试计划、测试用例、缺陷报告、测试总结……不管团队内部平时用什么项目管理工具、缺陷管理平台、在线协作文档,真…

2026/10/9 3:28:11 阅读更多 →
环形链表与快慢指针:从判断有环到定位环入口的数学推导

环形链表与快慢指针:从判断有环到定位环入口的数学推导

如果你在LeetCode上刷到第141题“环形链表”,第一反应大概是:这题有什么难的?三行代码就能写完。可真正在面试里被这道题拦住的人,从来不是写不出“判断有没有环”的代码,而是被追问“为什么快慢指针一定会相遇”时哑口…

2026/10/9 3:28:10 阅读更多 →
Linux实操手记:从装系统到日常运维的全链路记录

Linux实操手记:从装系统到日常运维的全链路记录

2026.3.19 Linux 实操手记:从装系统到日常运维的全链路记录2026年3月19日,我在自己的实验机器上完整走了一遍 Linux 的装、配、用、查全过程。写这篇文章的初衷很简单:当天整理了一份笔记,从虚拟机安装 Linux 镜像开始&#xff0c…

2026/10/9 3:28:10 阅读更多 →
6种Pandas数据填充方法详解:从fillna到插值分组与模型预测

6种Pandas数据填充方法详解:从fillna到插值分组与模型预测

上周处理一份门店销售明细,表拿到手第一眼挺干净,列名规范、数字工整。结果用pandas读进来一查:日期列缺了17个值,城市列有3种写法,单价列里混着空值和字符串,金额列还有个负得离谱的数字。业务方甩了一句“…

2026/10/9 3:28:10 阅读更多 →
C#+MySQL房屋租赁管理系统开发:从数据库设计到代码落地

C#+MySQL房屋租赁管理系统开发:从数据库设计到代码落地

简介:基于C#与MySQL实现的房屋租赁管理系统项目压缩包,面向计算机、软件工程、通信工程等专业学生的课程设计与毕业设计参考,适合具备一定C#基础者通过完整项目提升综合开发能力。系统采用Windows窗体配合ADO.NET处理MySQL数据访问&#xff0…

2026/10/9 3:27:10 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →