2013-12-16 3 views
1

Я использую функцию 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? И есть ли лучший способ сделать это?

ответ

3

В вашем коде у вас есть:

"a…Œ•a" 

Который содержит:

  • U + 2026 Горизонтальное многоточие
  • Œ U + 0152 Latin капитал лигатуры OE
  • U + 2022 Пуля

Как и следовало ожидать, Œ это письмо \p{L}, а два других являются пунктуация \p{P}, так что все разрешено.

Вы были введены в заблуждение ресурсом где-то, где кто-то сказал, что - U + 0085 и т. Д .; это не тот случай. Вероятная причина этого заключается в том, что они написали HTML-файл с цифрой ….

В HTML символ ссылается на €Ÿ (ака € к Ÿ) на самом деле не означают символы Unicode с U + кодовых 0080 до U + 009F. Вместо этого они означают символы, чья кодированная форма в кодировке Windows 1252 (западноевропейская) кодируется между 0x80 и 0x9F. Байт 0x85 на кодовой странице 1252 является многоточием, поэтому … означает U + 2026, а не U + 0085.

Это связано с историческими причинами: ошибки в древних браузерах, которые предшествовали современному пониманию Unicode, скопированы другими и, наконец, standardised by HTML5. XML не страдает от этой аномалии: в XHTML … действительно U + 0085.

Ваше выражение хорошо работает для реальных (невидимых, "C1") управляющих символов в кодовых U + 0080-U + 009F:

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" 
+0

Для меня большая честь ответить на мой вопрос. Вы никогда не перестанете впечатлять меня своим богатством знаний. –

0

Try utf8_encode() перед использованием preg_replace() как

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

Неа, он преобразует их в другие символы вместо удаления. См. [Это демо] (http://ideone.com/JcREGG) –

Смежные вопросы