Peter Rehm's Blog

apple,development,life & more

Weitere Lektion in der Umlautproblematik

Mit 2 Kommentaren

Nachdem ich in einem früheren Blog Eintrag empfohlen habe, alle Daten aus
Speicherplatzgründen die im UTF-8 Format sind in z.b. dem latin1 charset abzulegen,
muss ich dem nun komplett wiedersprechen.
Bei einem durchschnittlichen Projekt lädt man sich deutlich mehr Ärger auf,
als dass man dadurch Vorteile durch Speicherplatzersparnis erzielt.

In meiner Situation sah das dann so aus, dass ich ca. 8 Stunden damit beschäftigt
war, alle Datenbanken meiner Kunden umzustellen, was enorm händische Arbeit
erforderte.

Im Ist-Zustand war es nun auch so, dass mittels phpMyAdmin logischerweise
alle Umlaute kaputt angezeigt wurde, und man nicht oder nur mit hohem manuellen
Aufwand direkt die Daten bearbeiten konnte.

Ausgangssituation
Datenbank mit latin1 als Standardcharset, alle Tabellen latin1, und UTF-8 Daten darin gespeichert.

Ziel
Datenbank & Tabellen UTF-8, und alle Inhalte UTF-8
Ich habe mich für utf8_general_ci entschieden, der unterschied zu utf8_unicode_ci liegt nur in
der Abhandlung von Sortierreihenfolgen. Dies kann man aber im Detail dem MySQL Manual entnehmen.

1.) Datenbank Backup erstellen
Gehen wir einfach mal auf nummer sicher, um die Daten auch sicher nicht
endgültig zu zerstören.

2.) Umwandeln aller Tabellen voll automatisch, und davon sollen auch alle
Text und Varchar Felder umgewandelt werden. Manch einer wird hier noch anpassungen
vornehmen müssen, da ich keine Char Felder umwandle, da die nicht benötigt
werden. ACHTUNG! Das Script basiert wie alle meine Code Snippets auf adodb,
kann aber Problemlos auf die von MySQL zur Verfügung stehenden Funktionen
portiert werden.

CODE:
<?php
// fetch all tables
$data = $cfg['db']->pExecute("SHOW
TABLES");
while($row = $data->FetchRow())
{
$sres = $cfg['db']->pExecute("DESCRIBE ".($row[0]));
while( $column = $sres->FetchRow())
{
// if column is text or varchar, convert
if(strpos($column['Type'],'text')!==false || strpos($column['Type'],'char')!==false
|| strpos($column['Type'],'varchar')!==false)
{
$cfg['db']->Execute("ALTER TABLE ".($row[0])." CHANGE ".($column['Field'])." ".($column['Field'])." ".($column['Type'])." CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL");
}
}

// confert now also full table
$cfg['db']->Execute("ALTER TABLE ".$row[0]." DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
}
?>


3.) Manuelles Umwandeln der Datenbank
Ich habe mich dazu entschieden die eigentliche Datenbank händisch umzuwandeln,
da ich mich eh mit der Datenbank verbinden musste. Dazu habe ich dann folgendes
SQL Statement eingegebn

CODE:
ALTER DATABASE `dbname` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci


4.) Exportieren der Daten
Nun werden die Daten der kompletten Datenbank exportiert, nicht aber die
Struktur. Dies wird für die meisten am besten mittels einer grafischen Oberfläche
wie phpMyAdmin erledigt. Hier kann man dies mit weigen Mausklicks erreichen.

5.) Umwandeln des Datendumps
Nun wandeln wir einfach noch die "kaputten Zeichen" zurück in UTF8.
In meinem Fall und in den meisten wird folgendes Script hinreichend sein.
Dazu muss eine Datei data.sql im gleichen Verzeichnis wie das eigentliche
PHP Skript sein.

CODE:
<?php
$str=file_get_contents('data.sql');

$bad_char=array("ä","ö","ü","Ä","Ö","Ü","ß");
$right=array('ä','ö','ü','Ä','Ö','Ü','ß');

$bla=str_replace($bad_char,$right,$str);

echo $bla;

?>


6.) Abschließende Arbeiten
Um die ganze Aktion abzuschließen, muss nur noch die Datenbank geleert werden,
un der neue Dump eingelesen werden. Dann sollte man die Umlaute alle
im entsprechenden Format in der Datenbank haben.

Nun werden einige aber sicher zerstörte Umlaute in der Ausgabe haben,
und sich wundern warum. Dies liegt an der MySQL Verbindung die einen
Befehl zu beginn benötigt um UTF8 sauber zu behandeln.

CODE:
$cfg['db']->Execute("SET names utf8");


Nun sollte es endlich geschafft sein, und man sollte sich nun hoffentlich
wieder wichtigeren Dingen widmen können :-)

Achja, heikel ist dann auch das string handling an manchen stellen, daher sollte man auf
die mb_* funktionen von PHP zurückgreifen.


Geschrieben von Peter Rehm

16.08.2007 um 02:38:50

Abgelegt in PHP

0 Trackbacks zu Weitere Lektion in der Umlautproblematik

Trackback-URL für diesen Eintrag

  1. Keine Trackbacks

2 Kommentare zu Weitere Lektion in der Umlautproblematik

  1. Die beschriebene Aufgabe ist mit einfachereren Mitteln zu lösen:
    - Dump der alten Datenbank mit mysqldump: Dump enthält die in der latin1-Datenbank abgespeicherten UTF8-kodierten Daten

    - Nachbearbeitung der Dump-Datei, damit die Client-Verbindung für das Wiedereinlesen korrekt auf UTF8 gesetzt wird. Am Anfang der Datei einfügen:

    /*!40101 SET NAMES utf8 */;

    (Diese Anweisung fehlt im Dump, da die originale Datenbank ja dachte, dass der Inhalt als Latin1 kodiert sei.)

    - Wiedereinlesen der Dump-Datei in eine neue, defaultmäßig auf UTF8 gesetzte Datenbank. Da als Verbindung jetzt UTF8 genutzt wird, der Dump ebenfalls UTF8-Daten enthält, gibt es kein Problem. Kodierte Umlaute werden korrekt in die Datenbank einfgefügt.

    Diese Vorgehensweise funktioniert; soeben erfolgreich getestet mit einer Wordpress MySQL4.0 Migration auf MySQL5. Die Wordpressdaten waren in der 4.0-DB als UTF8 kodiert.

    Thorsten

    Thorsten

    Thorsten Albrecht

    05 Jul 09 um 18:17

    Antwort

  2. Hallo,

    für Punkt 5 gibt es eine wesentlich sicherere Methode.

    Das Windows-Notepad erlaubt laden von Dateien im angegebenen Format - Hat man also eine UTF-8 Datei, die aber aufgrund fehlenden BOM als iso/latin geladen wird, wählt mal nach dem auswählen der Datei "UTF-8" im Öffnen-Dialog aus.

    Notepad läd die Datei dann als wäre sie UTF-8 und erlaubt dann auch das korrekte Speichern.

    Ebenso ist es dann Möglich beim Speichern die Datei als "wirkliche" iso/latin Datei zu speichern.

    Das hat mit beim korrigieren von phpMyAdmin-Dumps schon einige male geholfen.

    Gruß,

Kommentar schreiben

BBCode-Formatierung erlaubt
Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.

Um maschinelle und automatische Übertragung von Spamkommentaren zu verhindern, bitte die Zeichenfolge im dargestellten Bild in der Eingabemaske eintragen. Nur wenn die Zeichenfolge richtig eingegeben wurde, kann der Kommentar angenommen werden. Bitte beachten Sie, dass Ihr Browser Cookies unterstützen muss, um dieses Verfahren anzuwenden.
CAPTCHA

Kommentare werden erst nach redaktioneller Prüfung freigeschaltet!