Как PHP внутренне представляет строки?

18

UTF8?
UTF16?

Строки в PHP также отслеживают используемую кодировку?

Давайте посмотрим на этот скрипт для примера. Скажи, что я бегу:

$original = "शक्नोम्यत्तुम्";

Что на самом деле происходит?

Очевидно, я думаю $original, не будет содержать только 7 символов. Эти глифы должны быть представлены несколькими байтами.

Тогда я делаю:

$converted = mb_convert_encoding ($original , "UTF-8");

Что будет с $converted? Как будет $convertedотличаться от $original?

Будет ли это точно такая же последовательность байтов, $originalно с другой кодировкой?

user4951
источник
1
Какая версия PHP? PHP <6 не может обрабатывать нативный UTF-8. Существуют пакеты и методы, которые помогают / решают эту проблему. Google весело с UTF-8 и PHP. Затем переключитесь на другую платформу вместо PHP. :)
Andrew T Finnell
4
PHP <6? Это включало бы каждую версию PHP, когда-либо выпущенную ...
tdammers
1
Кроме того, PHP может обрабатывать UTF-8, у него просто нет выделенного типа данных, поэтому вам нужно посмотреть, что вы делаете.
tdammers

Ответы:

22

Строка PHP - это просто последовательность байтов, без какой-либо кодировки. Строковые значения могут поступать из различных источников: клиента (через HTTP), базы данных, файла или из строковых литералов в вашем исходном коде. PHP читает все это как байтовые последовательности и никогда не извлекает никакой информации о кодировке.

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

Но если кодировки не совпадают (например, вы записываете строковый литерал в исходный файл, сохраненный как UTF-8, а затем отправляете его в базу данных, которая ожидает Latin-1), PHP не выполнит для вас никакого преобразования: счастливо скопировать байты по сырью.

Самое разумное решение:

  • Установите внутреннюю кодировку PHP в UTF-8.
  • Сохраните все ваши исходные файлы как UTF-8.
  • Используйте UTF-8 в качестве выходной кодировки (не забудьте отправить подходящие Content-typeзаголовки).
  • Установите соединение с базой данных для использования UTF-8 ( SET NAMES UTF8в MySQL).
  • Сконфигурируйте все остальное, чтобы оно было UTF-8, если это вообще возможно.
  • Для всего, что вы не можете контролировать (например, сторонние веб-сервисы), убедитесь, что вы знаете кодировку, и конвертируйте в UTF-8 как можно раньше, и возвращайтесь к другой кодировке как можно позже.

Почему UTF-8? Поскольку он может представлять все символы Unicode и, таким образом, заменяет все существующие 7-разрядные и 8-разрядные кодировки, а также потому, что он двоично совместим с ASCII, то есть каждая допустимая строка ASCII также является допустимой строкой UTF-8 (но не vv .).

В вашем примере, что происходит, это.

Сначала вы сохраняете свой исходный файл; ваш текстовый редактор, вероятно, настроен на использование UTF-8, поэтому ваш строковый литерал заканчивается в кодировке UTF-8 на диске. PHP читает этот файл, интерпретируя строку как последовательность байтов; $originalтеперь содержит строку из 7 символов в кодировке UTF-8, которая представляет собой последовательность байтов (хотя она содержит более 7 байтов, поскольку каждый символ представлен двумя или более байтами). Если вы затем позвоните echo $original, закодированная строка будет отправлена ​​клиенту как есть; если вы сказали клиенту ожидать UTF-8, все в порядке, но если нет, PHP не сможет определить разницу, и вы получите мусор в браузере. В качестве эксперимента попробуйте это:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

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

tdammers
источник
Таким образом, $ convert будет представлять ту же строку, но в другой кодировке. Фактическая кодировка, которую хранит PhP, будет другой.
user4951
2
Я повторю это для вас: PHP хранит байты, а не символы, и вообще не знает о кодировках (хотя некоторые библиотечные функции это делают.
tdammers
1
О, и это "PHP", а не "PhP".
tdammers
2
если необработанные байты такие же, какова разница между $ original и $ преобразуются тогда. Это то, что я прошу.
user4951
2
О, хорошо, это то, что вы имеете в виду. Да, необработанные байты изменяются в соответствии с преобразованием кодировки. PHP не помнит кодировку, поэтому, если вы преобразуете строку, скажем, из utf-8 в latin-1, а затем обрабатываете результат как utf-8, вы увидите странные результаты.
tdammers