Pit: Mal wieder Umlautprobleme

Hallo Forum,

nachdem ich meine Seite sowohl lokal als auch auf meinem Server problemlos laufen hatte, habe ich eine weitere Kopie auf den selben Server installiert und siehe da: Umlautprobleme.

Frage 1: Wie kann das denn überhaupt sein? Es sind dieselben Scripte, die db läuft auf demselben Server und die Datenbank selber ist per Dump rübergezogen. Und dennoch läuft die eine Installation ohne Umlautprobleme und die andre nicht.

Frage 2: Weil mir das inzwischen mächtigst auf den Senkel geht, habe ich anschließend beschlossen, alles auf utf-8 umzustellen.

Also habe ich:

  • Neue db angelegt, Kollation utf-8_unicode_cs
  • Sämtliche Tabellen auf Kollation utf-8_unicode_cs umgestellt
  • Sämtliche varchar Spalten auf Kollation utf-8_unicode_cs gestellt
  • DB-Verbindung geändert array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
  • Header geändert <meta http-equiv="content-type" content="text/html; charset=utf-8" />

Ergebnis: Anstelle von üöäÜÖÄß sowas hier: öäüÜÄÖß

Nun bin ich mit meinem Latein am Ende, was läuft denn hier schief?

Pit

  1. Tach!

    Weil mir das inzwischen mächtigst auf den Senkel geht, habe ich anschließend beschlossen, alles auf utf-8 umzustellen.

    Es reicht nicht, einfach nur alles korrekt zu deklarieren. Du musst auch selbst dafür sorgen, dass alles richtig kodiert ist. Zum Beispiel korrigieren sich nicht einfach kaputte Daten, nur weil du nun eine andere Kodierung festlegst.

    Es kann nur dann alles richtig werden, wenn du die Einstellungen korrekt vorgenommen hast und dann mit einer leeren Datenbasis startest. Oder mit Daten, die korrekt kodiert im DBMS stehen. Letzteres kann man mit phpMyAdmin kontrollieren. Wenn das alles richtig anzeigt, ist üblicherweise alles korrekt im DBMS, wenn nicht, dann nicht.

    • Header geändert <meta http-equiv="content-type" content="text/html; charset=utf-8" />

    Genauer gesagt: Header-Ersatz geändert. Der kommt nur zur Anwendung, wenn kein anderslautender HTTP-Header vom Server gesendet wird. Zudem ist heutzutage <meta charset="UTF-8"> ausreichend.

    Ergebnis: Anstelle von üöäÜÖÄß sowas hier: öäüÜÄÖß

    Kodierfehler. Kommt zustande, wenn das Ziel Kodierung X erwartet, du aber Y schickst. Manchmal fällt das nicht auf, weil sich beim Zurückschicken der Fehler wieder aufhebt.

    Nun bin ich mit meinem Latein am Ende, was läuft denn hier schief?

    Vermutlich bereits falsch kodierte Daten im System, wie gesagt. Probier es mit neu hinzugefügten Daten. Wenn es damit wie gwünscht funktioniert, musst du den Altbestand korrigieren.

    dedlfix.

    1. Hi dedlfix,

      Nun bin ich mit meinem Latein am Ende, was läuft denn hier schief?

      Vermutlich bereits falsch kodierte Daten im System, wie gesagt. Probier es mit neu hinzugefügten Daten. Wenn es damit wie gwünscht funktioniert, musst du den Altbestand korrigieren.

      Nein, die Bestandsdaten, die ich eingepflegt habe, waren nicht kontaminiert. Es geht lediglich um Neueinträge.

      Pit

      1. Tach!

        Es geht lediglich um Neueinträge.

        Wenn Neueinträge kaputtgehen, hast du irgendwo eine Kodierungsangabe vergessen oder sie ist nicht wirksam. Da hilft nur, jeden Verarbeitungsschritt und die Kommuniation zwischen den Schritten erneut zu überprüfen.

        dedlfix.

        1. Hi,

          Wenn Neueinträge kaputtgehen, hast du irgendwo eine Kodierungsangabe vergessen oder sie ist nicht wirksam. Da hilft nur, jeden Verarbeitungsschritt und die Kommuniation zwischen den Schritten erneut zu überprüfen.

          Warum erhalte ich eigentlich bei

          SELECT @@global.character_set_database 
          

          latin1 angezeigt?

          Pit

          1. Tach!

            Warum erhalte ich eigentlich bei

            SELECT @@global.character_set_database 
            

            latin1 angezeigt?

            Weil das die globale Konfiguration ist.

            Die ist aber nicht weiter relevant. Letztlich zählt nur, was für jedes einzelne Feld eingestellt ist. Kodierungsangaben für die Tabelle und für die Datenbank sind Defaultwerte, wenn darin was neues angelegt wird und du dabei keine Kodierung angibst.

            Und natürlich zählt auch die Einstellung für die Verbindung. MySQL versucht sogar umzukodieren, wenn Verbindung und Feld-Kodierung nicht übereinstimmen.

            dedlfix.

            1. Hi,

              Weil das die globale Konfiguration ist.

              Die ist aber nicht weiter relevant.

              Ah, ok.

              Letztlich zählt nur, was für jedes einzelne Feld eingestellt ist. Kodierungsangaben für die Tabelle und für die Datenbank sind Defaultwerte, wenn darin was neues angelegt wird und du dabei keine Kodierung angibst.

              Und natürlich zählt auch die Einstellung für die Verbindung. MySQL versucht sogar umzukodieren, wenn Verbindung und Feld-Kodierung nicht übereinstimmen.

              Aber siehst Du denn einen Fehler? Ich ja weiter oben geschrieben, wie meine Kodierungskette aussieht.

              Pit

              1. Tach!

                Aber siehst Du denn einen Fehler? Ich ja weiter oben geschrieben, wie meine Kodierungskette aussieht.

                Bei http-equiv steht das equiv für Equivalent. Das ist nur ein Eratz, der genommen wird, wenn kein gleichnamiger echter HTTP-Header kommt, oder dem die charset-Angabe fehlt. Da hast du also unter Umständen eine Abweichung zwischen Wunsch und Wirklichkeit, weil dir der HTTP-Header diese Angabe überschreibt. Die Entwicklertools im Browser zeigen dir im Netzwerk-Tab für jeden Request-Response auch die dabei übertragenen Header an. Damit kannst du prüfen, was du wirklich bekommt. Um das Problem zu lösen, kannst du explizit einen Content-Type Header inklusive charset-Angabe aus PHP (header()-Funktion) heraus in jede Antwort geben. Das überschreibt Default-Werte, die im Apachen konfiguriert sind, und die er ansonsten einfügt.

                dedlfix.

                1. Hi dedlfix,

                  Da hast du also unter Umständen eine Abweichung zwischen Wunsch und Wirklichkeit, weil dir der HTTP-Header diese Angabe überschreibt. Die Entwicklertools im Browser zeigen dir im Netzwerk-Tab für jeden Request-Response auch die dabei übertragenen Header an. Damit kannst du prüfen, was du wirklich bekommt.

                  Habe ich nicht gefunden. Wo steht das denn genau?

                  Um das Problem zu lösen, kannst du explizit einen Content-Type Header inklusive charset-Angabe aus PHP (header()-Funktion) heraus in jede Antwort geben. Das überschreibt Default-Werte, die im Apachen konfiguriert sind, und die er ansonsten einfügt.

                  Auf jeden Fall liegt da der Hase im Pfeffer. Ich habs an 2 Stellen eingefügt, dort sind dann auch die Umlautfehler (in den Formularen) weg. Aber an vielen Stellen im Text selber, vor allem auch bei den Dingen, die Jquery hinzufügt, stehen nun Fragezeichen anstelle der Umlaute (was zuvor widerum nicht war).

                  Wie bekomme ich das denn nun noch hin? Ich dachte, die Zeiten von &auml; und Konsorten wären vorbei? 😉

                  Pit

                  1. Tach!

                    Da hast du also unter Umständen eine Abweichung zwischen Wunsch und Wirklichkeit, weil dir der HTTP-Header diese Angabe überschreibt. Die Entwicklertools im Browser zeigen dir im Netzwerk-Tab für jeden Request-Response auch die dabei übertragenen Header an. Damit kannst du prüfen, was du wirklich bekommt.

                    Habe ich nicht gefunden. Wo steht das denn genau?

                    Im Netzwerk-Tab siehst du die Requests aufgelistet. Klick einen davon an, um seine Details zu sehen.

                    Auf jeden Fall liegt da der Hase im Pfeffer. Ich habs an 2 Stellen eingefügt, dort sind dann auch die Umlautfehler (in den Formularen) weg. Aber an vielen Stellen im Text selber, vor allem auch bei den Dingen, die Jquery hinzufügt, stehen nun Fragezeichen anstelle der Umlaute (was zuvor widerum nicht war).

                    Sind vielleicht die Code-Dateien, in denen du Text drinstehen hast, nicht als UTF-8 gespeichert?

                    dedlfix.

                    1. Hi dedlfix,

                      Im Netzwerk-Tab siehst du die Requests aufgelistet. Klick einen davon an, um seine Details zu sehen.

                      Ah, ok. Aber selbst das reichte bei mir nicht, ich mußte dem Entwicklertool zusätzlich mehr Platz einräumen, damit ich das sehe.

                      Sind vielleicht die Code-Dateien, in denen du Text drinstehen hast, nicht als UTF-8 gespeichert?

                      Du Tausendsassa, Du 😀 Jawohl, sind sie nicht. Und wenn ichs ändere, verschwinden die Umlautfehler dort.

                      Noch eine Frage: Muß ich wirklich jedem php-Script mitteilen, dass sie in utf-8 gesendet werden soll? Kann man das nicht zentralisieren? Per .htaccess habe ich schon versucht, das brachte nichts…

                      Pit

                      1. Tach!

                        Noch eine Frage: Muß ich wirklich jedem php-Script mitteilen, dass sie in utf-8 gesendet werden soll?

                        Du setzt damit nur den HTTP-Header. Dem PHP-Script teilt das gar nichts mit. Nur dem Browser, der daraufhin den Body der Response in dieser Kodierung zu interpretieren versucht. Dass dieser Body ordentlich kodiert ist, musst du anderweitig sicherstellen, indem du Templates und Inhalte korrekt kodierst.

                        Kann man das nicht zentralisieren? Per .htaccess habe ich schon versucht, das brachte nichts…

                        Mit AddDefaultCharset kann man das generell für alle text/plain und text/html einstellen. Wenn es nicht geht, darfst du es nicht überschreiben, weil es AllowOverride verbietet.

                        dedlfix.

                        1. Hi dedlfix,

                          Dass dieser Body ordentlich kodiert ist, musst du anderweitig sicherstellen, indem du Templates und Inhalte korrekt kodierst.

                          So langsam sehe ich wieder Lufft... aber 2 Probleme sind noch vorhanden, ich fang mal nur mit dem ersten an:

                          $query1="select
                          user
                          from table
                          ";
                          
                          $result1 = $db->query($query1);
                          if (!$result1)
                          {
                               error_dbo($query1);
                          }
                          
                          
                          while ($row1 = $result1->fetch()){
                          echo($row1[1]."<br>");
                          }
                          

                          ergibt auf meinem lokalen Server:

                          Peter
                          Jürgen
                          Klaus
                          

                          und auf meinem Server im Netz

                          Peter
                          J�rgen
                          Klaus
                          

                          Wo setze ich da an, um den Fehler zu finden?

                          Pit

                          1. Tach!

                            ergibt auf meinem lokalen Server:

                            Jürgen
                            

                            und auf meinem Server im Netz

                            J�rgen
                            

                            Wo setze ich da an, um den Fehler zu finden?

                            Immer schön separiert und entlang der Verarbeitungskette. Als erstes die Quelle anschauen, also den Datenbankserver. Sind da alle Felder (oder speziell das eine) korrekt konfiguriert? Zeigt der phpMyAdmin die Daten richtig an? Ja, dann wird es wohl nicht am DBMS liegen. Weiter zum PHP-Script. Verbindung wird korrekt aufgebaut mit der richtige charset-Angabe, oder PDO::MYSQL_ATTR_INIT_COMMAND bei veraltetem PHP (< 5.3.6)? Was zeigt dann ein urlencode() zu diesem Wert an? Ist das die richtige Bytefolge für den Umlaut? Weiter zum Browser, denn der bekommt die Daten als nächstes. HTTP-Header alle richtig? Auch die Angaben im Head? Man kann auch die Seite abspeichern und mit einem Hexeditor untersuchen. Wenn dabei allerdings keine UTF-8-Kodierung zu erkennen ist, dann kommt das wohl aus PHP falsch kodiert geliefert.

                            dedlfix.

                            1. Hi dedlfix,

                              Immer schön separiert und entlang der Verarbeitungskette. Als erstes die Quelle anschauen, also den Datenbankserver. Sind da alle Felder (oder speziell das eine) korrekt konfiguriert? Zeigt der phpMyAdmin die Daten richtig an? Ja, dann wird es wohl nicht am DBMS liegen.

                              Ok, phpMyAdmin zeigt "Jürgen" an.

                              Weiter zum PHP-Script. Verbindung wird korrekt aufgebaut mit der richtige charset-Angabe, oder PDO::MYSQL_ATTR_INIT_COMMAND bei veraltetem PHP (< 5.3.6)?

                              php-vers. 5.6 Verbindung per PDO: $db = new PDO("mysql:host=".$db_server.";dbname=".$db_name.";port=3306",$db_user,$db_passwd,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

                              Was zeigt dann ein urlencode() zu diesem Wert an?

                              J%FCrgen

                              Ist das die richtige Bytefolge für den Umlaut? Weiter zum Browser, denn der bekommt die Daten als nächstes. HTTP-Header alle richtig?

                              Content-Type text/html; charset=utf-8

                              Auch die Angaben im Head? Man kann auch die Seite abspeichern und mit einem Hexeditor untersuchen. Wenn dabei allerdings keine UTF-8-Kodierung zu erkennen ist, dann kommt das wohl aus PHP falsch kodiert geliefert.

                              Das müßte ich auf morgen verschieben, dazu muß ich mir erst einen anderen Edito zulegen.

                              Danke für die späte Hilfe, Pit

                              1. Tach!

                                php-vers. 5.6 Verbindung per PDO: $db = new PDO("mysql:host=".$db_server.";dbname=".$db_name.";port=3306",$db_user,$db_passwd,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

                                Nimm doch den charset-Parameter. Du hast ein PHP größer 5.3.6 und muss nicht das umständliche Init-Kommando setzen.

                                Was zeigt dann ein urlencode() zu diesem Wert an?

                                J%FCrgen

                                Das ist ein ISO-8859-1-ü. Sieht erstmal so aus, als ob auf der Verbindung doch kein UTF-8 eingestellt ist.

                                dedlfix.

                                1. Juchhuu,

                                  Nimm doch den charset-Parameter. Du hast ein PHP größer 5.3.6 und muss nicht das umständliche Init-Kommando setzen.

                                  Das ist ein ISO-8859-1-ü. Sieht erstmal so aus, als ob auf der Verbindung doch kein UTF-8 eingestellt ist.

                                  1000 Dank an dedlfix und MudGuard für diesen Hinweis!

                                  Mit dem charset-Parameter wird der Name perfekt dargestellt!

                                  Pit

                              2. Hi,

                                Was zeigt dann ein urlencode() zu diesem Wert an?

                                J%FCrgen

                                also kein UTF-8, das ist ISO-8859-1 (oder -15 oder ...).

                                Da müßte J%C3%BCrgen stehen

                                Ist das die richtige Bytefolge für den Umlaut?

                                nein, siehe oben.

                                cu,
                                Andreas a/k/a MudGuard

                                1. Da müßte J%C3%BCrgen stehen

                                  Genau das steht nun auch da!

                                  Pit