Рядок 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-бітове кодування фіксованої ширини, тобто один байт на символ, тому він буде рахувати байти, а не символи.