【问题标题】:preg_replace not working correctly with Unicode?preg_replace 不能与 Unicode 一起正常工作?
【发布时间】:2013-12-16 05:07:43
【问题描述】:

我正在使用preg_replace 函数过滤掉一些用户输入。下面的函数应该过滤掉 Unicode 中的 控制字符,但似乎其中一些字符被归类为其他类别(标点符号、空格等),从而允许它们通过过滤。为什么会这样?

preg_replace("/[^\p{L}\p{M}\p{N}\p{P}\p{S}]/u", "", $message);

这里有一些使用上述方法通过过滤的 Unicode control characters

U+0085  NEXT LINE (NEL)     …
U+008C  PARTIAL LINE BACKWARD   Œ
U+0095  MESSAGE WAITING     •

DEMO

preg_replace 的安全性如何?有没有更好的方法来做到这一点?

【问题讨论】:

    标签: php unicode utf-8 preg-replace


    【解决方案1】:

    在您的代码中,您有:

    "a…Œ•a"
    

    其中包含:

    • U+2026 水平省略号
    • Œ U+0152 拉丁大写连字 OE
    • U+2022 子弹

    如您所料,Œ 是一个字母 \p{L},另外两个是标点符号 \p{P},所以都允许。

    你被某个资源误导了,有人说 是U+0085,等等;不是这种情况。发生这种情况的可能原因是他们编写了一个 HTML 文件,其中包含数字字符引用 …

    在 HTML 中,引用 €Ÿ 的字符(又名 €Ÿ)实际上并不意味着代码点为 U+0080 到 U+009F 的 Unicode 字符。相反,它们表示在 Windows 代码页 1252(西欧)编码中的编码形式介于 0x80 和 0x9F 之间的字符。代码页 1252 中的字节 0x85 是省略号,因此 … 表示 U+2026 而不是 U+0085。

    这是由于历史原因:古代浏览器中的错误早于对 Unicode 的现代理解,被其他人复制,最后是 standardised by HTML5。 XML 不会出现这种异常:在 XHTML 中,… 确实是 U+0085。

    您的表达式适用于代码点 U+0080-U+009F 中的真实(不可见,“C1”)控制字符:

    function unichr($i) { // get character from code point, in UTF-8 string form
        return iconv('UCS-4LE', 'UTF-8', pack('V', $i));
    }
    
    $message = 'a'.unichr(0x85).unichr(0x8C).unichr(0x95).'a';
    $filtered = preg_replace("/[^\p{L}\p{M}\p{N}\p{P}\p{S}]/u", "", $message);
    var_dump($filtered);
    
    <<< string(2) "aa"
    

    【讨论】:

    • 很荣幸能回答我的问题。你的丰富知识总是给我留下深刻印象。
    【解决方案2】:

    在使用preg_replace() 之前尝试utf8_encode() 喜欢

    preg_replace("/[^\p{L}\p{M}\p{N}\p{P}\p{S}]/u", "", utf8_encode($message));
    

    【讨论】:

    • 不,它将它们转换为其他字符而不是删除。见this demo
    猜你喜欢
    • 2018-11-10
    • 2014-07-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多