Подтвердить что ты не робот

Я правильно поддерживаю UTF-8 в своих PHP-приложениях?

Я хотел бы убедиться, что все, что я знаю о UTF-8, является правильным. Я пытаюсь использовать UTF-8 некоторое время, но я продолжаю спотыкаться о все больше и больше ошибок и других странных вещей, из-за которых почти невозможно иметь 100% -ный сайт UTF-8. Где-то всегда есть что-то, что я, кажется, пропущу. Возможно, кто-то здесь может исправить мой список или ОК, поэтому я не пропущу ничего важного.

База данных

Каждый сайт должен где-то хранить данные. Независимо от ваших настроек PHP вы также должны настроить БД. Если вы не можете получить доступ к файлам конфигурации, убедитесь, что как только вы подключитесь, " УСТАНОВИТЬ НАЗВАНИЯ" utf8 ". Кроме того, не забудьте использовать utf8_ unicode_ ci для всех ваших таблиц. Это предполагает MySQL для базы данных, вам придется изменить для других.

Regex

Я делаю LOT регулярного выражения более сложный, чем ваш средний поиск. Я должен помнить, чтобы использовать модификатор "/u", чтобы PCRE не искажает мои строки. Тем не менее, даже тогда есть все еще проблемы, видимо,.

Строковые функции

Все строковые функции по умолчанию (strlen(), strpos() и т.д.) должны быть заменены на Многобайтовые строковые функции, которые выглядят в символе вместо байта.

Заголовки Вы должны убедиться, что ваш сервер возвращает правильный заголовок для браузера, чтобы узнать, какую кодировку вы пытаетесь использовать (точно так же, как вы должны сообщить MySQL).

header ('Content-Type: text/html; кодировка = UTF-8' );

Также неплохо поставить правильную <meta> в заголовке страницы. Хотя фактический заголовок будет отменять это, если они будут отличаться.

<meta http-equiv="Content-Type" content="text/html;charset=utf-8">

Вопросы

Нужно ли мне конвертировать все, что я получаю от пользовательского агента (HTML-форма и URI) в UTF-8, когда загружается страница, или если я могу просто оставить строки/значения так, как они есть, и по-прежнему запускать их через эти функции без проблем?

Если мне нужно преобразовать все в UTF-8, то какие шаги я должен предпринять? mb_detect_encoding, похоже, для этого построено, но я все вижу, что люди жалуются, что он не всегда работает. mb_check_encoding также, похоже, проблема, говорящая о хорошей строке UTF-8 из искаженной.

Сохраняет ли PHP строки в памяти по-разному в зависимости от того, какую кодировку он использует (например, типы файлов), или он все еще хранится как обычное жало, причем некоторые из символов интерпретируются по-разному (например, vs и in HTML). chazomaticus отвечает на этот вопрос:

В PHP (до PHP5, во всяком случае), строки это просто последовательности байтов. Там есть не подразумеваемый или явный набор символов связанные с ними; это что-то программист должен отслеживать.

Если a дать строку non-UTF-8 функции mb_ *, она когда-нибудь вызовет проблему?

Если строка UTF неправильно закодирована, что-то пойдет не так (например, ошибка синтаксического анализа в регулярном выражении?) или она просто пометит объект как плохой (html)? Есть ли вероятность, что неправильно закодированные строки приведут к возврату функции FALSE, потому что строка плохая?

Я слышал, что вы также должны указывать свои формы как UTF-8 (accept-charset = "UTF-8" ), но я не уверен, что это преимущество..?

Был ли написан UTF-16 для ограничения лимита в UTF-8? Как UTF-8 заканчивается для символов? (У2 (UTF) K & alpha;)

Функции

Вот пара пользовательских функций PHP, которые я нашел, но у меня нет никакого способа проверить, что они действительно работают. Возможно, у кого-то есть пример, который я могу использовать. Сначала convertToUTF8(), а затем seem_utf8 из wordpress.

function seems_utf8($str) {
    $length = strlen($str);
    for ($i=0; $i < $length; $i++) {
        $c = ord($str[$i]);
        if ($c < 0x80) $n = 0; # 0bbbbbbb
        elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
        elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
        elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
        elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
        elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
        else return false; # Does not match any model
        for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
            if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
                return false;
        }
    }
    return true;
}

function is_utf8($str) {
    $c=0; $b=0;
    $bits=0;
    $len=strlen($str);
    for($i=0; $i<$len; $i++){
        $c=ord($str[$i]);
        if($c > 128){
            if(($c >= 254)) return false;
            elseif($c >= 252) $bits=6;
            elseif($c >= 248) $bits=5;
            elseif($c >= 240) $bits=4;
            elseif($c >= 224) $bits=3;
            elseif($c >= 192) $bits=2;
            else return false;
            if(($i+$bits) > $len) return false;
            while($bits > 1){
                $i++;
                $b=ord($str[$i]);
                if($b < 128 || $b > 191) return false;
                $bits--;
            }
        }
    }
    return true;
}

Если кому-то интересно, я нашел отличную страницу примеров, чтобы использовать при тестировании UTf-8.

4b9b3361

Ответ 1

Нужно ли мне преобразовать все, что я получаю из пользовательского агента (HTML-форма и URI) в UTF-8, когда страница загружается

Нет. Пользовательский агент должен отправлять данные в формате UTF-8; если вы не теряете пользу Unicode.

Способ обеспечения того, чтобы пользовательский агент отправлялся в формате UTF-8, должен обслуживать страницу, содержащую форму, которая она отправляет в кодировке UTF-8. Используйте заголовок Content-Type (и meta http-equiv тоже, если вы намерены сохранить форму и работать автономно).

Я слышал, что вы также должны отмечать свои формы как UTF-8 (accept-charset = "UTF-8" )

не делать. Это была хорошая идея в стандарте HTML, но IE так и не понял. Предполагалось указать исключительный список допустимых кодировок, но IE рассматривает его как список дополнительных кодировок, чтобы попытаться на основе каждого поля. Поэтому, если у вас есть страница ISO-8859-1 и форма "accept-charset =" UTF-8 ", IE сначала попытается закодировать поле как ISO-8859-1, а если есть не-8859-1 персонажа, тогда он прибегнет к UTF-8.

Но так как IE не говорит вам, что он использовал ISO-8859-1 или UTF-8, это абсолютно бесполезно для вас. Вы должны были бы угадать, для каждого поля отдельно, какая кодировка использовалась! Не полезно. Опустите атрибут и покажите свои страницы как UTF-8; что лучшее, что вы можете сделать в данный момент.

Если строка UTF неправильно закодирована, что-то пойдет не так.

Если вы позволите такой последовательности пройти через браузер, у вас могут быть проблемы. Существуют "перекрывающиеся последовательности", которые кодируют кодовую точку с низким номером в более длинной последовательности байтов, чем это необходимо. Это означает, что если вы фильтруете '< путем поиска этого символа ASCII в последовательности байтов, вы можете пропустить его, и пусть элемент script в то, что вы считали безопасным текстом.

В первые дни Unicode были отменены лишние последовательности, но Microsoft потребовала очень много времени, чтобы собрать свое дерьмо: IE интерпретирует последовательность байтов '\ xC0\xBC как' < до IE6 Service Pack 1. Opera также ошибалась до версии (примерно, я думаю) версии 7. К счастью, эти старые браузеры вымирают, но по-прежнему стоит фильтровать последовательности с перекрытием в случае, если эти браузеры все еще сейчас (или новый идиот браузеры совершают ту же ошибку в будущем). Вы можете сделать это и исправить другие неудачные последовательности, с регулярным выражением, которое позволяет использовать только правильный UTF-8, например этот из W3.

Если вы используете функции mb_ в PHP, вы можете быть изолированы от этих проблем. Я не могу точно сказать, что mb_ * был непригодным для использования, когда я все еще писал PHP.

В любом случае, это также хорошее время для удаления управляющих символов, которые являются большим и вообще недооцененным источником ошибок. Я бы удалил символы 9 и 13 из поданной строки в дополнение к остальным, которые вызывается регулярным выражением W3; также стоит удалить простые строки для строк, которые, как вы знаете, не должны быть многострочными текстовыми полями.

Был ли написан UTF-16 для ограничения лимита в UTF-8?

Нет, UTF-16 представляет собой кодировку с двумя байтами на кодовую точку, которая используется для упрощения индексирования строк Unicode в памяти (с тех пор, как весь Unicode будет вписываться в два байта, системы, такие как Windows и Java, все еще делают это так). В отличие от UTF-8, он несовместим с ASCII и практически не используется в Интернете. Но вы иногда встречаете его в сохраненных файлах, обычно сохраняемых пользователями Windows, которые были введены в заблуждение по описанию Windows UTF-16LE как "Unicode" в меню Save-As.

seems_utf8

Это очень неэффективно по сравнению с регулярным выражением!

Кроме того, обязательно используйте utf8_unicode_ci для всех ваших таблиц.

На самом деле вы можете избавиться без этого, рассматривая MySQL как хранилище только для байтов и только интерпретируя их как UTF-8 в своем script. Преимущество использования utf8_unicode_ci заключается в том, что он будет сопоставлять (сортировать и делать нечувствительные к регистру сравнения) знания о не-ASCII-символах, так, например. "Ŕ" и "Ŕ" - один и тот же символ. Если вы используете не-UTF8 сопоставление, вы должны придерживаться двоичного (с учетом регистра) соответствия.

Какой бы вы ни выбрали, выполните его последовательно: используйте тот же набор символов для своих таблиц, что и для своего подключения. То, что вы хотите избежать, - это преобразование набора символов с потерями между вашими сценариями и базой данных.

Ответ 2

Большая часть того, что вы делаете сейчас, должна быть правильной.

Некоторые примечания: любая сортировка utf_* в MySQL будет хранить ваши данные правильно как UTF-8, единственная разница между ними - это сортировка (алфавитный порядок), применяемая при сортировке.

Вы можете сообщить Apache и PHP о том, чтобы задать правильные заголовки charset AddDefaultCharset utf-8 в httpd.conf/.htaccess и default_charset = "utf-8" в php.ini соответственно.

Вы можете указать расширение mbstring, чтобы заботиться о строковых функциях. Это работает для меня:

mbstring.internal_encoding=utf-8
mbstring.http_output=UTF-8
mbstring.encoding_translation=On
mbstring.func_overload=6

(это оставляет функцию mail() нетронутой - я обнаружил, что установил ее в 7 разыгранных с помощью моих почтовых заголовков)

Для преобразования charset посмотрите https://sourceforge.net/projects/phputf8/.

PHP совсем не заботится о том, что в переменной, он просто хранит и получает слепо его содержимое.

У вас появятся неожиданные результаты, если вы объявите один mbstring.internal_encoding и поставьте строки функций mb_ * в другой кодировке. Вы также можете безопасно отправлять ASCII в функции utf-8.

Если вы беспокоитесь о том, что кто-то публикует неправильно закодированные материалы, я считаю, что вы хотите рассмотреть HTML Purifie r для фильтрации данных GET/POST до обработка.

Accept-charset был в спецификации с тех пор навсегда, но его реальная поддержка в браузерах более или менее нулевая. Браузер будет типично использовать кодировку на странице, содержащей форму.

UTF-16 не является большим братом UTF-8, он просто служит другой цели.

Ответ 3

database/mysql: Если вы используете SET NAMES и, например, php/mysql вы покидаете mysql_real_escape_string() в темноте об изменении кодировки символов. Это может привести к неправильным результатам. Итак, если вы полагаетесь на функцию escape, такую ​​как mysql_real_escape_string (потому что вы не используете подготовленные операторы) SET NAMES является субоптимальным решением. Вот почему mysql_set_charset() был введен или почему gentoo применяет патч, который добавляет параметр конфигурации mysql.connect_charset для php/mysql и php/MySQLi.

Клиент обычно не указывает кодировку параметров, которые он отправляет. Если вы ожидаете, что данные utf-8, закодированные , и рассматривают их как таковые, могут быть ошибки кодирования (байтовые последовательности, которые недействительны в utf-8). Таким образом, данные могут отображаться не так, как ожидалось, или синтаксический анализатор может прервать разбор. Но, по крайней мере, пользовательский ввод не может "убежать" и принести больше вреда, например. в встроенной инструкции sql или выходе html. Например. возьмите script (сохраненный как iso-8859-1 или utf-8, не имеет значения)

<?php
$s = 'abcxyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));
// adding the byte sequence for äöü in iso-8859-1
$s = 'abc'. chr(0xE4) . chr(0xF6) . chr(0xFC). 'xyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));

печатает

string(6) "abcxyz"
string(0) ""

E4F6FC не является допустимой последовательностью байтов utf-8, поэтому htmlspecialchars возвращает пустую строку. Другие функции могут вернуться? или другой "особый" характер. Но, по крайней мере, они не будут "ошибочно" воспринимать персонажа как злонамеренного контрольного персонажа - если все они придерживаются "правильной" кодировки (в данном случае - utf-8).

accept-charset не гарантирует, что вы получите только данные с этой кодировкой. Насколько вам известно, клиент может даже не "использовать" /анализировать ваш html-документ, содержащий элемент формы. Это может помочь, и нет причин, по которым вы не должны устанавливать этот атрибут. Но это не "надежный".

Ответ 4

UTF-8 в порядке и не имеет ограничений, разрешаемых UTF-16. PHP не меняет способ хранения строк в памяти (в отличие от Python). Если весь поток данных использует UTF-8 (веб-формы получают данные UTF-8, в таблицах используется кодировка utf8, и вы используете SET NAMES utf8, а данные сохраняются без изменения (без преобразования кодировки), это должно быть хорошо.

Ответ 5

Для пользовательских входов из формы я добавляю этот атрибут в теги form: accept-charset="utf-8". Таким образом, данные, которые вы получаете, всегда должны быть закодированы в utf-8.