Marko: Unicode durch PHP konvertieren

Hallo,

Ich bin in einer etwas komplizierten Situation. Ich habe eine Tabelle in einer MySQL-Datenbank, in der momentan in Latin-1 Textbausteine aus allen möglichen Sprachen gespeichert werden. Texte aus Sprachen wie Griechisch oder Slowakisch sind dabei in ihrer Latin-1-Entsprechung (Kauderwelsch) gespeichert, werden also später erst aus der DB geholt und dann wieder in ihren Zeichensatz (Latin-7, Latin-2, etc) konvertiert.

Dieses Chaos soll ich nun nach Unicode konvertieren.

Das Problem ist, dass ich nicht direkt beim Import alles die Datenbank machen kann, da für diese ja alles Latin-1 ist. Die griechischen Texte müssen also einzeln (aus einer Backup-Tabelle) herausgefischt werden, und im Fall von Griechisch von Latin-7 nach UTF-8 konvertiert werden.

So weit, so gut, das funktioniert auch. Bis auf wenige Ausnahmen, die mir schlaflose Nächte bereiten... Zur Konvertierung nutze ich die PHP-Funktion iconv, die tadellos arbeitet. Wenn ich z.B. einen griechischen Text im Original (Latin-1) aus der DB hole, mit iconv nach UTF-8 konvertiere und an den Browser (unter einem Unicode-Header) ausgebe, sehe ich den Text wie er sein sollte.

Beim Rückspeichern in die Datenbank treten allerdings seltsame Fehler auf. Manche Zeichen (Rho, kleines Epsilon) werden einfach nicht korrekt gespeichert. Es sieht so aus, als würde mysql_query einfach eigenmächtig andere Bits an die Datenbank schicken als von mir angegeben.

Ich habe ein wenig nachgeforscht und gesehen, dass andere ähnliche Probleme hatten. Empfohlen wird das Ausführen von

mysql_query("SET NAMES 'utf8'", $db);

nach Verbindung zur Datenbank. In meinem Fall führt das aber zu der Fehlermeldung

Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='

bei Ausführung der nächsten Query.

Hat jemand einen Rat für mich?

  1. Welche MySQL-Version wird denn auf dem Server eingesetzt?
    Ich würde Dir empfehlen, die Datenbank intern auf UTF-8 umzustellen, da Zeichen anderer Kodierungen durch das senden an eine Latin1-Datenbank zerstört werden können.
    Der von Dir erwähnte "SET NAMES"-Befehl regelt den Zeichensatz für die Übertragung zwischen Client und Server, nutzt Dir effektiv also nur etwas, wenn Deine Datenbank selber als 'UTF-8' speichert.

    1. echo $begrüßung;

      Welche MySQL-Version wird denn auf dem Server eingesetzt?

      Wenn die Fehlermeldung von "collation" spricht, kann man davon ausgehen, dass eine Version 4.1 oder größer eingesetzt wird. Den Begriff gab es bis Version 4.0 noch nicht.

      Ich würde Dir empfehlen, die Datenbank intern auf UTF-8 umzustellen, da Zeichen anderer Kodierungen durch das senden an eine Latin1-Datenbank zerstört werden können.

      Ergänzend möchte ich empfehlen, sich das Kapitel Character Set Support zu Gemüte zu führen und sich zu vergegenwärtigen, dass Zeichensätze für

      • den Server
      • jede Datenbank
      • jede Tabelle
      • jedes (String-)Feld
      • jede Verbindung
          - Kommandos
          - Daten (in Richtung Server)
          - Ergebnisse (Resultsets)
      • jeden String
        jeweils einzeln eingestellt bzw. angegeben werden können.

      Der von Dir erwähnte "SET NAMES"-Befehl regelt den Zeichensatz für die Übertragung zwischen Client und Server, nutzt Dir effektiv also nur etwas, wenn Deine Datenbank selber als 'UTF-8' speichert.

      Jein. MySQL versucht Umwandlungen zwischen den Codierungen vorzunehmen. Dass dies nicht in jede Richtung verlustfrei möglich ist, liegt in der Natur der Sache.
      Beispielsweise könnte das Charset einer Tabelle latin1 (=ISO-8859-1) sein und für Resultsets der aktuellen Verbindung UTF-8 eingestellt sein, dann bekommt man das Abfrageergebnis nach UTF-8 gewandelt ausgeliefert.

      echo "$verabschiedung $name";

      1. Der von Dir erwähnte "SET NAMES"-Befehl regelt den Zeichensatz für die Übertragung zwischen Client und Server, nutzt Dir effektiv also nur etwas, wenn Deine Datenbank selber als 'UTF-8' speichert.

        Jein. MySQL versucht Umwandlungen zwischen den Codierungen vorzunehmen. Dass dies nicht in jede Richtung verlustfrei möglich ist, liegt in der Natur der Sache.
        Beispielsweise könnte das Charset einer Tabelle latin1 (=ISO-8859-1) sein und für Resultsets der aktuellen Verbindung UTF-8 eingestellt sein, dann bekommt man das Abfrageergebnis nach UTF-8 gewandelt ausgeliefert.

        Ich gebe zu, dass ich an dieser Stelle geschlampt habe und mit der Fehlermeldung konkret nichts anzufangen wusste.

        Aber um kurz bei SET NAMES zu bleiben:
        ich hatte bei einem PHP-Projekt Probleme mit dem reinen "SET NAMES" Befehl, er funktionierte nicht wie gewünscht. Ich bin dazu übergegangen, die drei Befehle

          
        SET character_set_client='utf8';  
        SET character_set_connection='utf8'  
        SET character_set_results='utf8'  
        
        

        hintereinander auszuführen, auch wenn ich mich damit nur um die Fehlerbehebung drücke.
        MySQL-Version (Client und Server) ist 4.1.12