Случаются в нашей работе запущенные случаи, при которых в одной базе перемешаны записи в различных кодировках. Причины могут быть различными, например, сбои при переносе. Ручное исправление нереально при сколько – нибудь заметном количестве записей в базе. Предлагаем автоматическое решение.
1. Сделайте резервную копию
До начала любых изменений сделайте резервную копию. Иначе в результате «лечения» все может стать намного хуже и безвозвратно.
2. Диагностируйте вид перекодировки
Сначала выясните, в какой именно кодировке наш «пациент». Для этого можно скопировать несколько фрагментов текста и проверить их
«Декодером» студии Лебедева.
3. Сделаем функции для выявления «больных» участков текста
Чтобы не лечить здорового текста, надо отделять перекодированные фрагменты.
Для UTF-8 это будет выполнять такая функция:
<?
function good($str) {
return preg_match('#[а-яА-Я]#u', $str);
}
А для cp1251 другая:
<?
function good($str) {
$str = mb_convert_encoding($str, 'windows-1251', 'utf-8');
return preg_match('#[а-яА-Я]#u', $str);
}
4. Код для «лечения»
Например, CP1252 преобразует в UTF-8 такой код:
<?
function heal($str) {
$str = mb_convert_encoding($str, 'windows-1252', 'utf-8');
if (good($str)) return $str;
return false;
}
Осталось написать код, который обработает всю базу и выполнит нужную нам перекодировку. Вот он:
<?
$rs = $DB->Query('show tables');
while ($f = $rs->Fetch()) // таблицы
{
list($k, $t) = each($f);
$rs0 = $DB->Query('show table status like "' . $t . '"');
$f0 = $rs0->Fetch();
if ($f0['Rows'] == 0) continue;
$arCols = array();
$id = '';
$rs0 = $DB->Query('show columns from ' . $t);
while ($f0 = $rs0->Fetch()) // столбцы
{
if ($f0['Key'] == 'PRI') $id = $f0['Field'];
if (preg_match('#char|text#', $f0['Type'])) $arCols[] = $f0['Field'];
}
if (!$id) {
echo ('Нет поля ID: ' . $t . '<br>');
continue;
}
if ($id == 'ID') continue;
foreach ($arCols as $fld) {
if (!$rs1 = $DB->Query('SELECT `' . $id . '`,`' . $fld . '` FROM ' . $t)) {
echo ('Нет поля ID: ' . $t . '<br>');
break;
}
while ($f1 = $rs1->Fetch()) // строки
{
if (!$f1['ID']) if (!trim($f1[$fld])) continue;
if ($new = heal($f1[$fld])) {
$q = 'UPDATE ' . $t . ' SET ' . $fld . '="' . $DB->ForSQL($new) . '" WHERE ' . $id . '="' . $DB->ForSQL($f1[$id]) . '"';
$DB->Query($q);
if ($yyy++ < 10) echo $q . '<br>';
}
}
}
}
echo '$iii=' . $iii;
5. Готово!
-------------------------------
Спасибо за внимание!
Читайте свежий выпуск
«Кладовки программиста» каждый день!
Назад в раздел