Как обнаружить и исправить кодировку символов в базе данных MySQL через php? - PullRequest
6 голосов
/ 01 октября 2009

Я получил эту базу данных, полную имен людей и данных на французском языке, что означает использование таких символов, как é, è, ö, û и т. Д. Около 3000 записей.

Очевидно, что данные внутри были закодированы иногда с использованием utf8_encode (), а иногда нет. Это приводит к неправильному выводу: в некоторых местах символы отображаются нормально, в других - нет.

Сначала я попытался отследить каждое место в пользовательском интерфейсе, где возникают эти проблемы, и использовать utf8_decode () там, где это необходимо, но на самом деле это нереальное решение.

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

Вопрос: возможно ли создать в php функцию, которая будет проверять, правильно ли закодирована строка utf8 (без utf8_encode) или нет (с utf8_encode), и, если это так, преобразовать ее обратно в исходное состояние?

Другими словами: я хотел бы знать, как я могу обнаружить контент utf8, который был utf8_encode (), в контент utf8, который не был utf8_encode () d.

** ОБНОВЛЕНИЕ: ПРИМЕР **

Вот хороший пример: вы берете строку, полную специальных символов, и берете копию этой строки и utf8_encode () ее. Функция, о которой я мечтаю, берет обе строки, оставляет первую нетронутой, а вторая строка теперь такая же, как и первая.

Я пробовал это:

$loc_fr = setlocale(LC_ALL, 'fr_BE.UTF8','fr_BE@euro', 'fr_BE', 'fr', 'fra', 'fr_FR');
$str1= "éèöûêïà ";
$str2 = utf8_encode($str1);

function convert_charset($str) {
    $charset=  mb_detect_encoding($str);
    if( $charset=="UTF-8" ) {
        return utf8_decode($str);
    }
    else {
        return $str;
    }
}
function correctString($str) {
    echo "\nbefore: $str";
    $str= convert_charset($str);
    echo "\nafter: $str"; 
}

correctString($str1);
echo('<hr/>'."\n");
correctString($str2);

И это дает мне:

before: éèöûêïà after: ������� 
before: éèöûêïà  after: éèöûêïà 

Спасибо

Alex

Ответы [ 5 ]

6 голосов
/ 02 октября 2009

Из вопроса о том, через какой объектив кодирования символов вы сейчас просматриваете, не совсем ясно (это зависит от настроек вашего текстового редактора, заголовков браузера, конфигурации базы данных и т. Д.) И от того, какие преобразования кодировки символов используются в данных прошли через. Может случиться так, что, например, при настройке конфигурации базы данных все будет исправлено, и это намного лучше, чем вносить частичные изменения в данные.

Похоже, что это может быть проблемой двойного кодирования utf8, и в этом случае исходные и поврежденные данные будут в utf8, поэтому обнаружение кодирования не даст вам необходимую информацию. Подход в этом случае требует предположений о том, какие символы могут обоснованно появляться в ваших данных: что касается PHP и Mysql, то «Ã» совершенно законно utf8, поэтому вы должны принимать решение на основе того, что вы знаете о данные и их авторы, что он должен быть поврежден. Это рискованные предположения, если вы просто техник. К счастью, если вы знаете, что данные на французском языке, а записей всего 3000, то, вероятно, можно делать такие предположения.

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

PROBABLY OK     Côte d'Azur
HAS NON-WHITELISTED CHAR        Côte d'Azur    195,180 ô
NON-UTF8        C�e d'Azur

Вот скрипт, вам нужно загрузить зависимые функции Юникода из http://hsivonen.iki.fi/php-utf8/

<?php

// Download from http://hsivonen.iki.fi/php-utf8/
require "php-utf8/utf8.inc";

$my_french_whitelist = array_merge(
  range(0,127), // throw in all the lower ASCII chars
  array(
    0xE8, // small e-grave
    0xE9, // small e-acute
    0xF4, // small o-circumflex
    //... Will need to add other accented chars,
    // Euro sign, and whatever other chars
    // are normally expected in the data.
  )
);

// NB, whether this string literal is in utf8
// depends on the encoding of the text editor
// used to write the code
$str1 = "Côte d'Azur";
$test_data = array(
  $str1,
  utf8_encode($str1),
  utf8_decode($str1),
);

foreach($test_data as $str){
  $questionable_chars = non_whitelisted(
    $my_french_whitelist,
    $str
  );
  if($questionable_chars===true){
    p("NON-UTF8", $str);
  }else if ($questionable_chars){
    p(
      "HAS NON-WHITELISTED CHAR",
      $str,
      implode(",", $questionable_chars),
      unicodeToUtf8($questionable_chars)
    );
  }else{
    p("PROBABLY OK", $str);
  }
}

function non_whitelisted($whitelist, $utf8_str){
  $codepoints = utf8ToUnicode($utf8_str);
  if($codepoints===false){ // has non-utf8 char
    return true;
  }
  return array_diff(
    array_unique($codepoints),
    $whitelist
  );
}


function p(){
  $args = func_get_args();
  echo implode("\t", $args), "\n";
}
2 голосов
/ 15 августа 2010

При подключении к базе данных не забывайте всегда использовать mysql_set_charset ('utf8', $ db_connection);

все исправит, все мои проблемы решены.

Смотрите это: http://phpanswer.com/store-french-characters-into-mysql-db-and-display/

2 голосов
/ 02 октября 2009

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

Способ, который я решил, состоял в том, что выгрузил базу данных, установил для сортировки базы данных utf8 и затем импортировал данные в двоичном виде. Это автоматически конвертировало все в utf8 и больше не давало мне ???.

Это было в MySQL

0 голосов
/ 23 октября 2009

Моя проблема в том, что каким-то образом я получил в своей базе данных символы, такие как à, é, ê в простом формате или в кодировке utf8. После исследования я пришел к выводу, что какой-то браузер (я не знаю IE, FF или другой) кодирует отправленные входные данные, поскольку не было намеренно добавлено кодирование utf8 для обработки форм отправки. Итак, если бы я читал данные с помощью utf8_encode, я изменил бы другие простые символы и наоборот.

Мое решение, после того как я изучил решения, приведенные выше: 1. Я создал новую базу данных с charset utf8 2. Импортировал базу данных ПОСЛЕ того, как я изменил определение набора символов в операторе CREATE TABLE в файле дампа sql с латыни .... на UTF8. 3. импортировать данные из исходной базы данных (до тех пор, пока здесь, возможно, будет достаточно просто изменить кодировку на существующих БД и таблицах, и это только в том случае, если исходный БД не является utf8) 4. обновить содержимое в базе данных напрямую, заменив символы в кодировке utf8 на простой формат, например,

UPDATE `clients` SET `name` = REPLACE(`name`,"é",'é' )  WHERE `name` LIKE CONVERT( _latin1 '%é%' USING utf8 ); 
  1. Я поместил в db class (для php-кода) эту строку, чтобы убедиться, что это UTF8-связь

    $ this-> query ('SET CHARSET UTF8');

Итак, как обновить? (шаг 4) Я построил массив с возможными символами, которые могут быть закодированы

$special_chars = array(
  'ù','û','ü',
  'ÿ',
  'à','â','ä','å','æ',
  'ç',
  'é','è','ê','ë',
  'ï','î',
  'ô','','ö','ó','ø',
  'ü');

Я построил массив с парами таблиц, поля, которые должны быть обновлены

$where_to_look = array(
    array("table_name" , "field_name"),
        ..... );

чем,

    foreach($special_chars as $char)
    {
      foreach($where_to_look as $pair)
      {
        //$table = $pair[0]; $field = $pair[1]
        $sql = "SELECT id , `" . $pair[1] . "` FROM " .$pair[0] . " WHERE `" . $pair[1] . "` LIKE CONVERT( _latin1 '%" . $char . "%' USING utf8 );";

    if($db->num_rows() > 0){
         $sql1 = "UPDATE " . $pair[0] . " SET `" . $pair[1] . "` = REPLACE(`" . $pair[1] . "`,CONVERT( _latin1 '" . $char . "' USING utf8 ),'" . $char . "' )  WHERE `" . $pair[1] . "` LIKE CONVERT( _latin1 '%" . $char . "%' USING utf8 )";
         $db1->query($sql1);
        }
    }
 }

Основной идеей является использование функций кодирования mysql, чтобы избежать кодирования между mysql, apache, browser и back; ПРИМЕЧАНИЕ: у меня не было доступных функций php, таких как mb _....

Лучший

0 голосов
/ 01 октября 2009

Поскольку вы сказали, что ваши данные иногда преобразуются с использованием utf8_encode, ваши данные кодируются с использованием UTF-8 или ISO 8859-1 (поскольку utf8_encode преобразуется из ISO 8859-1 в UTF-8). А поскольку UTF-8 кодирует символы от 128 до 255 двумя байтами, начиная с 1100001x, вам просто нужно проверить, являются ли ваши данные действительными UTF-8, и преобразовать их, если нет.

Сканируйте все свои данные, если это уже UTF-8 (см. Несколько функций is_utf8), и используйте utf8_encode, если это не UTF-8.

...