LINUX.ORG.RU

[мозговой штурм] Вопросы кодировок в PHP-фреймфорке


0

0

Исторически сложилось, что мой фреймворк работает не просто на системах с разными кодировками (utf-8, windows-1251, koi8-r), но нередко в смешанных условиях (БД отдаёт данные в utf-8, клиент должен получить в windows-1251, файлы лежат в koi8-r, клиент получает в utf-8, контент сайта отдаётся в koi8-r, но RSS отдаюься в utf-8 и т.п. сочетания).

До какого-то момента всё было прекрасно:
1. Все тексты в PHP-коде лежат в utf-8, но при загрузке система переводит их во внутреннюю кодировку системы. Например:

class ... function title() { return ec("Тест"); }

где ec() - функция, осуществляющая перекодировку utf8->internal_charset

2. Все операции над текстом (upper/lower/substr/etc) осуществляются во внутренней кодировке сервера.

3. При выводе происходит преобразование internal_charset -> output_charset.

4. При загрузке данных из пользовательских файлов происходит перекодировка files_charset -> internal_charset

5. При загрузке данных из БД происходит перекодировка db_charset->internal_charset.

6. Все Smarty-шаблоны в utf-8 и при их загрузке перекодируются в internal_charset.

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

И вот тут у меня случится первый затык. Для простоты рассмотрим конкретный пример.

Пусть internal_encoding, кодировка системы, у нас koi8-r. PHP-шаблон, единообразия ради, в utf-8. Без всякого преобразования сразу же получается каша: в utf-8 текст в PHP вставляются koi8-r данные.

Дальше я сделал очевидно, но не для меня тогда, неверное решение. Я волюнтаристски принял, что internal_encoding всегда utf-8. Плюсы были налицо: отпадает надобность в ec("") функциях, так как internal всегда такой же, как у основных шаблонов. В Smarty в {file...} или {include...} вместо своего типа файлов xfile:// [загрузчик которых которых наряду с прочим занимался перекодировкой] можно использовать обычные файлы, без замечания вставляются PHP-шаблоны. И, вообще, приятно жить в хоть как-то унифицированном мире :)

Понятно уже, где всплыл костыль? internal_charset != системной локали PHP. Не работают strtolower/strtoupper/substr...

И вот я теперь стою на перепутье. И прошу советов, как это можно разгрести :)

Первый вариант вижу лобовой. Сейчас частично ситуацию разруливаю им. Ввводим понятие системной кодировки. Т.е. системной локали. Меняем все strtolower() на свою u_lower(), где делаем iconv из внутренней кодировки фреймворка в системную, потом strtolower и обратно во внутреннюю. Плюсы - остаётся унифицированная кодировка фреймворка. По-прежнему нет надобности в ec(). Возможна более тонкая настройка на системах со глючными mb_string и т.п. Минусы - использование своих функций вместо стандартных. Лишняя нагрузка процессора. Небольшая, но если это будет где-то глубоко в цикле?

Второй вариант. internal_charset всегда равен системной локали, в общем случае не равен utf-8. PHP-шаблоны, как и прочее в системе - в utf-8. При загрузке PHP-шаблонов, данные скармливаемые им, предварительно перекодируются из internal в utf-8. Перехваченный вывод потом перекодируется из utf-8 в internal. Плюсы - система может пользоваться стандартными PHP-функциями без оверхеда. Минусы - при обращении из шаблона к другим данным, не поданным непосредственно, в шаблоне нужно перекодирование (скажем, $title я могу перекодировать, а вот $items[0]->title() будет уже в системной кодировке). Придётся использовать функции преобразования из системной кодировки в utf-8. Т.е. если основные данные сможем выводить как есть:

Привет, <?=$title?>,

то внутренние данные уже придётся выводить в чём-то типа

Купите <?dc($items->title())?>,

где dc() занимается преобразованием intrnal -> utf-8. И это тоже некоторый оверхед, особенно, если, опять же, в цикле.

Был в голове ещё какой-то вариант, сейчас вылетел, но он совсем уж безумный :)

Пока я склоняюсь больше ко второму. Всё же, юникод юникодом, но в системе лучше жить в системной кодировке. Позволяет система включить utf8 - отлично. Нет - не нам выбирать... Кроме того, при реализации второго варианта нужно будет переписывать самый минимум готового кода.

Может быть свежий взгляд со стороны подскажет более изящное решение?

★★★★★

Upd: я знаю, что правильно писать всё в utf-8. Более того, в моих личных проектах, или тех, что я пишу на заказ с нуля, всё только в этой кодировке и проблема вообще не встаёт. Поэтому не нужно писать банальность про переход на юникод. Я это знаю. Вопрос про случаи, когда это невозможно.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от kto_tama

Их и нет.

Есть неудобства разного рода костылей, отвечающих за связь вариантов в разных кодировках.

Хочется минимализации оных костылей :)

KRoN73 ★★★★★
() автор топика

ууу, как всё запущено... Тебе поможет такой костыль как russian apache :)

> но в системе лучше жить в системной кодировке.

что это за система что юникод не держит? :).

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

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

>Тебе поможет такой костыль как russian apache :)

Он-то каким боком? Судя по всему, ты вообще не понял проблемы :)

>что это за система что юникод не держит? :

Например, некоторые недорогие хостинги, предоставляющие только windows-1251 и mysql-4.0 или старый боевой сервер, на котором до сих пор стоит FreeBSD 4 и в котором нельзя менять сразу всё по принципу «до основанья, а затем» :)

>PS я уже давно понял что хранить строки не в юникоде это значит заработать бесплатный гемор

Вот поэтому у меня фреймворк внутри весь в юникоде. Но встаёт вопрос, как с ним дальше работать на системах, где с юникодом проблемы. Два своих варианта решения я привёл выше. Но хочется убедиться, что я не упускаю какое-то более изящное решение.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

> Судя по всему, ты вообще не понял проблемы :)

а ты не сказал что речь идёт о говновиртхостингах. А на старой фряшке рашн апач взлетит без проблем. Другое дело он сам может добавить косяков.

> или старый боевой сервер

гы, старая фряшка, как знакомо :). Впрочем, не вижу особых проблем мигрировать на новую систему. Мускул и 4.1 сгодится скорее всего, все конфиги от старого сервера возьмёшь, из портов нужное ПО доставишь, потом /home утянешь и всё. Стырые кривые системы-корень всех зол.

true_admin ★★★★★
()

Я придумал. Заверни все домены на свой сервак, а на нём проксю подними рекодирующую.

true_admin ★★★★★
()
Ответ на: комментарий от KRoN73

>koi8-r окружение в PHP

дык, а тупо iconv? не? что мешает?

(имхо, самый радикальный, простой и быстрый способ решения этой проблемы)

ps: чото повалили проблемы с пхп. весенне обострение? :)

grinn ★★
()
Ответ на: комментарий от grinn

>дык, а тупо iconv? не? что мешает?

Я же рассматривал в первом сообщении плюсы и минусы.

...

В итоге сошёлся на варианте, когда внутренняя кодировка фреймворка, всё же, такая же, как системная, а шаблоны (и прочее) конвертируются при загрузке. Второй, кажется (лень откручивать, чтобы посмотреть), вариант в первом сообщении.

KRoN73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.