我通过PHP回声发送XML文档来响应AJAX调用。为了形成这个XML文档,我遍历数据库的记录。问题是数据库包含具有'<'的记录其中的符号。很自然地,浏览器会在该特定位置抛出错误。如何解决这个问题?
答案 0 :(得分:62)
使用htmlspecialchars
转义这些字符,或者更合适地使用库来构建XML文档,例如DOMDocument或XMLWriter。
另一种选择是使用CDATA部分,但是你必须注意]]>
的出现次数。
还要考虑到您必须遵守为XML文档定义的编码(默认为UTF-8)。
答案 1 :(得分:59)
自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');
除了'
,'
,&
和<
之外,会将>
转换为"
。
(当然你甚至可以在属性之外使用它。)
答案 2 :(得分:9)
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
答案 3 :(得分:5)
如果可能的话,使用XML类而不是字符串操作来创建XML总是一个好主意 - 其中一个好处是类会根据需要自动转义字符。
答案 4 :(得分:5)
试试这个:
$str = htmlentities($str,ENT_QUOTES,'UTF-8');
因此,在使用htmlentities()
函数过滤数据后,您可以使用XML标记中的数据,如:
<mytag>$str</mytag>
答案 5 :(得分:4)
添加此项以防万一。
当我使用日文字符时,编码也已正确设置。但是,我发现htmlentities
和htmlspecialchars
是不够的。
某些用户输入包含未被上述功能剥离的特殊字符。在这些情况下,我必须这样做:
preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string))
这也会删除某些xml-unsafe
控制字符,例如Null character
或EOT
。您可以使用此table来确定要忽略的字符。
答案 6 :(得分:0)
我更喜欢Golang引用XML转义的方式(以及一些额外的内容,比如newline转义,并转义其他一些字符),所以我已将其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,但这些功能对我们来说非常有用! / p>
对于任何好奇的人,这里是相关的Go源https://golang.org/src/encoding/xml/xml.go?s=44219:44263#L1887