Nico: Umlautproblem in MySQL

Guten Abend,

ich habe eine MySQL-Datenbank (Server-Version: 4.1.13) und darin eine Tabelle mit Adressen abgelegt. Seit einiger Zeit (und ich habe währenddessen nichts an den Scripts verändert) verstümmeln sich die Umlaute darin, wenn ich sie in die Formulare eingebe.

Die Daten werden mit PHP an die Datenbank übergeben. Aus "ü" wird beispielsweise "ü". Jetzt das kuriose:

1. Wenn ich die Daten ausgeben lasse, steht dort "Münster" statt "Münster". Wenn ich im IE 6 dann in das Bearbeitungsformular gehe, bekomme ich "Münster" angezeigt, wenn ich jetzt speichern will, wird trotzdem "Münster" gespeichert.

2. Mache ich das gleiche in Firefox, steht es zwar in der Ausgabe auch falsch dar, wenn ich es zum Bearbeiten öffne auch (!), wenn ich es dann aber korrekt eintrage und speichere, stimmt alles (auch im IE).

Ich vermute, dass es sich um ein Zeichensatzproblem handelt, aber ich weiß nicht, wie ich da rangehen soll. Die Kollation meiner Datenbank ist "utf8_unicode_ci", Kollation der MySQL-Verbindung und die betroffenen Spalten ebenfalls. Als Zeichensatz im HTML habe ich <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />.

Was mache ich falsch?

Danke sehr für eure Hilfe!

Nico

  1. Moin Moin!

    An der einen oder anderen Schnittstelle bringen die beteiligen Anwendungen Bytes und Characters durcheinander. In ASCII, ISO-8859-x und ähnlichen Zeichensätzen gilt immer Byte==Character, bei UTF-8 kann ein Character aber bis zu 5 Bytes belegen. Deutsche Umlaute belegen in UTF-8 zufällig alle 2 Bytes, die bei falscher Kodierung eben die kruden Zeichen ("ü") darstellen.

    Das Gemeine ist, dass diese kruden Zeichen einen Round-Trip überleben können, d.h. Du gibst "ü" ein, speicherst in der DB "ü", und bei der Ausgabe mit dem passenden HTML-Charset zeigt der Browser das wieder als "ü" an. Wenn Dein Editor dann auch noch mit Unicode Probleme hat, bist Du echt gekniffen.

    Wenn in Deiner Datenbank ein "ü" nicht als "ü" ankommt, ist definitiv etwas faul. Entweder verdaust Du die Formular-Parameter nicht richtig (behandelst sie also als Bytes und nicht als Unicode-Strings) oder Du hast ein Schnittstellenproblem bei der Datenbank. (DB-Schnittstelle nicht Unicode-fähig?) Ersteres kannst Du durch ein Zurücksenden an den Browser ohne den Umweg über die Datenbank überprüfen, z.B. in dem Du Dir Zeichen für Zeichen den Zeichencode (65, 66, 67 für "ABC") ausgeben läßt. Umgekehrt muß auch die Aneinanderreihung von Zeichen aus Zeichencodes ("ABC" aus 65, 66, 67) im Browser perfekt funktionieren. Wenn Du zwischen Script und Browser alles geklärt hast, kannst Du Dir auf ähnliche Art die DB-Schnittstelle vornehmen.

    Alexander

  2. echo $begrüßung;

    Die Daten werden mit PHP an die Datenbank übergeben. Aus "ü" wird beispielsweise "ü".

    Beschreibe bitte genauer, wie du diese Beobachtung gemacht hast! Das ganze System ist recht komplex. Es spielen dabei der Browser, das PHP, das DBMS, ein HTTP-Header, HTML-Elemente und vielleicht auch noch externe Programme à la phpMyAdmin (PMA) mit. Aus deiner obigen Aussage kann man nichts Konkretes entnehmen, um eine mögliche Ursache zu vermuten.

    Ich vermute, dass es sich um ein Zeichensatzproblem handelt, aber ich weiß nicht, wie ich da rangehen soll.

    Du solltest dir zunächst über das Zusammenspiel der Komponenten klarwerden.
    Der HTTP-Header "Content-Type" hat eine zweite optionale Angabe zur Kodierung der Daten.
    Es gibt ein HTML-Meta-Element mit der gleichen Funktion. Ist der HTTP-Header vorhanden (bzw. der zweite Teil) so ist die Angabe im HTML-Meta-Element unwirksam.
    Beide Angaben sagen dem Browser, welche Daten und Kodierung er zu erwarten hat. Die von dir gesendeten Daten müssen in der angegebenen Kodierung vorliegen, sonst kann der Browser keine richtige Darstellung erzeugen.
    Die Angabe wird ebenfalls vom Browser verwendet, um Formulardaten zu kodieren, falls keine spezielle Angabe im FORM-Element gesetzt wurde.

    Die Kollation meiner Datenbank ist "utf8_unicode_ci",

    Wer hat dir das gesagt? Meint diese Angabe den Server-Default-Wert oder den einer konkreten Datenbank? Beide Angaben sind für die zu speichernden Daten weniger relevant, weil es nur jeweils Default-Werte für das jeweils untergeordnete Element sind, wenn beim Erzeugen des untergeordneten Elements keine Kodierungs-/Kollationsangabe gemacht wurde.

    Server -> Datenbank -> Tabelle -> Feld

    Letzten Endes kommt es auf die Kodierungsangabe eines Feldes an, welche Zeichen dieses Feld aufnehmen kann.

    Kollation der MySQL-Verbindung

    Wieder die Frage, woher diese Angabe stammt. Hat dir das der PMA erzählt? Wenn ja, dann ist das _seine_ Verbindungskodierung, nicht _deine_. Wenn du auf deiner Verbindung keine konkrete Angabe machst, gelten die server-globalen Werte (ja, Mehrzahl, denn es sind insgesamt drei). Hast du etwas getan, um für deine Verbindung eine konkrete Kodierung zu vereinbaren? Beispielsweise mysqli_set_charset() oder ein SET NAMES-Statement nach dem Verbindungsaufbau abgesendet? Das MySQL-Handbuch widmet dem Thema Character Set Support ein komplettes Kapitel. SET NAMES ist bereits auf der Übersichtsseite erwähnt, und trotzdem ist es ein häufiges Versäumnis.

    und die betroffenen Spalten ebenfalls.

    Gut, dann haben die Felder schon mal die Voraussetzung, den komplette UTF-8- bzw. Unicode-Bereich speichern zu können. MySQL nimmt übrigens selbständig eine Umkodierung vor, wenn die eingestellte Verbindungskodierung und die Feld-Kodierung unterschiedlich sind. Das geht natürlich nur, wenn mit der Zielkodierung das Zeichen dargestellt werden kann.

    Was zeigt denn der PMA an, wenn du die Feldinhalte mit ihm anschaust? Ist alles in Ordnung, kannst du davon ausgehen, dass die Daten in den Felder korrekt kodiert sind. Wenn nicht, hast du ein Problem, das bereits beim Eintragen in die Datenbank entstanden ist. Siehst du Fagezeichen sind deine Daten kaputt und eine händische Korrektur notwendig. Siehst du etwas anderes, besteht noch Hoffnung auf Rettung. Siehst du richtige und falsche Daten gemischt ist es ebenfalls sinnvoller Hand anzulegen als ein Konvertierungsstatement zu probieren.

    echo "$verabschiedung $name";