Я борюсь за понимание кодировки символов в 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
правильно отображаться на экране, но этого не происходит.
Чего мне не хватает?
Скрипт, который вы показываете, не использует не-ascii символов, поэтому его внутренняя кодировка не имеет значения. mb_internal_encoding
конвертирует ваши данные на выходе Этот вопрос расскажет вам больше о том, как это работает; это также скажет Вам, что лучше не использовать это.
Трехбайтовая строка $string
в вашем коде есть представление символа евро в UTF-8, а не его «кодовая точка Юникода» (которая имеет ширину 2 байта, как и все обычные символы Юникода: 0x20ac
).
Это проясняет поведение, которое вы видите?
Вы начали со строки, которая является 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).