2009-10-01 4 views
6

Otrzymałem tę bazę danych zawierającą nazwiska ludzi i dane w języku francuskim, co oznacza, używając znaków takich jak é, è, ö, û itp. Około 3000 wpisów.jak wykryć i naprawić kodowanie znaków w bazie danych mysql przez php?

Wygląda na to, że dane wewnątrz zostały zakodowane czasami za pomocą utf8_encode(), a czasami nie. W rezultacie powstaje pomieszany wynik: w niektórych miejscach postacie wyglądają dobrze, w innych nie.

Najpierw próbowałem wyśledzić każde miejsce w interfejsie, w którym pojawiają się te problemy, i użyć utf8_decode() w razie potrzeby, ale naprawdę nie jest to praktyczne rozwiązanie.

Zrobiłem kilka testów i nie ma powodu, aby używać utf8_encode w pierwszej kolejności, więc wolałbym usunąć to wszystko i pracować w UTF8 wszędzie - na poziomie przeglądarki, oprogramowania pośredniego i bazy danych. Muszę więc wyczyścić bazę danych, konwertując wszystkie zminimowane dane przez jej wyczyszczoną wersję.

Pytanie: czy byłoby możliwe utworzenie funkcji w php, która sprawdzi, czy łańcuch utf8 jest poprawnie zakodowany (bez utf8_encode) czy nie (z utf8_encode), a jeśli tak, przekonwertował go z powrotem do pierwotnego stanu ?

Innymi słowy: chciałbym wiedzieć, w jaki sposób mógłbym wykryć zawartość utf8, która została utf8_encode() na zawartość utf8, która nie została utf8_encode() d.

** UPDATE: Przykład **

Oto dobry przykład: bierzesz pełną ciąg znaków specjalnych i wziąć kopię tego napisu i utf8_encode() go. Funkcja, o której marzę, przyjmuje oba ciągi, pozostawia pierwszą nietkniętą, a druga jest teraz taka sama jak ciąg pierwsza.

Próbowałem to:

$loc_fr = setlocale(LC_ALL, 'fr_BE.UTF8','[email protected]', '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); 

I to daje mi:

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

Dzięki,

Alex

Odpowiedz

6

Nie jest całkowicie jasne, z jakiego rodzaju obiektywu kodowania znaków obecnie przeglądasz (zależy to od domyślnych ustawień edytora tekstu, nagłówków przeglądarki, konfiguracji bazy danych itp.) I jakie transformacje kodowania znaków zawierają dane przeszedł przez. Być może, na przykład, poprzez ulepszenie konfiguracji bazy danych wszystko zostanie poprawione, a to jest o wiele lepsze niż dokonywanie fragmentarycznych zmian danych.

Wygląda na to, że może to być problem z podwójnym kodowaniem utf8, a jeśli tak jest, zarówno oryginalne, jak i uszkodzone dane będą znajdować się w utf8, więc wykrywanie kodowania nie zapewni potrzebnych informacji.Podejście w tym przypadku wymaga przyjęcia założeń na temat tego, co bohaterowie mogą rozsądnie znaleźć w swoich danych: jeśli chodzi o PHP i Mysql, "Ã ©" jest całkowicie legalnym utf8, więc musisz dokonać oceny na podstawie tego, co wiesz o danych i ich autorów, że musi być uszkodzony. Są to ryzykowne założenia, jeśli jesteś tylko technikiem. Na szczęście, jeśli wiesz, że dane są w języku francuskim, a jest ich tylko 3000, prawdopodobnie można założyć takie założenia.

Poniżej znajduje się skrypt, który można zaadaptować przede wszystkim w celu sprawdzenia danych, a następnie skorygowania go i wreszcie ponownego sprawdzenia. Wszystko, co robi, to przetwarzanie ciągu znaków jako utf8, dzielenie go na postacie i porównywanie postaci z białą listą oczekiwanych francuskich znaków. Sygnalizuje problem jeśli ciąg jest albo nie jest w utf8 lub zawiera znaki, które normalnie nie są oczekiwane w języku francuskim, na przykład:

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

Oto skrypt, musisz pobrać utrzymaniu funkcji unicode z 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"; 
} 
+0

Myślę, że zrozumiałeś dokładnie ten problem i naprawdę doceniam twój szeroki wkład. Spróbuję twojego skryptu i skontaktuję się z tobą. Pytanie: gdzie mogę znaleźć kod innych akcentowanych znaków do dodania na białej liście? Jak to jest nazywane? Czy jest to kolumna kodu Hex na tej stronie: http://webdesign.about.com/od/localization/l/blhtmlcodes-fr.htm? – pixeline

+0

Ta lista powinna obejmować większość potrzebnych danych, a jeśli potrzebujesz innych znaków, jest to oparte na kodowaniu Unicode, które możesz znaleźć w http://www.fileformat.info/info/unicode/index.htm . Znak Euro może powodować pewne problemy - jego kodowanie w standardzie Unicode to U + 20AC, ale w HTML pojawiła się konwencja, w której użyto odwołania do znaku 80, co jest używane na liście webdesign.about.com. –

0

Jak można powiedzieć, że dane są czasami przeliczane utf8_encode, twoje dane są kodowane albo w UTF-8 albo w ISO 8859-1 (od utf8_encode konwertuje z ISO 8859-1 na UTF-8). A ponieważ UTF-8 koduje znaki od 128 do 255 z dwoma bajtami zaczynającymi się od 1100001x, musisz tylko sprawdzić, czy twoje dane są poprawne UTF-8 i przekonwertować je, jeśli nie.

Zeskanuj wszystkie swoje dane, jeśli jest już UTF-8 (zobacz kilka funkcji is_utf8) i użyj utf8_encode, jeśli nie jest to UTF-8.

+0

hi Gumbo, mam zaktualizowane moje pytanie z pierwszej (nieudanej próbie). Czy możesz wyglądać i doradzać? – pixeline

2

Myślę, że możesz przyjąć bardziej kompilację. Otrzymałem bułgarską bazę danych kilka tygodni temu, która została dynamicznie zakodowana w DB, ale po przeniesieniu jej do innej bazy danych uzyskałem funky ???

Sposób, w jaki rozwiązałem to przez zrzucenie bazy danych, ustawienie bazy danych na UTF8, a następnie zaimportowanie danych jako plików binarnych. To automatycznie przekonwertowałem wszystko na utf8 i nie dałem mi więcej ???.

Było to w MySQL

+0

mmh, brzmi dobrze! Jak dokładnie robisz "importowanie danych jako binarnych"? Czy to możliwe przez phpmyadmin? – pixeline

+0

Przepraszam, że trochę potrwałem, aby odpowiedzieć, że mnie nie było. Jest to możliwe przez phpmyadmin http://i38.tinypic.com/1z8cgj.jpg – Gus

+0

Witaj Gus. Dziękuję, że do mnie wróciłeś. Próbowałem i nie miałem szczęścia. Béatrice wciąż okazuje się być Béatrice zarówno na starej, jak i nowej bazie danych. – pixeline

0

moim problemem jest to, że jakoś mam w mojej bazy danych, takich jak tych znaków A, E, E w formacie zwykłego lub utf8 zakodowany. Po przeprowadzeniu dochodzenia doszedłem do wniosku, że niektóre przeglądarki (nie wiem IE lub FF lub inne) kodują przesłane dane wejściowe, ponieważ nie było żadnego kodowania utf8 celowo dodanego do obsługi formularzy przesyłania. Tak więc, gdybym czytał dane za pomocą utf8_encode, zmienię pozostałe znaki zwykłe i na odwrót.

Moje rozwiązanie, po Uczyłem rozwiązań podanych powyżej: 1. stworzyłem nową bazę danych z charset utf8 2. Przywożone bazy danych po zmianie definicji charset na CREATE TABLE w SQL pliku zrzutu z łaciny ... do UTF8. 3. import danych z oryginalnej bazy danych (do tego czasu może wystarczy tylko zmienić zestaw znaków w istniejącym db i tabelach, i to tylko, jeśli oryginalny db nie jest utf8) 4. zaktualizować zawartość w bazie danych bezpośrednio, zastępując utf8 kodowanych znaków z tam zwykłym formacie coś podobnego

UPDATE `clients` SET `name` = REPLACE(`name`,"é",'é') WHERE `name` LIKE CONVERT(_latin1 '%é%' USING utf8); 
  1. umieścić w klasie dB (dla kodu php) tej linii, aby upewnić się, że ich jest komunikacja UTF8

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

Tak, ho do aktualizacji?(Etap 4) I został zbudowany tablicę z możliwych znaków, które mogą być zakodowane

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

ja buit tablicę par tabeli, pola, które powinny być uaktualnione

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

niż

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); 
     } 
    } 
} 

podstawowym ideea jest użycie funkcji kodowania MySQL aby uniknąć kodowanie odbywa się między MySQL, apache, przeglądarki i powrotem; UWAGA: Nie miałem dostarczony funkcje php jak mb _....

Najlepszy