Ошибки конвертера для IPB3
Ошибка
mySQL query error: INSERT INTO ipb3groups (g_title,g_hide_from_list,g_use_pm,g_max_messages,g_max_mass_pm,prefix,suffix,g_perm_id) VALUES('Русские буквы в названии группы{тут знак вопроса или символ не читаемый в UTF-8}',1,0,0,0,'','',7)<br />
<br />
<br />
>SQL error: Incorrect string value: '\xD0' for column 'g_title' at row 1<br />
<br />
SQL error code: 1366<br />
<br />
Date: Thursday 17th o September 2009 11:48:44 AM<br />
Условия возникновения:
Мигрировал с phpBB3 на IPB 3 (ver 3.0.3)
Использовалась последняя версия конвертера с сайта производителя (на 17.09.2009)
При конвертации Member Groups
В моём случае ошибка вызвана в файле:
admin/applications_addon/ips/convert/sources/lib_master.php
/**
* IPS Converters
* Application Files
* Library functions
* Last Update: $Date: 2009-09-01 10:53:43 +0100 (Tue, 01 Sep 2009) $
* Last Updated By: $Author: mark $
*
* @package IPS Converters
* @author Mark Wade
* @copyright © 2009 Invision Power Services, Inc.
* @link http://external.ipsl.../?p=converthelp
* @version $Revision: 357 $
*/<br /><br />..<br />
// Line: 1656
$info['g_title'] = substr($info['g_title'], 0, 32);
Виной всему встроенная php функция substr(): http://ru2.php.net/manual/en/function.substr.php
Использовать её на мультибайт строках не безопасно. Например utf8 который используеться по умолчанию в ipb3 и в phpBB версии 3.
Поэтому скорее всего попытка переахть с других форумах где используеться Юникод тоже вызовет ошибку.
К сведенью: я быстренько пробежался по коду IPB 3 и обноружил множество мест, где использовался substr(), очень возможно возникновение похожих ошибок и в других местах и при других обстоятелствах.
Как лечить:
Способа есть по крайней мереnhb. Два из них связанны с использованием стандартного php модуля PHP_MBSTRING.
- Пожалуй самый правильным в данном случае, при использовании PHP 5-ой будет включение опции mbstring.func_overload (http://ru2.php.net/manual/en/mbstring.overload.php). Модуль mbstring нужно предварительно активировать. Напрмер так:
php.ini
mbstring.func_overload = 7
Можно и с использование функции ini_set(), но придется модифицировать файлы IPB. А этот способ тем и хорош, что не меняються оригинальные файлы форума. Но может привести к ошибкам, там где текстовые функции используються для бинарных операций. А потому после конвертации mbstring.func_overload настоятельно рекомендую отключить. - Отредактировать файл lib_master.php заменив substr() на mb_substr(). Модуль mbstring нужно предварительно активировать.
- Использховать встроенную в IPB функцию IPSText::mbsubstr().
Этим способом и должны были воспользоваться разработчики IPB. Но почему то этого не сделали.. )
Также замечу, что использование последних двух вариантов не спасёт вас от подобной ошибки в других местах.
Немного философии
Включением опции mbstring.func_overload способно вылечить множество проблем и спользованием Юникода, в качестве кодировки в движке, слабо приспособленного для его использование. Фактически строковые функции PHP Это единственное узкое место с точки зрения Юникода.
Пример: phpbb2 не поддерживает Юникод. Но чтобы заставить его корректно работать достаточно включить опцию mbstring.func_overload (не забыв предварительно перекодировать базу, lang файлы, изменить кодировку в настройках, стилях и параметрах подключения к базе).
Почему так получаться? Потому что php на уровне ядра не подозревает о существовании Юникода. В отличии скажем от Perl (который давно перешёл на Юникод) или Java (в котором юникод был с самого начала), в php поддержку Юникода нам обещают только в шестой версии. Решит ли это проблему с использованием строковых функций ядра на Строках с юникодом. Как например в случае с substr() ? Незнаю. Покажет время. Хотя RC версии php6 уже доступны. Кому не ленива - могут проверить.
Что же остаться программисту? Всегда (если не требеутся обработка именно бинарных данных) использовать функции с префиксом mb_ из модуля PHP_MBSTRING. Напомню, что использование строковых функций вроде substr() на бинарных данных в свою очередь тоже не являться безопасным. Во-первых потому, что эти функции могут быть перезагруженны в модуле PHP_MBSTRING. Во-вторых реализация этих функций действительно может измениться в последующих версиях PHP. А всё потому, что эти функции по хорошему не предназначенны для обработки бинарных данных.
Возможно самым самым универсальным вариантом будет использование дополнительного пользовательского класса. Вроде класса IPSText из IPB3, в котором переопределены все строковые функции. Это безусловно усложнит программу и увеличит время выполнение. Но сделает код менезависимым от переменного окружения.
И на последок: скорее всего рассматриваемая проблема решена на уровне фреймфорков или есть интересные варианты в PEAR. Поэтому если вы используете такие инструменты программирования - лучше для начала поискать там.
Ссылки по теме
Подробнее о том, как конфигурить php можно почитать сдесь: http://ru2.php.net/manual/en/ini.php