htmlspecialchars()是最安全的xss防护函数,需显式指定ent_quotes和'utf-8'参数;富文本应过滤而非转义,禁用preg_replace手写过滤;属性值、js上下文等须按场景选htmlspecialchars或json_encode。

htmlspecialchars() 是最常用也最安全的选择
直接用 htmlspecialchars(),别碰 htmlentities() 除非你真要转所有 Unicode 字符。它默认只转 、<code>>、"、'、& 这五个关键字符,既防 XSS 又保持可读性。
常见错误是漏传 $encoding 和 $flags 参数,导致中文乱码或单引号不转义:
- 必须显式指定
UTF-8编码:htmlspecialchars($str, ENT_QUOTES, 'UTF-8') -
ENT_QUOTES要带上,否则单引号'不会被转成',在属性值里可能出问题 - PHP 8.1+ 默认
$flags已含ENT_SUBSTITUTE,但老版本建议手动加,避免无效 UTF-8 字节触发警告
什么时候不能用 htmlspecialchars()
如果你的字符串本身来自富文本编辑器(比如带 <strong></strong>、<p></p> 的 HTML),再套一层 htmlspecialchars() 就全变成源码了——页面显示的是 <p>Hello</p>,而不是段落。
这种场景不是“转义”,而是“渲染前过滤”:
立即学习“PHP免费学习笔记(深入)”;
- 用
strip_tags()剥离所有标签,只留纯文本:strip_tags($html, ['br', 'p', 'strong']) - 更安全的做法是用专门库如
HTMLPurifier,白名单控制允许的标签和属性 - 绝对不要用
preg_replace()手写“过滤 script 标签”逻辑,绕过方式太多
echo 时忘记转义是最常见的 XSS 入口
模板里直接 echo $user_input 是高危操作,哪怕只是输出到 <div> 或 <code><input value="..."> 里。浏览器不会区分“这是变量还是字面量”,只要没转义,就可能执行 JS。
几个典型踩坑点:
- 在属性值中拼接字符串:
<input value="<?php echo $name; ?>">→ 必须用htmlspecialchars($name, ENT_QUOTES, 'UTF-8'),否则用户输" onclick="alert(1)就触发 - JS 上下文里直接插 PHP 变量:
var msg = "<?php echo $msg; ?>";→ 这里需要 JSON 编码:json_encode($msg, JSON_UNESCAPED_UNICODE),不是htmlspecialchars() - 用
printf()或短标签= $x ?>时,一样要先转义,短标签不自动做任何处理
mb_convert_encoding() 和 iconv() 不解决转义问题
有人看到中文乱码,第一反应是调编码函数,结果写了 mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8')——这函数根本不存在,mb_convert_encoding() 只负责字符集转换,不生成实体。
真正要生成 HTML 实体,只有两个可靠路径:
-
htmlspecialchars():推荐,轻量、可控、语义明确 -
htmlentities():仅当需要把 ©、α、€ 等全部转成©、α、€时才用,体积大、可读差、部分旧浏览器支持不好
转义和编码是两件事:前者防注入,后者保显示。混用只会让问题更难定位。










