Datenbank-Heini: Türkisch in DB speichern

Moin Leute,

auf meiner Seite können sich registrierte Nutzer in einem eigens erstellten Profil vorstellen. Das Profil kann der jederzeit geändert werden. Der Eingabetext wird in meiner Datenbank mySql(V5.1.61) gespeichert, nachdem der Text die Funktion htmlspecialchars() durchlaufen hat.
Das Feld in der Datenbank ist ein Longtext utf8_unicode.

Jetzt wollte ein Nutzer folgenden Text speichern:
Hastalığa karşı değil, Sağlık için…

In meiner Datenbank wurde aber folgedes gespeichert:
Hastalığa karşı değil, Sağlık için…

Wie mache ich es richtig, damit die Nutzer auch wie hier z.B. einen türkischen Text speichern können?

Besten Dank für Eure Hilfe

Datenbank-Heini

  1. Tach!

    Der Eingabetext wird in meiner Datenbank mySql(V5.1.61) gespeichert, nachdem der Text die Funktion htmlspecialchars() durchlaufen hat.

    Was willst du mit HTML-spezifisch kodierten Zeichen in der Datenbank? Dort gehören sie nicht hin, sondern nur in die HTML-Ausgabe.

    Das Feld in der Datenbank ist ein Longtext utf8_unicode.
    Jetzt wollte ein Nutzer folgenden Text speichern:
    Hastalığa karşı değil, Sağlık için…
    In meiner Datenbank wurde aber folgedes gespeichert:
    Hastalığa karşı değil, Sağlık için…

    Vermutlich kam das bereits so vom Browser. Das kannst du mit einer Kontrollausgabe der Eingabedaten überprüfen. Schau dazu aber in die Quelltextansicht, denn die ausgegebenen NCRs werden ja vom Browser in Zeichen gewandelt.

    Ich nehme an, dass du deine Webseite nicht in UTF-8 erstellt und so ausgezeichnet hast. Stattdessen wird der Browser von ISO-8859-1 oder so etwas ähnlichem ausgehen. Er versucht dann die Formulareingaben nach ISO-8859-1 (oder was auch immer) zu kodieren, was er aber bei den Nicht-ASCII-Zeichen nicht schafft. Stattdessen nehmen einige Browser die NCRs als Ersatz. Alternativ bekommst du Zeichenverlust meist in Form eines Fragezeichens..

    Wie mache ich es richtig, damit die Nutzer auch wie hier z.B. einen türkischen Text speichern können?

    Verwende in der gesamten Verarbeitungskette durchgängig UTF-8. Überleg dir, an welchen Stellen die Daten in ein anderes System übergeben werden. Ermittle dann, wie dem Zielsystem die Zeichenkodierung mitgeteilt werden muss. Überzeug dich, dass deine Systeme UTF-8 verstehen können, solange sie die Daten nicht einfach unverändert durchreichen. Und prüfe, dass du auch wirklich UTF-8 weitergibst und empfängst.

    Das war die grobe Richtlinie. Der Teufel steckt im Detail, aber dazu kannst du ja Detailfragen stellen, wenn du die Antwort nicht bereits im SELFHTML-Wiki-Bereich zu Zeichenkodierungen findest. Beachte außerdem die Kontextwechsel-Problematik, um die notwendigen kontextspezifischen Schreibweisen nicht an der falschen Stelle anzuwenden.

    dedlfix.

    1. Der Eingabetext wird in meiner Datenbank mySql(V5.1.61) gespeichert, nachdem der Text die Funktion htmlspecialchars() durchlaufen hat.

      In meiner Datenbank wurde aber folgedes gespeichert:
      Hastalığa karşı değil, Sağlık için…

      Vermutlich kam das bereits so vom Browser.

      Kann eigentlich nicht sein. Wenn vom Browser der Text ı käme, hätte htmlspecialchars() daraus ı gemacht.

      1. Tach!

        Der Eingabetext wird in meiner Datenbank mySql(V5.1.61) gespeichert, nachdem der Text die Funktion htmlspecialchars() durchlaufen hat.
        In meiner Datenbank wurde aber folgedes gespeichert:
        Hastalığa karşı değil, Sağlık için…
        Vermutlich kam das bereits so vom Browser.
        Kann eigentlich nicht sein. Wenn vom Browser der Text ı käme, hätte htmlspecialchars() daraus ı gemacht.

        Das ist vemutlich auch so. Ich glaube nicht, dass der OP den tatsächlich im DBMS gespeicherten Wert gesehen hat. Vielmehr wird er die Ausgabe im Browser gesehen haben und daraufhin auf den DBMS-Eintrag geschlossen haben. Zwischen DBMS und Browser-Ausgabe liegen aber noch mindestens zwei Übergaben (DBMS->PHP, PHP->Browser) und einmal Verarbeiten (PHP), bei denen alles mögliche passieren kann, besonders wenn man es nicht genau definiert sondern dem Zufall überlässt. Jedenfalls, beim Ausgeben des Textes über den Browser wird das & wieder zu & und danach die restlichen Zeichen angezeigt. Ein Blick in die Quelltextansicht des Browsers sollte diese Vermutung bestätigen, denn da sollte dann ı zu sehen sein.

        dedlfix.

  2. #Der Eingabetext wird in meiner Datenbank mySql(V5.1.61) gespeichert, nachdem der Text die Funktion htmlspecialchars() durchlaufen hat.
    Das Feld in der Datenbank ist ein Longtext utf8_unicode.

    Jetzt wollte ein Nutzer folgenden Text speichern:
    Hastalığa karşı değil, Sağlık için…

    In meiner Datenbank wurde aber folgedes gespeichert:
    Hastalığa karşı değil, Sağlık için…

    Da PHP Zeichen als solche nicht kennt, hat htmlspecialchars() unter anderem einen Parameter, der die Zeichenkodierung bestimmt. Vielleicht probierst du damit mal ein wenig.
    Mir ist zwar im Moment schleierhaft, warum das überhaupt notwendig wäre, htmlspecialchars() ist nicht htmlentities() und soll nur fünf einfache Zeichen im untersten Bereich umwandeln, aber vielleicht hilft's ja.

    Davon ganz unabhängig solltest du Texte meiner Meinung nach besser erst dann mit htmlspecialchars() sichern, wenn es wirklich nötig ist - nämlich direkt bei der Ausgabe. Der Datenbank tut HTML nicht weh und vor allem verschleiert die Absicherung gleich nach der Eingabe nur den Zustand der Daten an der Ausgabe.
    Woher soll ich wissen, ob Daten sicher ausgegeben werden können? Weil ich sie irgendwann mal irgendwo abgesichert habe und darauf vertraue, das "ja immer so zu machen"? Wäre mir zu gewagt. Steht die Absicherung direkt bei der Ausgabe, stellt sich die Frage gar nicht erst, weil htmlspecialchars() gleich beim echo zu sehen ist und nicht kilometerweit entfernt bei irgendeiner Eingabebehandlung. Vertrauen ist gut, Kontrolle ist besser.

    Dein Kodierungsproblem wegen des merkwürdigen htmlspecialchars()-Verhaltens täte sich obendrein in Wohlgefallen auflösen. Aber das nur als Anregung.

    1. Tach!

      Da PHP Zeichen als solche nicht kennt, hat htmlspecialchars() unter anderem einen Parameter, der die Zeichenkodierung bestimmt. Vielleicht probierst du damit mal ein wenig.
      Mir ist zwar im Moment schleierhaft, warum das überhaupt notwendig wäre, htmlspecialchars() ist nicht htmlentities() und soll nur fünf einfache Zeichen im untersten Bereich umwandeln, aber vielleicht hilft's ja.

      Nein, das hilft garantiert nicht, denn htmlspecialchars() ist nicht htmlentities(), wie du schon erkannt hast. Die NCRs stammen auf keinen Fall von htmlspecialchars().

      Der Zeichenkodierungsparameter hat bei htmlspecialchars() für ISO-8859-x und UTF-8 keinerlei Auswirkung. Die behandelten Zeichen liegen alle im ASCII-Teil, dessen Byte-Werte 00..7F auch nur für diesem verwendet werden. Kombinationen aus mehreren Bytes werden bei UTF-8 mit Werten oberhalb von 7F gebildet. Einige (asiatische) Kodierungen verwenden Werte aus dem Bereich 00..7F in Kombination mit anderen Werten für Nicht-ASCII-Zeichen. Die Kenntnis der Kodierung spielt nur bei diesen Kodierungen eine Rolle, um solche Kombinationen korrekt erkennen zu können.

      Davon ganz unabhängig solltest du Texte meiner Meinung nach besser erst dann mit htmlspecialchars() sichern, wenn es wirklich nötig ist - nämlich direkt bei der Ausgabe. Der Datenbank tut HTML nicht weh

      Oh doch. Zum einen verbrauchen die NCRs (oder andere Ersatzschreibweisen üblicherweise) mehr Zeichen als das originale korrekt kodierte. Dabei kann beim Speichern in Feldern mit begrenzter Zeichenanzahl ein Verlust auftreten. Noch dazu meldet MySQL diesen Verlust nur mit einer Warnung, die aber kaum jemand auswertet. Zum anderen lässt sich mit einer Ersatzschreibweise keine gescheite Stringverarbeitung (inklusive Sortierung) mehr betreiben. Hühner werden beispielsweise vor Hasen einsortiert, weil &...; kleiner als a ist.

      Dein Kodierungsproblem wegen des merkwürdigen htmlspecialchars()-Verhaltens täte sich obendrein in Wohlgefallen auflösen.

      Nö, sicher nicht. Die Zeichenkodierungsproblematik löst sich nicht in Wohlgefallen auf, indem man sie komplett ignoriert. Er wird nicht drum herumkommen, die Beziehungen zwischen allen beteiligten Systemem diesbezüglich zu beleuchten.

      dedlfix.

      1. Davon ganz unabhängig solltest du Texte meiner Meinung nach besser erst dann mit htmlspecialchars() sichern, wenn es wirklich nötig ist - nämlich direkt bei der Ausgabe. Der Datenbank tut HTML nicht weh

        Oh doch.

        Nein. Dass MySQL wegen HTML in irgendeinem Feld sich verselbständigt hätte oder gar explodiert wäre, ist mir jedenfalls noch nicht untergekommen.

        Zum anderen lässt sich mit einer Ersatzschreibweise keine gescheite Stringverarbeitung (inklusive Sortierung) mehr betreiben. Hühner werden beispielsweise vor Hasen einsortiert, weil &...; kleiner als a ist.

        Da hast du zwar eine richtige Schlussfolgerung gezogen, aber als Antwort auf meine lang und breit ausgeführte Empfehlung ist sie völlig belanglos.

        Wenn er die Texte erst, siehe Zitat oben, "bei der Ausgabe" durch htmlspecialchars() jagt, nicht schon nach der Eingabe, kommt logischerweise auch kein Hühnchen in die Datenbank.

        Zum einen verbrauchen die NCRs (oder andere Ersatzschreibweisen üblicherweise) mehr Zeichen als das originale korrekt kodierte.

        Dabei kann beim Speichern in Feldern mit begrenzter Zeichenanzahl ein Verlust auftreten.

        Das erscheint mir nun, mit Verlaub, etwas albern. Wer wegen der Kodierung einiger Zeichen Datenverlust erleidet, der hat ein ganz anderes Problem als die Kodierung: Die zu knapp bemessenen Felder.

        Aber, ich schreib's zum dritten Male, wenn's nach mir geht, sollen die Texte ja gar nicht HTML-kodiert in der Datenbank landen.

        1. Tach!

          Davon ganz unabhängig solltest du Texte meiner Meinung nach besser erst dann mit htmlspecialchars() sichern, wenn es wirklich nötig ist - nämlich direkt bei der Ausgabe. Der Datenbank tut HTML nicht weh
          Oh doch.
          Nein. Dass MySQL wegen HTML in irgendeinem Feld sich verselbständigt hätte oder gar explodiert wäre, ist mir jedenfalls noch nicht untergekommen.

          Explodieren wird es nicht, aber es kann wie gesagt zu Datenverlust und anderen "seltsamen" Folgefehlern kommen.

          Zum anderen lässt sich mit einer Ersatzschreibweise keine gescheite Stringverarbeitung (inklusive Sortierung) mehr betreiben. Hühner werden beispielsweise vor Hasen einsortiert, weil &...; kleiner als a ist.
          Da hast du zwar eine richtige Schlussfolgerung gezogen, aber als Antwort auf meine lang und breit ausgeführte Empfehlung ist sie völlig belanglos.
          Wenn er die Texte erst, siehe Zitat oben, "bei der Ausgabe" durch htmlspecialchars() jagt, nicht schon nach der Eingabe, kommt logischerweise auch kein Hühnchen in die Datenbank.

          Du gehst davon aus, dass die verwendete Funktion der Übeltäter wäre und deine Empfehlung das Problem löst. Das ist aber nach meinem Dafürhalten nicht der Fall. Die Empfehlung löst nur ein nebensächliches Problem, aber nicht das eigentliche des OP. Da das nebensächliche Problem durch die fehlerhafte Anwendung von htmlspecialchars() ebenfalls negativen Einfluss auf die Datenhaltung hat, was du jedoch verneintest, habe ich hier zum Widerspruch angesetzt.

          Zum einen verbrauchen die NCRs (oder andere Ersatzschreibweisen üblicherweise) mehr Zeichen als das originale korrekt kodierte.
          Dabei kann beim Speichern in Feldern mit begrenzter Zeichenanzahl ein Verlust auftreten.
          Das erscheint mir nun, mit Verlaub, etwas albern. Wer wegen der Kodierung einiger Zeichen Datenverlust erleidet, der hat ein ganz anderes Problem als die Kodierung: Die zu knapp bemessenen Felder.

          Nö. Wenn vorgesehen ist, dass ein bestimmter Wert maximal x Zeichen hat, muss ich das Feld nicht auf n*x Zeichen dimensionieren, nur damit alle fehlerhaft verwendeten Ersatzschreibweisen Platz darin haben. Ich fände es albern, das Feld nur wegen nicht erkannter Programmierfehler aufzubohren.

          Aber, ich schreib's zum dritten Male, wenn's nach mir geht, sollen die Texte ja gar nicht HTML-kodiert in der Datenbank landen.

          Richtig, das ist auch mein Anliegen. Das Weglassen von htmlspecialchars() trägt jedoch nur einen kleinen Beitrag bei (der in der Beschreibung des OP aber gar nicht relevant geworden ist - was aber mit anderen Daten noch werden kann).

          dedlfix.

      2. Tach!

        Da PHP Zeichen als solche nicht kennt, hat htmlspecialchars() unter anderem einen Parameter, der die Zeichenkodierung bestimmt. Vielleicht probierst du damit mal ein wenig.
        Mir ist zwar im Moment schleierhaft, warum das überhaupt notwendig wäre, htmlspecialchars() ist nicht htmlentities() und soll nur fünf einfache Zeichen im untersten Bereich umwandeln, aber vielleicht hilft's ja.
        Nein, das hilft garantiert nicht, denn htmlspecialchars() ist nicht htmlentities(), wie du schon erkannt hast. Die NCRs stammen auf keinen Fall von htmlspecialchars().

        Und noch ein Argument, das gegen die htmlspecialchars()-Theorie spricht: Selbst wenn der OP fälschlicherweise htmlspecialchars() genannt hat und stattdessen im eigentlichen Programm htmlentities() verwendet hat, kann das beschriebene Fehlerbild nicht auftreten. Beide Funktionen erzeugen keine NCRs, mit Ausnahme des NCRs für den Apostroph.

        htmlspecialchars() schreibt also keines der gezeigten Zeichen um, htmlentities() lediglich das ç, was aber zu ç wird. Der Rest der Zeichen wird ignoriert, weil es dafür keine Entitys gibt. (Diese Aussage ist gültig für PHP-Versionen kleiner als 5.4. Ab 5.4 kann man sich HTML5 wünschen, was ein paar Zeichen mehr berücksichtigt, aber immer noch keine NCRs erzeugt.)

        dedlfix.

      3. @@dedlfix:

        nuqneH

        Der Datenbank tut HTML nicht weh

        Oh doch. Zum einen verbrauchen die NCRs (oder andere Ersatzschreibweisen üblicherweise) mehr Zeichen als das originale korrekt kodierte. […] Zum anderen lässt sich mit einer Ersatzschreibweise keine gescheite Stringverarbeitung (inklusive Sortierung) mehr betreiben.

        Das vielleicht wichtigste Argument fehlt noch: Es ist nicht gesagt, dass die Texte in der Datenbank später überhaupt als HTML ausgegeben werden sollen. Vielleicht will man sie ja auch mal anders weiterverarbeitet und braucht dann unbedingt die richtigen Zeichen.

        Qapla'

        --
        „Perfektion ist nicht dann erreicht, wenn es nichts mehr hinzuzufügen gibt, sondern wenn man nichts mehr weglassen kann.“ (Antoine de Saint-Exupéry)
  3. Hallo Leute,

    ich komme leider erst jetzt dazu, mich weiter mit meinem Problem zu beschäftigen.

    Also, ich fasse nochmal detailiert zusammen, was wann wie und wo gespeichert bzw. mit der Variable gemacht wird:

    1.) die Dateneingabe vom User durchläuft htmlspecialchars()
    2.) die Dateneingabe wird in meiner Datenbank MySql(V5.1.61) in einem Longtext utf8_unicode gespeichert

    3.) Zur Anzeige wird der Browser mit <meta http-equiv="content-type" content="text/html; charset=UTF-8"> gestartet
    4.) Nachdem das Datenbankfeld ausgelesen wurde, durchläuft die Variable  zunächst htmlentities() und anschließend nl2br() und wird dann ausgegegeben.

    Zur Problemstellung:
    -----------------------------------------------------------------------
    [Folgender Text wird vom User eingegeben:]
    Doğal Tıp | Psikolojik Danışmanlık

    [Folgendes steht dann in der Datenbank:]
    Do&amp;#287;al T&amp;#305;p | Psikolojik Dan&amp;#305;&amp;#351;manl&amp;#305;k

    [Beim auslesen steht im Quelltext des Browsers:]
    Do&amp;amp;#287;al T&amp;amp;#305;p | Psikolojik Dan&amp;amp;#305;&amp;amp;#351;manl&amp;amp;#305;k

    [Und folgendes wird im Browser ausgegeben:]
    Do&amp;#287;al T&amp;#305;p | Psikolojik Dan&amp;#305;&amp;#351;manl&amp;#305;k
    -----------------------------------------------------------------------

    Die Ausgabe ist also nicht identisch mit der Eingabe.

    Wo liegt nun der Fehler, beim speichern oder beim ausgeben?
    Und die viel wichtigere Frage: Wie mache ich es richtig?

    Besten Dank für hilfreiche Beiträge

    1. Tach!

      Also, ich fasse nochmal detailiert zusammen, was wann wie und wo gespeichert bzw. mit der Variable gemacht wird:

      Das war ja schon in deinem Ausgangsposting einigermaßen klar. Welchen von den Hinweisen bist du bereits nachgegangen und was für ein Ergebnis hast du bekommen?

      1.) die Dateneingabe vom User durchläuft htmlspecialchars()

      Das ist Unsinn, wie schon gesagt. htmlspecialchars() ist für die Ausgabe und nicht für die Eingabedaten vorgesehen. Aber viel interessanter wäre, wie das aussieht, was vom Anwender kommt. An dieser Stelle, so meine Vermutung, sind die Zeichen bereits verunstaltet.

      2.) die Dateneingabe wird in meiner Datenbank MySql(V5.1.61) in einem Longtext utf8_unicode gespeichert

      Davor fehlt noch, ob die Zeichenkodierung mit dem MySQL-Server ausgehandelt wurde. Bis jetzt hast du anscheinend nur gesagt, wie die Daten abgelegt werden sollen, aber nicht mitgeteilt, in welcher Kodierung sie übergeben werden.

      3.) Zur Anzeige wird der Browser mit <meta http-equiv="content-type" content="text/html; charset=UTF-8"> gestartet

      Der Browser läuft schon. Du deklarierst damitl lediglich die Zeichenkodierung des Dokuments - falls der Webserver das nicht bereits in einem HTTP-Header getan hat, denn diese Meta-Angabe ist nur ein Ersatz dafür. Bitte prüf das mit einem Tool, das die HTTP-Header anzeigen kann, beispielsweise die livehttpheaders-Extension für den Firefox.

      Was ist mit der Seite, die das Eingabeformular enthält? Prüf diese bitte auch an beiden Stellen: Meta-Angabe und HTTP-Headers.

      4.) Nachdem das Datenbankfeld ausgelesen wurde, durchläuft die Variable  zunächst htmlentities() und anschließend nl2br() und wird dann ausgegegeben.

      htmlentities() ist bei UTF-8 nicht notwendig. Lediglich htmlspecialchars() musst du anwenden. Und zwar hier bei der Ausgabe und nicht bei den Eingabedaten.

      [Folgender Text wird vom User eingegeben:]
      Doğal Tıp | Psikolojik Danışmanlık

      [Folgendes steht dann in der Datenbank:]
      Do&amp;#287;al T&amp;#305;p | Psikolojik Dan&amp;#305;&amp;#351;manl&amp;#305;k

      Das war das falsch verwendete htmlspecialchars(), das hat die & der NCRs zu &amp; gemacht. Wie schaust du dir eigentlich an, was in der Datenbank steht? Die ist schließlich eine Art Blackbox. Wie stellst du sicher, dass nicht beim Auslesen irgendwelche Umkodierungen gleich welcher Art vorgenommen werden?

      [Beim auslesen steht im Quelltext des Browsers:]
      Do&amp;amp;#287;al T&amp;amp;#305;p | Psikolojik Dan&amp;amp;#305;&amp;amp;#351;manl&amp;amp;#305;k

      Das war das htmlentities(), das hat die & von den &amp; zu &amp; gemacht, woraus sich &amp;amp;NCR; ergibt.

      [Und folgendes wird im Browser ausgegeben:]
      Do&amp;#287;al T&amp;#305;p | Psikolojik Dan&amp;#305;&amp;#351;manl&amp;#305;k

      Klar, der interpretiert das &amp; richtig und gibt den Rest aus.

      Die Ausgabe ist also nicht identisch mit der Eingabe.

      Aus Sicht der Scriptverarbeitung (Eingabe zum DBMS und DBMS zum Browser) hast du ja auch einmal falsch HTML-kodiert. Ansonsten würdest du genau das sehen, was das Script als Eingabedaten gesehen hat.

      Wo liegt nun der Fehler, beim speichern oder beim ausgeben?

      Davor - vermutlich.

      Und die viel wichtigere Frage: Wie mache ich es richtig?

      Das hab ich doch schon verlinkt.

      dedlfix.

      1. @@dedlfix:

        nuqneH

        Bitte prüf das mit einem Tool, das die HTTP-Header anzeigen kann, beispielsweise die livehttpheaders-Extension für den Firefox.

        Der W3C Internationalization Checker sollte hier gute Dienste tun und die Installation eines Plugins überflüssig machen.

        Qapla'

        --
        „Perfektion ist nicht dann erreicht, wenn es nichts mehr hinzuzufügen gibt, sondern wenn man nichts mehr weglassen kann.“ (Antoine de Saint-Exupéry)