【问题标题】:How do I best remove the unicode characters that XHTML regards as non-valid using php?如何最好地删除 XHTML 认为使用 php 无效的 unicode 字符?
【发布时间】:2010-04-13 07:43:56
【问题描述】:

我经营一个旨在支持国际数学小组的论坛。我最近将其切换为 unicode 以更好地支持国际字符。在调试此转换时,我发现并非所有 unicode 字符都被视为有效的 XHTML(相关网站似乎是 http://www.w3.org/TR/unicode-xml/)。论坛软件在将帖子呈现给浏览器之前要经过的步骤之一是 XHTML 验证/清理步骤。在那个阶段,它应该删除任何 XHTML 不喜欢的 unicode 字符,这似乎是一个合理的想法。

所以我的问题是:

在 PHP 中是否有标准(或最佳)方法?

(顺便说一下,论坛是用 PHP 编写的。)

我猜故障保护将是一个简单的str_replace(如果这也是最好的,我是否需要做任何额外的事情以确保它与 unicode 一起正常工作?)但这将涉及我必须通过 XHTML DTD(或上面引用的 W3 页面)仔细找出要在 str_replacesearch 部分列出哪些字符,所以如果这是最好的方法,有人已经这样做了,所以我会偷,会犯错,会抄袭吗?

(顺便说一句,导致问题的字符是 U+000C,即“formfeed”,它(根据 W3 页面)是有效的 HTML 但无效的 XHTML!)

【问题讨论】:

    标签: php xhtml unicode


    【解决方案1】:

    我找到了一个可以做你想做的事情的函数 phpedit.net.

    我将发布存档函数,感谢 PHPEdit.net 上的 ltp:

    /**
     * Removes invalid XML
     *
     * @access public
     * @param string $value
     * @return string
     */
    function stripInvalidXml($value)
    {
        $ret = "";
        $current;
        if (empty($value)) 
        {
            return $ret;
        }
    
        $length = strlen($value);
        for ($i=0; $i < $length; $i++)
        {
            $current = ord($value{$i});
            if (($current == 0x9) ||
                ($current == 0xA) ||
                ($current == 0xD) ||
                (($current >= 0x20) && ($current <= 0xD7FF)) ||
                (($current >= 0xE000) && ($current <= 0xFFFD)) ||
                (($current >= 0x10000) && ($current <= 0x10FFFF)))
            {
                $ret .= chr($current);
            }
            else
            {
                $ret .= " ";
            }
        }
        return $ret;
    }
    

    【讨论】:

    • 我猜这比 preg_replace 方法快(尤其是考虑到php.net/manual/en/regexp.reference.unicode.php 上关于速度的评论),但同样的缺点是我必须找出自己的白名单! (请参阅上面关于懒惰的评论!)
    • 您不必自己找出白名单。允许使用基于 ASCII 代码的字符,当它们超出函数指定的范围时,它们将被替换为空格。我很确定这就是您所需要的,白名单已经在函数中。
    • 该函数中当然有一个白名单,但我怎么知道它是正确的白名单?例如,0xC 在 HTML 中是允许的,但在 XHTML 中是不允许的。如果我在白名单中工作,它应该以某种方式从 DTD 生成。
    • 0xC 在此函数中被过滤,所有其他 XML 文档中不允许的字符也是如此。为什么需要从 DTD 生成白名单?只需从数据库中检索帖子,通过此函数将它们输出为 XHTML。
    • 我需要从 DTD 生成一个白名单,因为不同的 DTD 允许不同的实体列表。 0xC 在 HTML 中允许的。
    【解决方案2】:

    假设您的输入是 utf8,您可以使用类似的东西删除 unicode 范围

     preg_replace('~[\x{17A3}-\x{17D3}]~u', '', $input);
    

    另一种更好的方法是默认删除所有内容,并且只删除您想查看的白名单字符。 Unicode 属性 (\p) 对此非常实用。例如,删除除 (unicode) 字母和数字之外的所有内容:

      preg_replace('~[^\p{L}\p{N}]~u', '', $input)
    

    【讨论】:

    • 我对这两种方法的问题是我必须通过 DTD 来提取要匹配的白名单或黑名单。我有点希望有人已经为我做到了!我不认为所有那些有效 XHTML 的字符都有一个 '\p{XHTML}',是吗? (我是一名数学家,我们基本上是一群懒惰的人——如果其他人已经解决了这个问题,那么我们就不想再麻烦了!)
    • 我也不知道这样的解决方案,但如果您正在寻找快速简便的方法,您可以简单地将字母-数字-标点符号以外的所有内容转换为数字实体。
    • 将“所有内容除外”转换为实体不起作用。如果我在有效集合之外发送一个字符,即使编码为实体,浏览器也会抱怨。 (我或许应该明确说明我正在使用 XHTML+MathML,因此它必须 100% 有效——我不能依赖浏览器忽略无效实体。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 2016-02-16
    • 2011-09-22
    • 2018-05-08
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    相关资源
    最近更新 更多