【发布时间】:2011-03-26 11:04:27
【问题描述】:
我通过 PHP 回显发送一个 XML 文档来响应 AJAX 调用。为了形成这个 XML 文档,我遍历了数据库的记录。问题是数据库中包含有“
【问题讨论】:
-
您是否尝试创建一个函数,将所有有意义的字符替换为其 xml 等效项。或者可能在 "" 中包含所有具有潜在字符的值?
我通过 PHP 回显发送一个 XML 文档来响应 AJAX 调用。为了形成这个 XML 文档,我遍历了数据库的记录。问题是数据库中包含有“
【问题讨论】:
从 PHP 5.4 开始,您可以使用:
htmlspecialchars($string, ENT_XML1);
你应该指定编码,例如:
htmlspecialchars($string, ENT_XML1, 'UTF-8');
注意以上只会转换:
& 到 &
< 到 <
> 到 >
如果您想转义文本以用于用双引号括起来的属性:
htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8');
除了&、<和>之外,还将"转换为"。
如果你的属性用单引号括起来:
htmlspecialchars($string, ENT_XML1 | ENT_QUOTES, 'UTF-8');
除了&、<、>和"之外,还会将'转换为'。
(当然你甚至可以在属性之外使用它)。
【讨论】:
htmlspecialchars 不会转义 \xB(垂直选项卡),例如 invalid XML。
我更喜欢 Golang 为 XML 引用转义的方式(以及一些额外的东西,如换行符转义和转义一些其他字符),所以我将它的 XML 转义函数移植到下面的 PHP 中
function isInCharacterRange(int $r): bool {
return $r == 0x09 ||
$r == 0x0A ||
$r == 0x0D ||
$r >= 0x20 && $r <= 0xDF77 ||
$r >= 0xE000 && $r <= 0xFFFD ||
$r >= 0x10000 && $r <= 0x10FFFF;
}
function xml(string $s, bool $escapeNewline = true): string {
$w = '';
$Last = 0;
$l = strlen($s);
$i = 0;
while ($i < $l) {
$r = mb_substr(substr($s, $i), 0, 1);
$Width = strlen($r);
$i += $Width;
switch ($r) {
case '"':
$esc = '"';
break;
case "'":
$esc = ''';
break;
case '&':
$esc = '&';
break;
case '<':
$esc = '<';
break;
case '>':
$esc = '>';
break;
case "\t":
$esc = '	';
break;
case "\n":
if (!$escapeNewline) {
continue 2;
}
$esc = '
';
break;
case "\r":
$esc = '
';
break;
default:
if (!isInCharacterRange(mb_ord($r)) || (mb_ord($r) === 0xFFFD && $Width === 1)) {
$esc = "\u{FFFD}";
break;
}
continue 2;
}
$w .= substr($s, $Last, $i - $Last - $Width) . $esc;
$Last = $i;
}
$w .= substr($s, $Last);
return $w;
}
请注意,由于mb_ord 的使用,您至少需要 PHP7.2,否则您必须将其换成另一个 polyfill,但这些功能对我们非常有用!
对于任何好奇的人,这里是相关的 Go 源代码https://golang.org/src/encoding/xml/xml.go?s=44219:44263#L1887
【讨论】:
添加这个以防它帮助某人。
当我使用日文字符时,编码也已适当设置。但是,我时常发现htmlentities和htmlspecialchars不够用。
某些用户输入包含上述函数未删除的特殊字符。在这些情况下,我必须这样做:
preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string))
这还将删除某些xml-unsafe 控制字符,例如Null character 或EOT。您可以使用此table 来确定要省略哪些字符。
【讨论】:
试试这个:
$str = htmlentities($str,ENT_QUOTES,'UTF-8');
因此,在使用htmlentities() 函数过滤数据后,您可以使用 XML 标记中的数据,例如:
<mytag>$str</mytag>
【讨论】:
如果可能的话,使用 XML 类而不是字符串操作来创建 XML 总是一个好主意 - 好处之一是类会根据需要自动转义字符。
【讨论】:
1) 您可以像这样将文本包装为 CDATA:
<mytag>
<![CDATA[Your text goes here. Btw: 5<6 and 6>5]]>
</mytag>
见http://www.w3schools.com/xml/xml_cdata.asp
2)正如已经有人说过的那样:逃避那些字符。例如。像这样:
5<6 and 6>5
【讨论】:
通过使用htmlspecialchars 转义这些字符,或者更合适的是使用用于构建XML 文档的库,例如DOMDocument 或XMLWriter。
另一种选择是使用 CDATA 部分,但是您必须注意 ]]> 的出现。
还要考虑到您必须尊重您为 XML 文档定义的编码(默认为 UTF-8)。
【讨论】:
&amp;lt; 不适合 XML? htmlspecialchars 实际上只用保证可用于 any XML 文档的实体进行实体替换,甚至留下一个(当它可以使用 &apos; 时将 ' 替换为 &#039;;当然,&#039; 也是正确的)。
htmlspecialchars 对于 XML 可能不够用有一些的原因(即,它不会替换 XML 中的禁止字符,也不会t 在 $double_encode 为 TRUE 时对禁止的实体进行编码)——顺便说一句,我已经通过在主干版本的 htmlspecialchars/entities 中引入配置文件来解决这个问题——但你所说的根本不是真的。您所描述的是双重编码,您需要在 XML 中使用 &amp;lt;,就像在 HTML 中需要它一样——当您需要表示 &amp;lt; 时。