Як PHP внутрішньо представляє рядки?


18

UTF8?
UTF16?

Чи також рядки в PHP відслідковують використовуване кодування?

Давайте розглянемо, наприклад, цей сценарій. Скажіть, я бігаю:

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

Що насправді відбувається?

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

Тоді я роблю:

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

Що буде $converted? Чим вони $convertedбудуть відрізнятися від $original?

Чи буде це точно та сама послідовність байтів, як $originalі з іншим кодуванням?


1
Яка версія PHP? PHP <6 не може працювати з нативною UTF-8. Існують пакети та методи, які допомагають / вирішують цю проблему. Google весело з utf-8 та php. Потім перейдіть на іншу платформу замість PHP. :)
Ендрю Т Фіннелл

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тепер міститься кодована рядок UTF-8 із 7 символів, що є лише послідовністю байтів (хоча вона містить більше 7 байт, оскільки кожен символ представлений двома або більше байтами). Якщо потім зателефонувати echo $original, кодована рядок надсилається клієнтові як є; якщо ви сказали клієнтові очікувати UTF-8, все нормально, але якщо ви цього не зробили, PHP не має можливості сказати різницю, і ви потрапите в смітник у смітник. В якості експерименту спробуйте це:

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

strlen є кодувально-агностичним і передбачає 8-бітове кодування фіксованої ширини, тобто один байт на символ, тому він буде рахувати байти, а не символи.


Тож перетворений $ буде представляти той самий рядок, але в іншому кодуванні. Фактична сира кодування, яка зберігається в PHP, буде різною.
user4951

2
Я повторю це для вас: PHP зберігає байти, а не символи, і він взагалі не знає про кодування (хоча деякі функції бібліотеки роблять.
tdammers

1
О, і це "PHP", а не "PHP".
tdammers

2
якщо необроблені байти є однаковими, яка різниця між $ оригіналом і перетвореним $. Це я прошу.
user4951

2
О, гаразд, саме так ви маєте на увазі. Так, необроблені байти змінюються відповідно до перетворення кодування. PHP не пам’ятає кодування, тому, якщо ви перетворите рядок з, скажімо, utf-8 в latin-1, а потім трактуєте результат як utf-8, ви побачите дивні результати.
tdammers
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.