htmlspecialchars() 是绝大多数场景下最安全的选择,仅转义 &、<、>、"、' 五个字符,防 XSS 且不破坏中文和 HTML 结构;务必显式指定 ENT_QUOTES 和 UTF-8 编码。

用 htmlspecialchars() 处理用户输入最安全
绝大多数场景下,该函数就是你要找的答案。它只转义 &、、<code>>、"、' 这 5 个关键字符,既防 XSS,又不破坏 HTML 结构或中文显示。
常见错误是直接上 htmlentities(),结果把所有非 ASCII 字符(比如中文、emoji)也转成 ...;,页面显示乱码或异常空白。
实操建议:
- 始终显式指定
charset参数,如htmlspecialchars($str, ENT_QUOTES, 'UTF-8'),避免 PHP 默认 ISO-8859-1 导致中文被误判为非法字节而返回空字符串 - 用
ENT_QUOTES而非ENT_COMPAT,确保单引号也被转义(尤其在data-*属性中很关键) - 不要依赖
default_charsetini 设置,它不可靠且容易被覆盖
需要完整转义所有 Unicode 字符?用 htmlentities() 加 ENT_IGNORE
只有当你明确需要把中文、日文、数学符号等全部转成十进制或十六进制实体(如 你好 → 你好),才考虑这个函数。典型场景是生成严格 ASCII 兼容的邮件模板或遗留系统接口。
立即学习“PHP免费学习笔记(深入)”;
但必须加 ENT_IGNORE(PHP 7.2+ 已废弃,改用 ENT_SUBSTITUTE),否则遇到非法 UTF-8 字节序列会直接返回空字符串,导致数据丢失。
示例:
$safe = htmlentities($str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
注意:ENT_SUBSTITUTE 会把非法字节替换成 ,比静默丢弃更可控。
htmlspecialchars_decode() 和 html_entity_decode() 别混用
前者只还原 &、<、>、"、' 这 5 个,后者能还原所有已知 HTML 实体(包括 ©、λ、😊 等)。
如果你用 htmlentities() 转过全量字符,就必须用 html_entity_decode() 才能正确还原;反之,若原始只是 htmlspecialchars(),两者效果一致,但前者更快、更轻量。
常见坑:
- 没传
charset导致中文实体解码失败,返回原样或乱码 - 在 JSON 响应里嵌套 HTML 实体后又双重解码,造成
→ <code><→的意外标签注入
输出到 HTML 属性值时额外加引号包裹
即使用了 htmlspecialchars(),如果直接拼进未加引号的属性,仍有风险。例如:
<div data-id=<?php echo htmlspecialchars($user_input); ?>>
当 $user_input 是 123 onclick=alert(1),结果变成 data-id=123 onclick=alert(1) —— 属性提前闭合,XSS 成立。
正确做法是:始终用双引号或单引号包裹属性值,并确保引号本身也被转义(即用 ENT_QUOTES):
<div data-id="<?php echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); ?>">
这个细节在模板引擎里常被忽略,尤其是手写 echo 拼接时。



















