Unicode — Понимание кодировки символов в переполнении стека

Я борюсь за понимание кодировки символов в PHP.

Рассмотрим следующий скрипт (вы можете запустить его Вот):

$string = "\xe2\x82\xac";

var_dump(mb_internal_encoding());
var_dump($string);
var_dump(unpack('C*', $string));
$utf8string = mb_convert_encoding($string, "UTF-8");
var_dump($utf8string);
var_dump(unpack('C*', $utf8string));

mb_internal_encoding("UTF-8");

var_dump($string);
var_dump($utf8string);

У меня есть строка, на самом деле символ €, представленный с ее кодовыми точками Unicode. Вплоть до PHP 5.5 используемая внутренняя кодировка ISO-8859-1следовательно, я думаю, что моя строка будет закодирована с использованием этой кодировки. С unpack Я могу видеть представление укуса моей строки, и оно соответствует шестнадцатеричным кодам, которые я использую для определения строки.

Затем я конвертирую кодировку строки в UTF-8, с помощью mb_convert_encoding, В этот момент строка по-разному отображается на экране, и ее представление байтов изменяется (и это ожидается).

Если я изменю PHP внутреннее кодирование также UTF-8Я бы ожидал utf8string правильно отображаться на экране, но этого не происходит.

Чего мне не хватает?

1

Решение

Скрипт, который вы показываете, не использует не-ascii символов, поэтому его внутренняя кодировка не имеет значения. mb_internal_encoding конвертирует ваши данные на выходе Этот вопрос расскажет вам больше о том, как это работает; это также скажет Вам, что лучше не использовать это.

Трехбайтовая строка $string в вашем коде есть представление символа евро в UTF-8, а не его «кодовая точка Юникода» (которая имеет ширину 2 байта, как и все обычные символы Юникода: 0x20ac).

Это проясняет поведение, которое вы видите?

2

Другие решения

Вы начали со строки, которая является utf-8 представление символа евро. Если вы бежите echo($string) все версии PHP производят три байта, которые вы положили в $string, Как они интерпретируются браузером, зависит от набора символов, указанного в Content-Type заголовок. Если это text/html; charset=utf-8 тогда вы получите знак евро на странице визуализации.

Тогда вы делаете неправильный ход. Ты звонишь mb_convert_encoding() только с двумя аргументами. Это позволяет PHP использовать текущее значение своей внутренней кодировки, используемой mb_string расширение для третьего аргумента ($from_encoding). Зачем?

Для PHP 5.6 и новее значение по умолчанию, возвращаемое mb_internal_encoding() является utf-8 и призыв к mb_convert_encoding() это неоперация.

Но для предыдущих версий PHP значение по умолчанию, возвращаемое mb_internal_encoding() является iso-8859-1 и это не соответствует кодировке вашей строки. Соответственно, mb_convert_encoding() интерпретирует байты $string в виде трех отдельных символов и кодирует их, используя правила utf-8, Результат явно неверный.

Кстати, если вы инициализируете $string с '€' вы получаете одинаковый вывод на всех версиях PHP (даже на PHP 4, iirc).

1

По вопросам рекламы [email protected]