当我在 htmlspecialchars 页面上看到这些常量时,我开始想知道这些常量有什么行为。文档很垃圾,所以我开始挖掘 PHP 的源代码。
基本上,这些常量会影响某些实体是否被编码(或为html_entity_decode 解码)。最明显的效果是撇号 (') 是编码为 '(对于 ENT_HTML401)还是 '(对于其他人)。同样,它在使用html_entity_decode 时确定' 是否被解码。 (' 总是被解码)。
所有用法都可以在 ext/standard/html.c 及其头文件中找到。来自 ext/standard/html.h:
#define ENT_HTML_DOC_HTML401 0
#define ENT_HTML_DOC_XML1 16
#define ENT_HTML_DOC_XHTML 32
#define ENT_HTML_DOC_HTML5 (16|32)
(将 ENT_HTML_DOC_ 替换为 ENT_ 以获取它们的 PHP 常量名称)
我开始寻找这些常量的所有出现,并可以分享以下关于ENT_* 常量的行为:
- 它影响将解码或不解码的数字实体。例如,
 被解码为 ENT_HTML401、ENT_XHTML 和 ENT_XML1 的不可读/无效字符。但是对于ENT_HTML5,这被认为是无效字符,因此它保持为。 (C function unicode_cp_is_allowed)
- 启用
ENT_SUBSTITUTE 后,指定字符集的无效代码单元序列将替换为�。 (不取决于文档类型!)
- 启用
ENT_DISALLOWED 后,指定文档类型不允许的代码点将替换为�。 (不依赖于字符集!)
- 使用
ENT_IGNORE,来自ENT_SUBSTITUTE 的相同无效代码单元序列将被删除并且不进行替换(取决于“文档类型”的选择,例如ENT_HTML5)
- 禁止

 使用 ENT_HTML5 (line 976)
-
ENT_XHTML 与 ENT_HTML401 共享实体映射。唯一的区别是' 将转换为带有ENT_XHTML 的撇号,而ENT_HTML401 不会转换它(参见this line)
-
ENT_HTML401 和 ENT_XHTML 使用完全相同的实体映射(减去与上一点的差异)。 ENT_HTML5 使用自己的地图。其他人(目前为ENT_XML1)的解码映射非常有限(>、&、<、'、" 及其数字等价物)。 (见C function unescape_inverse_map)
- 注意前一点:当只有少数实体必须转义时(想想
htmlspecialchars),所有实体映射将使用与ENT_XML1 相同的实体,ENT_HTML401 除外。那个不会使用',而是'。
这几乎涵盖了所有内容。我不会列出所有实体差异,而是想指出 https://github.com/php/php-src/tree/php-5.4.11/ext/standard/html_tables 一些包含每种类型映射的文本文件。
htmlspecialchars 应该使用什么 ENT_*?
当htmlspecialchars 与 ENT_COMPAT(默认)或 ENT_NOQUOTES 一起使用时,选择哪一个并不重要(见下文)。我在 SO 上看到了一些答案,归结为:
<input value="<?php echo htmlspecialchars($str, ENT_HTML5);?>" >
这是不安全。它将覆盖默认值ENT_HTML401 | ENT_COMPAT,这与使用 HTML5 实体不同,但 也 引号不再转义!此外,这是冗余代码。必须由htmlspecialchars 编码的实体对于所有ENT_HTML401、ENT_HTML5 等都是相同的。
只需改用ENT_COMPAT 或ENT_QUOTES。当您对属性使用撇号 (value='foo') 时,后者也适用。如果htmlspecialchars 只有两个参数,则根本不要包含该参数,因为它是默认值(ENT_HTML401 是 0,记得吗?)。
当你想在页面上打印一些东西时(在标签之间,而不是属性之间),你选择哪一个并不重要,因为它会产生相同的效果。使用等于数值0 的ENT_NOQUOTES | ENT_HTML401 甚至就足够了。
另见下文,关于 ENT_SUBTITUTE 和 ENT_DISALLOWED。
我应该为 htmlentities 使用什么 ENT_*?
如果您的文本编辑器或数据库太糟糕以至于无法包含非 US-ASCII 字符(例如 UTF-8),您可以使用 htmlentities。否则,请保存一些字节并改用 htmlspecialchars(见上文)。
您是否需要使用ENT_HTML401、ENT_HTML5 或其他方式取决于您的页面的服务方式。如果您有 HTML5 页面 (<!doctype html>),请使用 ENT_HTML5。 XHTML 还是 XML?使用对应的ENT_XHTML 或ENT_XML1。如果没有 doctype 或普通的 HTML4,请使用 ENT_HTML401(省略时为默认值)。
我应该使用 ENT_DISALLOWED、ENT_IGNORE 还是 ENT_SUBSTITUTE?
默认情况下,对给定字符集无效的字节序列会被删除。要使用� 代替无效的字节序列,请指定ENT_SUBSTITUTE。 (请注意,&#FFFD; 显示为非 UTF-8 字符集)。但是,当您指定ENT_IGNORE 时,即使您指定了ENT_SUBSTITUTE,这些字符也不会显示。
当指定ENT_DISALLOWED 时,文档类型 的无效字符将替换为上述相同的替换字符(或其实体)。无论是否设置了ENT_IGNORE(这与文档类型的无效字符无关),都会发生这种情况。