Andi123: MySQL: durchgehendes UTF-8. Nur wie und wo?

Hallo,

seit kurzem (wahrscheinlich wurden bisher keine solchen 'Sonderzeichen' wie ein ć eingegeben?) erhalte ich bei Einträgen aus einem Formular auf meiner Webseite in meine Datenbank den MySQL-Fehler Incorrect string value: '\xC4\x87ek\x0D\x0A...' for column 'lineup' (an der Stelle soll ein 'Vlćek' eingegeben werden).

Da war es für mich an der Zeit, mich mal mit der aktuell bestehenden Kodierung im einzelnen zu beschäftigen.

Was ich habe: PHP-Skript ist im Editor auf UTF8 gestellt

Ausgabe der Webseite: UTF-8.

Eine seit 13 Jahren bestehende Datenbank mit den Werten wie folgt:

  • collations.character_set_name: latin1 (betrifft alle Tabellen in der DB)
  • collation_connection: utf8_general_ci
  • collation_database: latin1_swedish_ci
  • collation_server: latin1_swedish_ci
  • character_set_client: utf8
  • character_set_connection: utf8
  • character_set_database: latin1
  • character_set_filesystem: binary
  • character_set_results: utf8
  • character_set_server: latin1
  • character_set_system: utf8

Meine Fragen:

  • Ich las im Netz, dass es sein kann, dass man von utf8 auf utf8mb4 umschalten solle, da man dann auch die Zeichen aus höheren Unicode-Regionen verwenden kann. Ist das anzuraten und eine Absicherung für die Zukunft? Oder gibt es da allgemeingültigere Möglichkeiten, die schon jetzt ein noch größeres Charset abbilden? utf8_general_ci ?

  • Wo muss ich zwingend überall utf8/ utf8mb4/ utf8_general_ci einstellen, damit obige Fehler nicht mehr passieren?

  • Kann ich die bestehenden Datensätze in meinen Tabellen irgendwie konvertieren ?

Vielen Dank Andi

  1. Tach!

    PHP-Skript ist im Editor auf UTF8 gestellt

    Ist nur relevant, wenn du String-Literale im Code hast.

    Ausgabe der Webseite: UTF-8.

    Was auch immer du da schaust, es gibt jedenfalls ein paar Möglichkeiten, wo man die Zeichenkodierung einstellen kann. Wichtig ist immer auch, dass die Kodierung tatsächlich verwendet wird. Es gibt keine Magie, die alle Daten so umkodiert, wie angegeben wurde.

    Eine seit 13 Jahren bestehende Datenbank mit den Werten wie folgt:

    Es gibt einige Default-Werte, die sich hierarchisch vererben. Letztlich sind zwei Stellen wichtig: die Kodierung jedes einzelnen Feldes und die beim Verbindungsaufbau ausgehandelte Kodierung.

    • collations.character_set_name: latin1 (betrifft alle Tabellen in der DB)
    • collation_connection: utf8_general_ci
    • collation_database: latin1_swedish_ci
    • collation_server: latin1_swedish_ci
    • character_set_client: utf8
    • character_set_connection: utf8
    • character_set_database: latin1
    • character_set_filesystem: binary
    • character_set_results: utf8
    • character_set_server: latin1
    • character_set_system: utf8

    Das sieht nach den Default-Werten aus. Schau die konkreten Werte der Datenbank, Tabellen und ((VAR)CHAR-)Felder an.

    • Ich las im Netz, dass es sein kann, dass man von utf8 auf utf8mb4 umschalten solle, da man dann auch die Zeichen aus höheren Unicode-Regionen verwenden kann. Ist das anzuraten und eine Absicherung für die Zukunft?

    Wie relevant die höheren Regionen sind, kommt auf deinen Anwendungsfall an. Das landen nicht nur zukünftige Zeichen drin, da sind auch derzeit schon Zeichen zu finden. Für die meisten Anwendungen wird wohl auch utf8 reichen.

    Oder gibt es da allgemeingültigere Möglichkeiten, die schon jetzt ein noch größeres Charset abbilden? utf8_general_ci ?

    Historisch gesehen hatte MySQL nur Unterstützung für die so geannte BMP, die ersten 65536 Zeichen. Die werden durch das "utf8" repräsentiert. Das "general" und das "ci" sind keine Angaben zur Kodierung, sondern zur Kollation (Sortier- und Vergleichsregeln).

    • Wo muss ich zwingend überall utf8/ utf8mb4/ utf8_general_ci einstellen, damit obige Fehler nicht mehr passieren?

    Zwei Stellen sind pro beteiligtem System von Bedeutung: die Datenablage und die Übertragung zum nächsten Glied der Verarbeitungskette. Die Datenablage muss korrekt konfiguriert sein. Zur Übertragung müssen beide Systeme die korrekte Verbindung aushandeln oder das Zielsystem bekommt von der Quelle genannt, welche Kodierung vorliegt.

    Konkret sind das in MySQL: Datenbank, Tabelle, Felder, Verbindungsaufbau.

    Wenn PHP die Daten nur durchreicht, muss man da nichts weiter beachten. Bei Stringverarbeitung, auch einfachste, wie Zeichen zählen oder Abschneiden, braucht man die mb_-Funktionen (Initialisierungsfunktion nicht vergessen aufzurufen).

    Der Webserver teilt dem Browser je Response mit, welche Kodierung vorliegt. Der Browser schickt Daten üblicherweise in der Kodierung zurück, die die Response hatte, in der das Formular lag.

    Dann folgt wieder PHP und die Datenbank.

    • Kann ich die bestehenden Datensätze in meinen Tabellen irgendwie konvertieren ?

    Ja. Wenn die Daten korrekt in den Feldern liegen, musst du nur die Kodierungsangabe der Felder ändern. MySQL kodiert das dann um. Geht natürlich nur in Richtung UTF-8 verlustfrei. Du kannst die Korrektheit prüfen, indem du mit dem phpMyAdmin Datensätze mit Nicht-ASCII-Zeichen anschaust. Besonderes Augenmerk solltest du auf "Exoten" legen, die nicht in ISO-8859-1 enthalten sind. Siehst du die Zeichen richtig, stimmt üblicherweise die Kodierung des Feldes mit dem Inhalt überein. Ist das falsch, muss man individuell schauen, was konkret kaputt ist.

    Wir haben im Wiki auch einen Teil zur Zeichenkodierung, inklusive weiterführender Seiten, auf denen in mehr Details beschrieben ist, wie Zeichenkodierungen zwischen Systemen anzugeben sind.

    dedlfix.

    1. Vielen Dank für die ausführliche Erklärung!!!