Intereting Posts
Как я могу сделать таблицу во время получения привязки Поместите изображение в другое изображение с помощью PHP Запрос ОЧЕНЬ медленный (> 30 секунд) в php, но быстрый при запуске запроса в phpmyadmin PHP5: Как включить включенную функцию, всегда эхо, если я ее назову? Бесконечное соответствие подвыражений (регулярных выражений) возвращает только одно совпадение Laravel eloquent – Отношения для многих PHP – условный оператор не работает должным образом Как я могу программно вернуть деньги с помощью PayPal? fgetcsv () игнорирует специальные символы, когда они находятся в начале строки! PHP: получить имя браузера Как вы переиндексируете массив в PHP? Как сделать PHP-неэтериализацию jQuery-сериализованной формы? Как получить версию PCRE (в комплекте с PHP) из кода? как отправлять электронную почту с localhost с помощью codeigniter? Загруженное имя файла отправляется через Ajax

Обеспечение правильного utf-8 в PHP

Я использую PHP для обработки текста из разных источников. Я не ожидаю, что это будет нечто иное, чем UTF-8, ISO-8859-1 или, возможно, WINDOWS-1252. Если это что-то другое, кроме одного из них, мне просто нужно убедиться, что текст превращается в действительную строку UTF-8, даже если символы потеряны. Опция // TRANSLIT для iconv разрешает это? Например, сохранит ли этот код безопасную вставку в кодированный UTF-8 документ (или базу данных)?

function make_safe_for_utf8_use($string) { $encoding = mb_detect_encoding($string, "UTF-8,ISO-8859-1,WINDOWS-1252"); if ($encoding != 'UTF-8') { return iconv($encoding, 'UTF-8//TRANSLIT', $string); } else { return $string; } } 

UTF-8 может хранить любой символ Юникода. Если ваша кодировка – это что-то еще, в том числе ISO-8859-1 или Windows-1252, UTF-8 может хранить каждый символ в нем. Поэтому вам не нужно беспокоиться о потере любых символов, когда вы конвертируете строку из любой другой кодировки в UTF-8.

Кроме того, как ISO-8859-1, так и Windows-1252 являются однобайтными кодировками, в которых действителен любой байт. Технически невозможно отличить их. Я бы выбрал Windows-1252 в качестве вашего совпадения по умолчанию для не-UTF-8 последовательностей, так как единственными байтами, которые декодируют по-другому, являются диапазоны 0x80-0x9F. Они декодируются для различных символов, таких как умные кавычки и евро в Windows-1252, тогда как в ISO-8859-1 они являются невидимыми управляющими символами, которые почти никогда не используются. Веб-браузеры иногда говорят, что они используют ISO-8859-1, но часто они действительно будут использовать Windows-1252.

будет ли этот код гарантировать, что строка безопасна для вставки в кодированный UTF-8 документ

Вы, конечно же, хотели бы установить для него необязательный параметр «strict» в TRUE. Но я не уверен, что это действительно охватывает все недопустимые последовательности UTF-8. Функция не претендует на проверку байтовой последовательности для действительности UTF-8. Известны случаи, когда mb_detect_encoding раньше догадывался UTF-8, хотя я не знаю, может ли это произойти в строгом режиме.

Если вы хотите быть уверенным, сделайте это самостоятельно, используя рекомендованное W3 regex :

 if (preg_match('%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*$%xs', $string)) return $string; else return iconv('CP1252', 'UTF-8', $string); 

С библиотекой mbstring у вас есть mb_check_encoding () .

Пример использования:

 mb_check_encoding($string, 'UTF-8'); 

Когда производительность имеет значение, это быстрее, чем регулярное выражение, предоставленное в принятом ответе.

Быстрый тест в моей конфигурации показывает (для 20 000 итераций):

  • regex: ~ 310мс
  • mb_check_encoding: ~ 90 мс

РЕДАКТИРОВАТЬ

С помощью PHP 7.1.9 в последней системе Windows 10 решение regex превосходит mb_check_encoding() для любой длины строки (все еще 20 000 итераций):

  • 10 символов: regex => mb_check_encoding() , mb_check_encoding() => 64ms
  • 10000 символов: regex => 125ms, mb_check_encoding() => 2.4s

Просто заметьте: вместо использования часто рекомендуемого (довольно сложного) регулярного выражения W3C вы можете просто использовать модификатор 'u' для проверки строки для UTF-8:

 <?php if (preg_match("//u", $string)) { // $string is valid UTF-8 } 

Посмотрите http://www.phpwact.org/php/i18n/charsets для руководства по кодировкам. Эта страница ссылается на страницу специально для utf8.

ответ на «iconv is idempotent»

ни один iconv – iconv не является идемпотентным

большая разница между utf8_encode () и iconv () заключается в том, что iconv может приводить к ошибкам, подобным этому «Обнаружен неполный многобайтовый символ во входной строке», даже с

iconv ('ISO-8859-1', 'UTF-8'. '// IGNORE', $ str)

в приведенном выше коде:

$ encoding = mb_detect_encoding ($ string, "UTF-8, ISO-8859-1, WINDOWS-1252");

вы должны знать, что mb_detect_encoding может ответить на uft-8 даже на недопустимые строки utf-8 (плохо сформированный utf8)

Не уверен, достигнет ли это того же, но не мог бы вы просто использовать utf8_encode() для всего текста, не беспокоясь об обнаружении? Если текст уже UTF-8, это не повредит. И если это не так, оно будет преобразовано. Если вы уже подумали об этом, есть ли причина, по которой это не сработает?