1

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

Благодаря hcs вы можете не заморачиваться, а взять готовую сборку для UTF-8 здесь: http://punbb.ru/viewtopic.php?id=791 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)

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

2

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

поиск в "официальных местах" - punbb.org и punres.org дал мне только одну стоящую ссылку
Indexing is not unicode-safe: http://forums.punbb.org/viewtopic.php?id=4509

другие полезные ссылки я почерпнул из того топика
http://nicknettleton.com/zine/php/php-utf-8-cheatsheet
http://www.php.net/mbstring

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

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

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

3

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

Однажды очень много времени потратил на изучение проблем UTF-8 в PHP, так как хотел реализовать нормальный регистронезависимый поиск в TxP. Рекомендую обратить внимание на то, что пишет про UTF-8 и PHP Юлик. Оттуда я почерпнул больше всего информации в понятной для меня (не специалиста) форме.

Сайт 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 будет подставлять в заголовок то, что нам надо.

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт 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'");
    }
выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

6

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

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

http://intdn.com/idn/viewtopic.php?id=2881

Поделиться

7

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

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

punbb-1.2.17+utf-8+1.0.zip

Поделиться

8

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

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

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

9 (06.05.2008 05: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 ...

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

11 (07.05.2008 00: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 китайских)

В UTF-8 длина одного символа от 1 до 4 байт, имейте это в виду.

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

13 (08.05.2008 06: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 (08.05.2008 13: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»: php-функции для обработки текста в кодировке UTF-8

must have! ссылку нашел через блог Жилинского

выполню сложную работу, от $10/час - пишите в ЛС. рефссылка: VPS за $5/мес. бонус за регистрацию $10.

Сайт artoodetoo

Поделиться

17

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

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

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

Сайт Freeman

Поделиться