preg_replace无法正常使用Unicode?

时间:2013-12-16 05:07:43

标签: php unicode utf-8 preg-replace

我正在使用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的安全性如何?还有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

在您的代码中,您有:

"a…Œ•a"

其中包含:

  • U + 2026水平省略号
  • Œ U + 0152 Latin capital ligature OE
  • U + 2022 Bullet

正如您所料,Œ是一封信\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"

答案 1 :(得分:0)

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

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