1

Тема: Заготовка FAQ по UTF-8

Благодаря hcs вы можете не заморачиваться, а взять готовую сборку для UTF-8 здесь: (Please log in or register to see this URL) hcs регулярно обновляет ее, когда обнаруживается что-то новое.

Тем не менее, для любознательных пишу этот FAQ. Это "заготовка", потому что пока нет уверенности, что учтены все нюансы. Чем больше мы знаем, тем больше убеждаемся что не знаем ничего. Я буду постоянно править и дополнять FAQ, а лишние комментарии чистить, чтобы легче читалось.

Итак:

Что нужно сделать, чтобы перевести действующий форум на кодировку страниц UTF-8
0. Вы должны перекодировать все русские сообщения в языковых файлах из window-1251 или koi-8 в UTF-8. Для этого вам понадобятся умные редакторы вроде akelpad или PHP Exper Editor.

1. В языковом файле lang/Russian/comon.php надо указать новую кодировку страниц

// Determine what locale to use
switch (PHP_OS)
{
    case 'WINNT':
    case 'WIN32':
        $locale = 'russian';
        break;

    case 'FreeBSD':
    case 'NetBSD':
    case 'OpenBSD':
        $locale = 'ru_RU.utf-8';
        break;

    default:
        $locale = 'ru_RU';
        break;
}

// Attempt to set the locale
setlocale(LC_CTYPE, $locale);
setlocale(LC_TIME, $locale);

// Language definitions for frequently used strings
$lang_common = array(

// Text orientation and encoding
'lang_direction'        =>    'ltr',    // ltr (Left-To-Right) or rtl (Right-To-Left)
'lang_encoding'            =>    'utf-8',
'lang_multibyte'        =>    true,

я рекомендую вставить такие lang_encoding и lang_multibyte во все языки! Тогда независимо от языка интерфейса пользователи будут видеть неискаженный текст на других языках.

2. в файле include/dblayer/mysql.php сразу за if ($this->link_id) надо указать что мы работаем с данными в уникоде:

        if ($this->link_id)
        {
            @mysql_query("SET NAMES 'utf8'");

Обратите внимание: здесь utf8 пишется без дефиса!
Когда вы укажете такое, сервер MySQL перестанет конвертировать данные из своего внутреннего unicode-представления в windows-1251

3. Функции strlen, strtolower, strtoupper не умеют работать с мультибайтной кодировкой. Выход такой:

3a. в include/common.php после подключения языкового файла укажем, что будет использоваться UTF-8.

@include PUN_ROOT.'lang/'.$pun_user['language'].'/common.php';
if (!isset($lang_common))
    exit('There is no valid language pack \''.pun_htmlspecialchars($pun_user['language']).'\' installed. Please reinstall a language of that name.');
mb_internal_encoding('UTF-8');

3b. Во всех *.php находим и заменяем strlen на mb_strlen, strtolower на mb_strtolower, strtoupper на mb_strtoupper.
Особый случай - функция pun_strlen() в include/functions.php Она измеряет длинну строки с учетом символов в виде &#nnn.
Она должны выглядеть так:

function pun_strlen($str)
{
    // FIX FOR UTF-ENCODING 
    // Original:
    //return strlen(preg_replace('/&#([0-9]+);/', '!', $str));
    // Tested, but not valid:
    //return mb_strlen(preg_replace('/&#([0-9]+);/', '!', $str), 'UTF-8');
    return strlen(utf8_decode($str));
}

4. По непонятным причинам в файле seach.php предусмотрен альтернативный поиск для мультибайтных кодировок. Работает он не совсем корректно. Мы избавимся от этого
находим строчку "$multibyte =", делаем так:

// UTF FIX BEGIN
// ORIGINAL:
//$multibyte = (isset($lang_common['lang_multibyte']) && $lang_common['lang_multibyte']) ? true : false;
$multibyte = false;
// UTF FIX END

После этих изменений форум должен нормально отображать и принимать русский текст, кодировка страниц при этом будет UTF-8. Мы ничего не изменили в бызе MySQL, но работать уже можем!

Я хочу использовать кроме русского и другие языки. Например, французский. При сохранении сообщения символы с "умляутами" портятся. Как исправить?

Для полной "уникодизации" необходимо изменить collation таблиц в БД на utf8_general_ci или иной utf8_ порядок сравнения.
Исключение - поле search_words.word. Она должна иметь collation binary. Сменить collation можно в phpMyAdmin.

Если форум ставится заново, откройте install.php и добавьте модификатор utf8 рядом со всеми полями типа varchar, типа такого:

`message` text character set utf8

ошибка "Unable to insert search index words"

Ошибка происходит из-за попытки записать в таблицу неуникальное слово. Дело в том, что при записи в базу стрОки обрезаются до длины поля, поэтому длинные слова, различающиеся последними символами станут одинаковыми. Поле search_words.word изначально расчитано на слова длиной до 20 (однобайтовых) символов. Кирилические символы в UTF-8 занимают два байта. Другие алфавиты могут потребовать три байта на символ.

Необходимо убедиться, что
- поле search_words.word имеет collation BINARY либо само поле типа VARBINARY (зависит от версии MySQL)
- длина поля не менее 40 (20 символов * 2 байта или 13 символов * 3 байта)
т.е. нормальный вид поля word VARBINARY(40)

В файле include/search_idx.php найти функцию split_words и в ней заменить условие на максимальную длину слова. Вот как должен выглядеть этот фрагмент:

            $num_chars = strlen($word);

            if ($num_chars < 3 || $num_chars > 40 || in_array($word, $stopwords))
                unset($words[$i]);

Обратите внимание на немультибайтную strlen - здесь нам надо вычислить длину строки в байтах, а не символах!

Если ошибка уже случилась, надо очистить таблицу search_words и полечить ее в myPHPadmin, затем провести переиндексацию в админке форума (раздел Maintenance)

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

2

Re: Заготовка FAQ по UTF-8

поиск в "официальных местах" - punbb.org и punres.org дал мне только одну стоящую ссылку
Indexing is not unicode-safe: (Please log in or register to see this URL)

другие полезные ссылки я почерпнул из того топика
(Please log in or register to see this URL)
(Please log in or register to see this URL)

В последней ссылке есть Function Overloading Feature - подмена однобайтных функций на мультибайтные через настройки php.ini или .htaccess. Кому-то покажется удобнее делать именно так, хотя там же дается предупреждение, что это небезопасно.

update: так мы можем упустить случаи, когда нам все-таки больше подходит однобайтная функция - см. FAQ, пункт про ошибку index words

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

3

Re: Заготовка FAQ по UTF-8

Однажды очень много времени потратил на изучение проблем UTF-8 в PHP, так как хотел реализовать нормальный регистронезависимый поиск в (Please log in or register to see this URL). Рекомендую обратить внимание на то, что (Please log in or register to see this URL). Оттуда я почерпнул больше всего информации в понятной для меня (не специалиста) форме.

(Please log in or register to see this URL)

Сайт BrokenBrake

Поделиться

4

Re: Заготовка FAQ по UTF-8

Еще раз, углубленно и с особым цинизмом:

Плевать в какой кодировке работаем, надо чтобы все обслуживающие программы знали с какой кодировкой работают в данный момент.

Цепочка программ такая: браузер - вебсервер - php_с_клиентом_msql - сервер_mysql

Есть кодировка страниц, а есть кодировка данных в таблицах БД. Они могут совпадать, а могут и не совпадать! Между ними есть невидимая "труба" — клиент mysql. Он ВСЕГДА пытается перекодировать данные с кодировки базы в кодировку страниц и обратно.

Клиент mysql точно знает какая кодировка в таблице - там она указана. Про кодировку страниц клиент строит предположения. Чтобы подсказать ему правильное решение мы можем дать команду SET NAMES.

ИТОГО: для правильной работы с русским текстом надо обеспечить следующие условия:
1. Таблицы должны иметь русский (cp1251, koi8r) или уникодный (utf8) чарсет. Лучше всего настроить такой чарсет по-умолчанию для своей базы ПЕРЕД установкой форума. Или в install.php указывать [search]default charset[/search] для всех CREATE TABLE. Коллейшн (порядок сортировки) зависит от чарсета. Если вы указали правильный чарсет, коллейшн сам подставится правильный.
2. В php скриптах сразу после соединения с базой надо явно указывать кодировку html. То есть прописать [search]SET NAMES[/search].

Если эти два условия соблюдены, ваши данные будут белыми и пушистыми. Иначе может вылезти лажа, причем может вылезти не сразу, а когда вам будет чего терять. Заметьте: здесь я говорю не только про utf и не только про PunBB, эти правила универсальные, относятся к любым кодировкам и скриптам.
ВСЕГДА ПРОПИСЫВАЙТЕ КОДИРОВКИ ЯВНО! НЕ ПОЛАГАЙТЕСЬ НА УДАЧУ!

Проверено: данные в базе могут быть в любой из русских кодировок или utf8, кодировка страниц может быть в любой (другой) из русских кодировок или utf8 и все будет работать ништяк, пока мы соблюдаем пп.1 и 2. ... с русским и английским текстом будет работать.
НО! Если вы хотите, хотябы изредка, вставлять в сообщения символы из иных кодировок: французский, литовский, китайский и т.д., спецсимволы какие-нибудь научные — используйте UTF-8 на обоих концах. С AJAX проще работать при UTF-8. Человекопонятные УРЛы с русским текстом — UTF-8...

Update:
Бывает такое: что бы мы не прописали в <meta ... Content-Type ... chasert ... /> браузер самонастраивается на одну кодировку, например на windows-1251. Это значит, что Apache подставляет в заголовок http свое сообщение про кодировку. А зря... Грешат этим русские провайдеры.
Исправить можно опять-таки указывая ЯВНО свою кодировку в файле .htaccess командой [search]AddDefaultCharset[/search]. Тогда Apache будет подставлять в заголовок то, что нам надо.

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

5

Re: Заготовка FAQ по UTF-8

дополнение: скрипт установки install.php сам определяет доступный интерфейс БД: mysql или mysqli. пропустить этот момент очень легко, но разница есть! если у вас mysqli, то в файл конфигурации config.php пропишется

$db_type = 'mysqli';

форум будет использовать файл mysqli.php , а не mysql.php. а значит чтобы вы там не писа́ли в mysql.php, не будет никакого эффекта. вот как выглядит правильный фрагмент в [size=16]mysqli.php[/size]

    function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $foo)
    {
        $this->prefix = $db_prefix;

        // Was a custom port supplied with $db_host?
        if (strpos($db_host, ':') !== false)
            list($db_host, $db_port) = explode(':', $db_host);

        if (isset($db_port))
            $this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name, $db_port);
        else
            $this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name);

        if (!$this->link_id)
            error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);

        @mysqli_query($this->link_id, "SET NAMES 'utf8'");
    }
The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

6

Re: Заготовка FAQ по UTF-8

Все языки в utf-8:

(Please log in or register to see this URL)

Поделиться

7

Re: Заготовка FAQ по UTF-8

Чистый PunBB 1.2.17 + UTF-8:

(Please log in or register to see this URL)

Поделиться

8

Re: Заготовка FAQ по UTF-8

Раскоментировал строки с SET NAMES и все русские сообщения испортились
Так и должно было получиться, потому что русский текст УЖЕ сохранился в базе неправильно. Придется набивать текст заново, зато дальше все будет работать как положено.

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

9 (06.05.2008 17:49 отредактировано NamlessTee)

Re: Заготовка FAQ по UTF-8

2. в файле include/dblayer/mysql.php сразу за if ($this->link_id) надо указать что мы работаем с данными в уникоде:

В этом файле "if ($this->link_id)" встречается 2 раза(в "function DBLayer" и в function close), в обоих случаях надо указывать?

Пункт 3b относится только к "include/" или ко всему форуму вообще?

И ещё вот вопрос, я несовсем понял что надо делать, у меня возникает ошибка "Unable to insert search index words", при попытке редактирования постов, хотя всё делал по этой инструкции, но мог где-то ошибиться или что-то пропустить, не знаете, что я мог сделать неправильно?
P.S. В файле include/search_idx.php кусок функции split_words, который у вас выглядит вот так:

            $num_chars = strlen($word);

            if ($num_chars < 3 || $num_chars > 40 || in_array($word, $stopwords))
                unset($words[$i]);

у меня выглядит вот так:

            $num_chars = pun_strlen($word);

            if ($num_chars < 3 || $num_chars > 40 || in_array($word, $stopwords))
                unset($words[$i]);

Поделиться

10

Re: Заготовка FAQ по UTF-8

- достаточно только в конструкторе function DBLayer. хотя если поставите в нескольких местах ошибки не будет smile

- помоему п. 3b все написано однозначно: "во всех *.php " и "особый случай".

- split_words: вам надо понять как работает функция pun_strlen. в отличие от strlen она возвращает не длину в байтах, а длину в "экранных символах", в т.ч. в символах вида &#nnnn;
split_words выбрасывает те слова, которые не влезут в поле search_words.word ...

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

11 (07.05.2008 12:01 отредактировано NamlessTee)

Re: Заготовка FAQ по UTF-8

Спасибо ^_^ search_idx.php поправил.
Остальное всё вроде правильно...
Проблема с "Unable to insert search index words", при попытке редактирования постов осталась... =(
Вот, что пишет форум:

An error was encountered
File: ***/include/search_idx.php
Line: 149

PunBB reported: Unable to insert search index words 

Database reported: Duplicate entry 'browserparasitescann' for key 1 (Errno: 1062)

Сто сорок девятая строка в файле "search_idx.php":

                    $db->query('INSERT INTO '.$db->prefix.'search_words (word) VALUES'.implode(',', preg_replace('#^(.*)$#', '(\'\1\')', $new_words))) or error('Unable to insert search index words', __FILE__, __LINE__, $db->error());

Извиняюсь за глупые вопросы, я в php абсолютный ноль, да и вообще ни каких языков программирования или скриптовых не знаю(если не считать давно забытый JavaScript)... =\

Поделиться

12

Re: Заготовка FAQ по UTF-8

punbb - движок для тех, кто хотябы немного понимает в программировании, отмазки типа "в php я абсолютный ноль" не канают!
А главное — учитесь читать внимательно!!! Читайте первый пост:

ошибка "Unable to insert search index words"

Ошибка происходит из-за попытки записать в таблицу неуникальное слово. Дело в том, что при записи в базу стрОки обрезаются до длины поля, поэтому длинные слова, различающиеся последними символами станут одинаковыми. Поле search_words.word изначально расчитано на слова длиной до 20 (однобайтовых) символов. Кирилические символы в UTF-8 занимают два байта. Другие алфавиты могут потребовать три байта на символ.

Необходимо убедиться, что
- поле search_words.word имеет collation BINARY либо само поле типа VARBINARY (зависит от версии MySQL)
- длина поля не менее 40 (20 символов * 2 байта или 13 символов * 3 байта)
т.е. нормальный вид поля word VARBINARY(40)

У вас, судя по всему, поле осталось 20-байтным. Если split_words выдает слова до 40 байт блинной, то и поле должно быть таким!!! Или поправьте функцию чтобы оставляла 20 байт (до 20 латинских букв == до 10 русских == до 6 китайских)

(Please log in or register to see this URL), имейте это в виду.

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

13 (08.05.2008 18:20 отредактировано NamlessTee)

Re: Заготовка FAQ по UTF-8

Не уверен что там с MySQL, у меня к нему доступа никакого нет, но попрошу чела, у которого хостится мой форум, чтоб перепроверил... С самим форумом я все необходимые операции произвёл, судя по всему...

punbb - движок для тех, кто хотябы немного понимает в программировании, отмазки типа "в php я абсолютный ноль" не канают!

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

Или, посоветуйте мне какой-нить гайд/мануал по пхп... Желательно, только, чтоб интересно было написанно.. smile
/me вспомнил, что он ещё месяца 3 назад собирался садиться за изучение C#, дабы написать кой-каких скриптов для рануо, даже уже книжек накачал, но пока никак руки не доходят... =\

Поделиться

14

Re: Заготовка FAQ по UTF-8

NamlessTee пишет:

форум, только для тех кто нифига не понимает в пхп да и вообще с языками программирования и скриптовыми языками слабо занком...

phpbb?

NamlessTee пишет:

Или, посоветуйте мне какой-нить гайд/мануал по пхп... Желательно, только, чтоб интересно было написанно..

Интересный мануал, ну сказанул big_smile

PunBB.Ru ☭

Сайт nobody

Поделиться

15 (09.05.2008 01:52 отредактировано NamlessTee)

Re: Заготовка FAQ по UTF-8

nobody пишет:

Интересный мануал, ну сказанул

Ну например у меня был какой-то справочник по TCP/IP от издательства "Питер", мне его было интересно читать, пока у меня его одна знакомая не взяла... С тех пор я его больше не видел, так же как и ещё 2 книги по комповой безопастности, которые я даже не начал читать... И каждая из этих книг стоила в районе 500 рублей =\
Вообще некоторые вещи вроде мануалов мне было интересно читать, когда автор живо пишет что-то а не просто нудно излагает информацию... =(

nobody пишет:

phpbb?

он мне показался слишком навароченным, и вообще не понравился... :) Ктомуже он очень популярный, а мне хочется чего-нить малоиспользуемого... Вообще я как-то предпочитаю пользоваться малопопулярными вещами...
А так глядиш с punbb ещё и php выучу... Вот CSS уже собираюсь вспоминать, т.к. хочу тему для форума сделать по своему вкусу... ^_^
Ещё никак руки не дойдут сайт начать делать, хочу исключительно HTML+CSS юзать, постараюсь даже без жабаскрипта обойтись...

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

Поделиться

16

Re: Заготовка FAQ по UTF-8

Нашел очень интересную библиотечку для PHP. Пригодится тем несчастным, у которых по какой-то причине не может быть установлено расширение mbstring, с помощью библиотечки можно создать свои работающие заглушки mb_* функций, а также для написания "цензуры" для русского языка.

Форум «Лаборатории dk»: (Please log in or register to see this URL)

must have! ссылку нашел через (Please log in or register to see this URL)

The more you know, the more you know you don't know.

Сайт artoodetoo

Поделиться

17

Re: Заготовка FAQ по UTF-8

Хочу ещё немного от себя добавить. Некоторые браузеры, в частности Опера (и возможно, Firefox) считают BOM в файле важней кодировки в [mono]<meta>[/mono]. Может возникнуть ситуация, когда файлы по факту сохранены в 1251, в базу/из базы данные передаются верно, даже AddDefaultCharset в .htaccess есть, а русский в браузере всё равно нечитабелен.

Проблема в редакторах, некорректно работающих с UTF-8, вроде встроенного в WinSCP. С его медвежьей услугой файл в 1251 может иметь BOM (!) - столкнулся однажды на практике. Пользуйтесь правильными редакторами.

Сайт Freeman

Поделиться