cakephp 如何使字符串“XML安全”?

0yycz8jy  于 2022-11-24  发布在  PHP
关注(0)|答案(7)|浏览(152)

我通过PHP echos发送一个XML文档来响应 AJAX 调用。为了形成这个XML文档,我遍历了一个数据库的记录。问题是数据库中包含有“〈”符号的记录。所以很自然地,浏览器在那个特定的位置抛出了一个错误。如何修复这个错误?

uidvcgyl

uidvcgyl1#

从PHP 5.4开始,您可以用途:

htmlspecialchars($string, ENT_XML1);

您应该指定编码,例如:

htmlspecialchars($string, ENT_XML1, 'UTF-8');

更新

请注意,以上只会转换:

  • &&
  • <&lt;
  • >&gt;

如果要对用双引号括起来的属性中使用的文本进行转义:

htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8');

除了&<>之外,还将"转换为&quot;
如果属性用单引号括起来:

htmlspecialchars($string, ENT_XML1 | ENT_QUOTES, 'UTF-8');

除了将&<>"转换为&apos;之外,还将'转换为&apos;
(Of当然,您甚至可以在属性之外使用它)。
请参阅the manual entry for htmlspecialchars

oyt4ldly

oyt4ldly2#

通过使用htmlspecialchars对这些字符进行转义,或者更恰当地说,使用用于构建XML文档的库(如DOMDocumentXMLWriter)。
另一种替代方法是使用CDATA节,但这样就必须注意]]>的出现。
还要考虑到,您必须遵守为XML文档定义的编码(默认情况下为UTF-8)。

xpszyzbs

xpszyzbs3#

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&lt;6 and 6&gt;5
nnt7mjpx

nnt7mjpx4#

试试看:

$str = htmlentities($str,ENT_QUOTES,'UTF-8');

因此,在使用htmlentities()函数过滤数据后,可以使用XML标记中的数据,如下所示:

<mytag>$str</mytag>
goqiplq2

goqiplq25#

如果可能的话,使用XML类而不是字符串操作来创建XML总是一个好主意-好处之一是类将根据需要自动转义字符。

li9yvcax

li9yvcax6#

加上这个以防对别人有帮助。
由于我正在处理日语字符,编码也设置得很合适。但是,我不时地发现htmlentitieshtmlspecialchars是不够的。
一些用户输入包含特殊字符,这些字符不能被上述函数去除。在这些情况下,我必须这样做:

preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string))

这也会移除某些xml-unsafe控制字符,例如Null characterEOT。您可以使用此table来决定要省略哪些字符。

k10s72fa

k10s72fa7#

我更喜欢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 = '&#34;';
                break;
            case "'":
                $esc = '&#39;';
                break;
            case '&':
                $esc = '&amp;';
                break;
            case '<':
                $esc = '&lt;';
                break;
            case '>':
                $esc = '&gt;';
                break;
            case "\t":
                $esc = '&#x9;';
                break;
            case "\n":
                if (!$escapeNewline) {
                    continue 2;
                }
                $esc = '&#xA;';
                break;
            case "\r":
                $esc = '&#xD;';
                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来替换它,但是这些函数对我们来说工作得很好!
对于任何好奇的人,这里是相关的围棋资源https://golang.org/src/encoding/xml/xml.go?s=44219:44263#L1887

相关问题