代码之家  ›  专栏  ›  技术社区  ›  JayD3e

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

  •  56
  • JayD3e  · 技术社区  · 14 年前

    我通过PHP echos向AJAX调用发送一个XML文档来响应它。为了形成这个XML文档,我遍历了一个数据库的记录。问题是数据库包含的记录具有'<'他们身上的符号。所以很自然,浏览器会在特定的位置抛出一个错误。如何修复?

    7 回复  |  直到 7 年前
        1
  •  68
  •   Artefacto    14 年前

    htmlspecialchars DOMDocument XMLWriter .

    另一种选择是使用CDATA分区,但是您必须注意 ]]> .

        2
  •  84
  •   Sébastien    8 年前

    由于PHP 5.4,您可以使用:

    htmlspecialchars($string, ENT_XML1);
    

    应指定编码,例如:

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

    更新

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

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

    将转换 " &quot; & , < >


    如果属性用单引号括起来:

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

    将转换 ' &apos; & < , > " .

    (当然,您甚至可以在属性之外使用它)。


    the manual entry for htmlspecialchars .

        3
  •  9
  •   Elvith    14 年前

    1) 您可以将文本包装为CDATA,如下所示:

    <mytag>
        <![CDATA[Your text goes here. Btw: 5<6 and 6>5]]>
    </mytag>
    

    看见 http://www.w3schools.com/xml/xml_cdata.asp

    5&lt;6 and 6&gt;5
    
        4
  •  6
  •   DontVoteMeDown    11 年前

    试试这个:

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

    所以,在使用 htmlentities() 函数,您可以使用XML标记中的数据,如:

    <mytag>$str</mytag>
    
        5
  •  5
  •   Ed Schembor    14 年前

        6
  •  4
  •   Reuben L.    9 年前

    加上这个以防万一。

    当我使用日语字符时,编码也被适当地设置。然而,我时不时地发现 htmlentities htmlspecialchars

    某些用户输入包含特殊字符,这些字符不是由上述函数剥离的。在这种情况下,我必须这样做:

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

    这也将删除某些 xml-unsafe 控制字符,如 Null character EOT . 你可以用这个 table 以确定要忽略哪些字符。

        7
  •  0
  •   Brian Leishman    6 年前

    我更喜欢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 使用,否则你将不得不换成另一个polyfill,但这些功能是伟大的工作为我们!

    https://golang.org/src/encoding/xml/xml.go?s=44219:44263#L1887