Nicki: Umlaut-Salat aus Datenbank

Hallo,

meine Site (Shop) hat einen Adminbereich mit mehreren Formularen (Kategorien, Neuer Artikel usw.) Die Eingaben aus den Formularen füllen die MySql-Datenbank. In der Datenbank werden die Umlaute html-codiert geschrieben. Beim wiedereinlesen der Daten hat sich die Kodierung geändert.

Beispiel:

Im Formular steht: weiß
In der Datenbank steht: weiß
Beim eingelesen steht dann im Warenkorb: Wei�

(1) Die Kollation aller Tabellen steht auf "utf8_general_ci" ebenso die Kollation der Zeichensatz / Kollation der MySQL-Verbindung.

(2) alle php-Dateien sind als utf-8 codiert/gespeichert

(3) <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Wieso bekomme ich so einen "Umlautsalat"?

Danke schon mal.
Gruß
Nicki

  1. In der Datenbank werden die Umlaute html-codiert geschrieben.

    Warum? Das ist doch Unsinn. Diese Codierung ist für HTML gedacht, nicht für Strings. Und sie ist schon längst aus der Mode.

    Von selbst kann sich da eigentlich nichts ändern. Das ist für die Datenbank ein Text der aus den einzelnen Zeichen & s z l i g ; besteht, mit einem Umlaut hat das nichts mehr zu tun.

    Beim wiedereinlesen der Daten
    Was für einen Schritt meinst du damit?

    1. In der Datenbank werden die Umlaute html-codiert geschrieben.
      Warum? Das ist doch Unsinn. Diese Codierung ist für HTML gedacht, nicht für Strings. Und sie ist schon längst aus der Mode.

      Ich weiß auch nicht, warum das dann so in der DB steht. Ich schreibe ins Formular ganz normal "ß" und in der DB steht dann "&szlig".

      Von selbst kann sich da eigentlich nichts ändern. Das ist für die Datenbank ein Text der aus den einzelnen Zeichen & s z l i g ; besteht, mit einem Umlaut hat das nichts mehr zu tun.

      Beim wiedereinlesen der Daten
      Was für einen Schritt meinst du damit?

      Ich hab da z.B ein Dropdownmenü mit der Auswal der (T-Shirt)-Farbe. Der Besteller kann zwischen weiß|schwarz|blau wählen. Hat er sich für "weiß" entschieden und schaut sich dann den Inhalt des Warenkorbes an, steht da nicht mehr "weiß" sondern "WeiÃ�".

      1. Ich weiß auch nicht, warum das dann so in der DB steht. Ich schreibe ins Formular ganz normal "ß" und in der DB steht dann "&szlig".

        Dann ist der Fehler bei der Übergabe in die Datenbank zu suchen, wenn alles andere ausgeschlossen wurde.

        Hat er sich für "weiß" entschieden und schaut sich dann den Inhalt des Warenkorbes an, steht da nicht mehr "weiß" sondern "WeiÃ�".

        Also gibt es sogar bei deiner Übergabe in die Datenbank auch eine vorherige Bearbeiung mittels ucfirst("weiß"). ;)

        Hast du das Programm geschrieben? Wenn nein, frag den Entwickler wieso die Sonderzeichen so in die Datenbank geschrieben werden.

        1. Tach!

          Ich weiß auch nicht, warum das dann so in der DB steht. Ich schreibe ins Formular ganz normal "ß" und in der DB steht dann "&szlig".
          Dann ist der Fehler bei der Übergabe in die Datenbank zu suchen, wenn alles andere ausgeschlossen wurde.

          MySQL hat von HTML-Entitys keine Ahnung. Der Vorgang, der aus dem ß ein &szlig; macht, findet vorher statt. Und auch der Browser ist unschuldig. Der produziert höchstens NCRs, keine Entitys. Da macht sich also irgendwer zwischen Browser und Datenbank die Mühe, Entitys zu erzeugen.

          Hat er sich für "weiß" entschieden und schaut sich dann den Inhalt des Warenkorbes an, steht da nicht mehr "weiß" sondern "WeiÃ�".
          Hast du das Programm geschrieben? Wenn nein, frag den Entwickler wieso die Sonderzeichen so in die Datenbank geschrieben werden.

          Und warum dann rückwarts die Entitys wieder umgewandelt werden ...

          dedlfix.

    2. In der Datenbank werden die Umlaute html-codiert geschrieben.
      Und sie ist schon längst aus der Mode.

      Jein - es gibt drei große Ausnahmen:

      1. Die 5 markupspezifischen Zeichen müssen (ja, es gibt Ausnahmen) maskiert werden

      2. Unsichtbare Zeichen sollten als Zeichenreferenz angegeben werden (z.B. geschützte Leerzeichen, schmale Leerzeichen, Tabulatoren usw.), weil man nicht davon ausgehen kann, dass das der Texteditor des nächsten der es bearbeitet auch entsprechend darstellen kann.

      3. Dasselbe gilt für schwer unterscheidbare Zeichen wie z.B. verschiedene Arten von horizontalen Strichen (Gedankenstriche, Bindestriche, Minus-Zeichen ...)

      1. Tach!

        In der Datenbank werden die Umlaute html-codiert geschrieben.
        Und sie ist schon längst aus der Mode.
        Jein - es gibt drei große Ausnahmen:

        1. Die 5 markupspezifischen Zeichen müssen (ja, es gibt Ausnahmen) maskiert werden

        Keine Frage, ist zwingend HTML-syntaktisch notwendig.

        1. Unsichtbare Zeichen sollten als Zeichenreferenz angegeben werden [...]
        2. Dasselbe gilt für schwer unterscheidbare Zeichen [...]

        Das mag für Stringliterale im Quelltext sinnvoll sein. Für Daten, die über ein Formular eingegeben werden oder aus irgendeiner anderen Quelle stammen, ist es nicht notwendig, sie in irgendeinem Verarbeitungsschritt oder beim Ausgeben in NCRs oder Entitys umzuwandeln. Ziel der Ausgabe ist ja eine Maschine (Browser) und nicht der Mensch, und die Maschine kann die Zeichen eindeutig an ihrer Kodierung erkennen.

        dedlfix.

        1. Für Daten, die über ein Formular eingegeben werden [...] ist es nicht notwendig, sie in irgendeinem Verarbeitungsschritt oder beim Ausgeben in NCRs oder Entitys umzuwandeln.

          Ich werfe jetzt mal Wikis wie MediaWiki in den Raum wo man durchaus benannte Referenzen in den Quelltext schreiben sollte, damit der nächste Benutzer der den Artikel bearbeitet auch sieht was gemeint ist :)

          1. Tach!

            Für Daten, die über ein Formular eingegeben werden [...] ist es nicht notwendig, sie in irgendeinem Verarbeitungsschritt oder beim Ausgeben in NCRs oder Entitys umzuwandeln.

            Ich werfe jetzt mal Wikis wie MediaWiki in den Raum wo man durchaus benannte Referenzen in den Quelltext schreiben sollte, damit der nächste Benutzer der den Artikel bearbeitet auch sieht was gemeint ist :)

            Wikis sind ein anderer Fall. Bei denen wird Quelltext eingegeben. Der obige Satz bezieht sich auf alle anderen Anwendungsfälle, bei denen nur Text eingegeben wird und der normalsterbliche Anwender nicht mit Code irgendeiner Form in Berührung kommt.

            dedlfix.

  2. Tach!

    In der Datenbank werden die Umlaute html-codiert geschrieben. Beim wiedereinlesen der Daten hat sich die Kodierung geändert.

    Das, hat ja Encoder schon gesagt, ist Unsinn.

    In der Datenbank steht: wei&szlig;
    Beim eingelesen steht dann im Warenkorb: Wei�

    Das passt nicht. Da fehlt ein Zwischenschritt, der aus dem Entity wieder ein Zeichen macht. Mit dem Entity bekommst du in keinem Fall einen Zeichensalat - was nicht heißt, dass Entitys und NCRs die Lösung aller Probleme seien.

    Andere Vermutung: da steht doch ein richtiges ß in dem fraglichen Datensatz (oder auch ein falsch kodiertes, aber kein Eintity).

    (1) Die Kollation aller Tabellen steht auf "utf8_general_ci" ebenso die Kollation der Zeichensatz / Kollation der MySQL-Verbindung.

    Das ist nicht weiter wichtig. Es zählt das, was für das jeweilige Feld eingestellt ist. Siehe http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung/MySQL.

    (2) alle php-Dateien sind als utf-8 codiert/gespeichert

    Ist nur von Bedeutung, wenn darin Texte/Strings stehen.

    (3) <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    Diese Angabe hat nur den zweiten Rang. Siehe http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung/Webdokumente und auch http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung/Webserver

    Wieso bekomme ich so einen "Umlautsalat"?

    Dir fehlt vielleicht die Angabe wie zwischen PHP und MySQL kodiert werden soll. Siehe erster Link.

    Wichtig sind immer zwei Dinge: Jedes System muss mit der Kodierung umgehen können, es sei denn, es ist nur Durchreicher. Zwischen zwei Systemen muss definiert sein, wie die Daten übertragen werden. Gegebenenfalls ist das auszuhandeln oder einfach nur anzugeben.

    Demzufolge reicht es nicht, nur das Feld zu konfigurieren, denn das erfüllt nur die erste Bedingung. Die zweite Bedingung wird erfüllt ... siehe erster Link. Erfüll erstmal beide Bedingungen für alle beteiligten Systeme (Datenbank, Webserver, Browser). Wenn dann noch Fehler auftreten, sind deine Daten kaputt.

    dedlfix.

  3. Vielen Dank erstmal für die vielen Anregungen.

    Einen kleinen Nachtrag hätte ich da noch, der Umlaut-Salat betrifft nur die Ergebnisse aus den Dropdown-Menüs. Alle anderen Felder, (z.B. der Namen des Artikels) werden richtig dargestellt. Keine Ahnung, warum nur DIESE Felder betroffen sind..

    Gruß
    Nicki

    1. Tach!

      der Umlaut-Salat betrifft nur die Ergebnisse aus den Dropdown-Menüs. Alle anderen Felder, (z.B. der Namen des Artikels) werden richtig dargestellt. Keine Ahnung, warum nur DIESE Felder betroffen sind..

      Ich vermute, und sagte das bereits, dass irgendeine Stelle deines Codes händisch eine Umwandlung in HTML-Entitys vornimmt. Für Drop-Downs wird dies anscheinend vergessen. Und dann hast du vermutlich das allgemeine Problem, dass du auf der Verbindung zum DBMS nicht angibst, welche Kodierung zu nehmen sei.

      dedlfix.

      1. Hi

        Ich vermute, und sagte das bereits, dass irgendeine Stelle deines Codes händisch eine Umwandlung in HTML-Entitys vornimmt. Für Drop-Downs wird dies anscheinend vergessen.

        Ja du hast Recht, ich hab den fehler gefunden. Folgende Zeile habe ich ergänzt, jetzt klappt es! Danke für den Tipp.

        Vorher:
        htmlentities($_POST['variante2']);

        Nachher:
        htmlentities($_POST['variante2'],ENT_QUOTES,$CHARSET);

        Gruß
        Nicki

        1. Vorher:
          htmlentities($_POST['variante2']);

          Nachher:
          htmlentities($_POST['variante2'],ENT_QUOTES,$CHARSET);

          Tagschön!

          Besser wäre bei
          mysql-client-encoding()
          iconv-get-encoding()

          zu lesen und ggf. mit

          mysql-set-charset()
          iconv-set-encoding()

          und (nur im Notfall) mit
          iconv()

          zu korrigieren.

          MfG

          Jörg Reinholz

          1. Tach!

            Vorher:
            htmlentities($_POST['variante2']);
            Nachher:
            htmlentities($_POST['variante2'],ENT_QUOTES,$CHARSET);
            Besser wäre bei
            mysql-client-encoding()
            iconv-get-encoding()
            zu lesen und ggf. mit

            Das Lesen der eingestellten Werte bringt keinen gesteigerten praktischen Nutzen. Einfach mit

            mysql-set-charset()

            die Kodierung setzen, die man verwendet, und fertig ist. Man spart sich dabei das Lesen des Wertes samt bedingtem Draufreagieren.

            iconv-set-encoding()
            und (nur im Notfall) mit
            iconv()

            Dieser Notfall darf nur dann auftreten, wenn man mit (fremden) Systemen kommunizieren muss, die andere Kodierungen verwenden. Wenn man alles unter eigener Kontrolle hat, sollte man tunlichst auf die durchgehende Verwendung _einer_ Kodierung achten. Da HTML bereits mit nichts geringerem als Unicode arbeitet, ergibt sich eigentlich zwingend, dass man mit einer Unicode-Kodierung arbeitet, wenn man keinen Zeichenverlust erleiden möchte.

            Der/die OP hat aber anscheinend keine Lust, das fehlerhafte System grundlegend zu korrigieren, sondern hat nur nach einer "funktionierenden" Patch gesucht. Es bringt da auch nicht viel, noch mysql_set_charset() anzuwenden, weil eh schon alles verASCIIt wurde.

            dedlfix.

            1. Das Lesen der eingestellten Werte bringt keinen gesteigerten praktischen Nutzen.

              Doch doch. Es zeigt dem Frager, warum und worin sein Problem eigentlich besteht. Auf die Lösung mit mysql-set-charset() wird er dann doch wohl kommen, weil die auf der Seite zu mysql-client-encoding() auch gleich mit steht...

              Nicht grundlos schrieb ich er solle besser "bei" mysql-client-encoding() und
              iconv-get-encoding() lesen.

              Der/die OP hat aber anscheinend keine Lust, das fehlerhafte System grundlegend zu korrigieren,

              Da fragt jemand und hat eigentlich keine Lust, es richtig zu machen.

              Hm. Leiste ich da etwa Beihilfe zum Pfusch?

              MfG
              Jörg Reinholz

              1. Tach!

                Das Lesen der eingestellten Werte bringt keinen gesteigerten praktischen Nutzen.
                Doch doch. Es zeigt dem Frager, warum und worin sein Problem eigentlich besteht.

                Für den (Debugging-)Augenblick vielleicht. Dieser Wert ist jedoch nicht in jedem Fall richtig, denn er berücksichtigt nicht das, was man mit SET NAMES einstellen kann.

                Im Betrieb (und wenn man es grundlegend richtig machen will) setzt man einfach die Zeichenkodierung mit mysql_set_charset() definiert auf den gewünschten Wert und muss sich nicht darum kümmern, was der Default-Wert ist. Der kann sich schließlich (theoretisch) jederzeit ändern.

                Auf die Lösung mit mysql-set-charset() wird er dann doch wohl kommen, weil die auf der Seite zu mysql-client-encoding() auch gleich mit steht...

                Dazu braucht man aber das grundlegende Verständnis, dass es Unterschiede zwischen der Einstellung der Felder/Tabellen/Datenbanken und der Einstellung auf der Client-Verbindung gibt, und man letztlich beides braucht.

                Nicht grundlos schrieb ich er solle besser "bei" mysql-client-encoding() und iconv-get-encoding() lesen.

                Gründe, die du nicht anführst, kann ich nur sehr schwer berücksichtigen. Besonders schwer fällt mir das, wenn du auf Funktionen verweist, die mit dem Problem meiner Meinung nach nichts zu tun haben. Die iconv-Funktionen haben nämlich keinerlei Auswirkungen auf den Rest PHPs.

                dedlfix.