heinetz: Umstellung auf UTF-8

Hallo Forum,

ich würde gerne eine recht komplexe PHP-Site auf UTF-8 umstellen und habe mit 3 Einstellungen begonnen:

1. header("Content-Type: text/html; charset=utf-8");
2. mysql_query("SET NAMES 'utf8'");
3. <meta content="text/html; charset=utf-8" http-equiv="Content-Type">

... was den grössten Teil abzufangen scheint. Nun gibt es das ein oder andere fehlerhaft dargestellte Sonderzeichen, dass auf als iso-codierte Files zurückzuführen ist, aber darüber hinaus funktioniert z.B. die Suche auf der Site nicht richtig und es gibt noch eine andere Stelle, an der GET-Parameter
nicht mehr korrekt dargestellt werden. Gibt es da (GET) etwas zu bedenken?

danke für Tipps und

beste gruesse,
heinetz

  1. Gibt es da (GET) etwas zu bedenken?

    Nein, eigentlich nicht, wenn du zuvor deine URLs ordentlich und kontextgerecht behandelt hast bzw. mit den dafür gedachten funktionen wie http_build_url und http_build_query gearbeitet hast.

    1. Hello,

      Gibt es da (GET) etwas zu bedenken?

      Nein, eigentlich nicht, wenn du zuvor deine URLs ordentlich und kontextgerecht behandelt hast bzw. mit den dafür gedachten funktionen wie http_build_url und http_build_query gearbeitet hast.

      Sehe ich gaaaaaaaaaaaaanz anders!

      Es gibt eine Menge umzustellen in alten Scripten!

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Gibt es da (GET) etwas zu bedenken?

        Nein, eigentlich nicht, wenn du zuvor deine URLs ordentlich und kontextgerecht behandelt hast bzw. mit den dafür gedachten funktionen wie http_build_url und http_build_query gearbeitet hast.

        Sehe ich gaaaaaaaaaaaaanz anders!

        Es gibt eine Menge umzustellen in alten Scripten!

        Ich bezog mich rein auf den Query-String ("GET") - natürlich ist der Rest damit noch lange nicht erledigt.

      2. Ja, das hatte ich auch irgendwo gelesen und dennoch gewagt, es einfach zu versuchen. Fast der ganze Content der Site steht in einer MySQL-DB und der Löwenanteil dessen ist HTML-Code, in dem sämtliche Sonderzeichen geschützt sind. Das, was ich von aussen sehe, sieht nach meinen 3 Eingriffen korrekt aus. Sämtliche fehlerhaften Darstellungen konnte ich reparieren, indem ich die Zeichenkodierungen der betroffenen Dateien angepasst habe.

        Selbst die Suche, bei der u.U. Sonderzeichen als GET übergeben, dann mit regulären Ausdrücken bearbeitet werden und schlussendlich als SQL-Statement
        verwendet werden konnte ich so reparieren.

        Ich will gerne glauben, dass die Umstellung nicht ohne Weiteres möglich ist, aber das Problem wird mir (leider) nicht offensichtlich.

        beste gruesse,
        heinetz

        1. Selbst die Suche, bei der u.U. Sonderzeichen als GET übergeben, dann mit regulären Ausdrücken bearbeitet werden und schlussendlich als SQL-Statement
          verwendet werden konnte ich so reparieren.

          Das ist Unfug.

          Ich will gerne glauben, dass die Umstellung nicht ohne Weiteres möglich ist, aber das Problem wird mir (leider) nicht offensichtlich.

          Wie ich schon sagte: wenn es nur um GET geht und man sauber arbeitet, muss man nichts beachten, da PHP (in beide Richtungen) sämtliche Kontextwechsel-Spezifischen Dinge bereits übernimmt (die richtigen Funktionen müssen natürlich genutzt werden).

          1. Hello,

            Selbst die Suche, bei der u.U. Sonderzeichen als GET übergeben, dann mit regulären Ausdrücken bearbeitet werden und schlussendlich als SQL-Statement
            verwendet werden konnte ich so reparieren.

            Das ist Unfug.

            Ich will gerne glauben, dass die Umstellung nicht ohne Weiteres möglich ist, aber das Problem wird mir (leider) nicht offensichtlich.

            Wie ich schon sagte: wenn es nur um GET geht und man sauber arbeitet, muss man nichts beachten, da PHP (in beide Richtungen) sämtliche Kontextwechsel-Spezifischen Dinge bereits übernimmt (die richtigen Funktionen müssen natürlich genutzt werden).

            Da wird, zumindest bis PHP-5.x, überhaupt nix automatisch beachtet. Vielleicht kann man die Datenbankverbindung bereits voreisntellen, aber ob das klappt, hägt doch immer noch von der API für die DB ab. Die ist aber nicht PHP-spezifisch, sondern Host-spezifisch für das gerade benutzte PHP.

            Und die PHP-Scritpe muss m,an trotzdem allle kontrollieren. "Die passende Funktion" heißt auch, dass man die passende Logik programmieren muss, denn anstelle der Funktionen für Single-Byte-Codierungen nur diejenigen für Multi-Byte-Codierugnen einzusetzen, ist keinesfalls ausreichend!

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. Hello,

              Selbst die Suche, bei der u.U. Sonderzeichen als GET übergeben, dann mit regulären Ausdrücken bearbeitet werden und schlussendlich als SQL-Statement
              verwendet werden konnte ich so reparieren.

              Das ist Unfug.

              Ich will gerne glauben, dass die Umstellung nicht ohne Weiteres möglich ist, aber das Problem wird mir (leider) nicht offensichtlich.

              Wie ich schon sagte: wenn es nur um GET geht und man sauber arbeitet, muss man nichts beachten, da PHP (in beide Richtungen) sämtliche Kontextwechsel-Spezifischen Dinge bereits übernimmt (die richtigen Funktionen müssen natürlich genutzt werden).

              Da wird, zumindest bis PHP-5.x, überhaupt nix automatisch beachtet.

              $_GET  beinhaltet einen 1:1 nutzbaren Wert - wenn dieser weiterverwendet wird, z.B. in einer SQL-Abfrage, muss natürlich wieder entsprechend eine Kontextgerechte Behandlung stattfinden.

              Wie gesagt, ich beziehe mich rein auf die Geschichte: PHP erzeugt URL mit Querystring ("GET") oder PHP nimmt eine GET-Anfrage entgegen.

              Und die PHP-Scritpe muss m,an trotzdem allle kontrollieren. "Die passende Funktion" heißt auch, dass man die passende Logik programmieren muss, denn anstelle der Funktionen für Single-Byte-Codierungen nur diejenigen für Multi-Byte-Codierugnen einzusetzen, ist keinesfalls ausreichend!

              In diesem Kontext interessiert dich das nicht.

              Wenn in $_GET['foo'] "Schöne neue Welt" hat das nicht die Bohne mit mb_-Funktionen zu tun, das ist eine Sache des Webservers, des CGI und der "unteren Ebenen" des PHP-Interpreters.

              Erst wenn du danach mit diesem String hantierst, kommen ggf. mb_-Funktionen zum Tragen.

              Genauso umgekehrt: http_build_query(array('foo' => 'Schöne neue Welt')); Was auch immer du da mit mb_-Funktionen willst, verstehe ich nicht.

  2. Hello,

    ich würde gerne eine recht komplexe PHP-Site auf UTF-8 umstellen und habe mit 3 Einstellungen begonnen:

    1. header("Content-Type: text/html; charset=utf-8");
    2. mysql_query("SET NAMES 'utf8'");
    3. <meta content="text/html; charset=utf-8" http-equiv="Content-Type">

    Da fehlt das "Request-Response" Konzept.

    1. Du machst auf eine Ressource-Anfrage ein Angebot
    2. der User betrachtet das Angebot
    3. der User antwortet auf das Angebot
    4. die Antwort wird ausgewertet und ein neues Angebot erzeugt

    Das bedeutet, dass Du in allen Deinen Angeboten sämtliche Verwendung von Stringfunktionen überprüfen musst. Die Ressource muss utf-8-fest sein. Die gesamte Ausgabe muss multibytefest seein. Wenn es Erkennungen (RegExps) gibt, Ersetzungen gibt (Markierungen im Text), o.ä. müssen die alle multibytefest sein.

    Wenn der User antwortet, also einen neuen Request absendet, muss erkannt werden, ob der tatsächlich in utf-8 codiert stattfindet und dann entsprechend behandelt werden.

    Und dann erst müssen alle Queries und sonstigen internen Abfragen und Verarbeitungen entsprechend geeignet sein.

    Viel Spaß bei der Umstellung. :-O

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
  3. Hallo heinetz,

    1. mysql_query("SET NAMES 'utf8'");

    Die bevorzugte Methode lautet

    mysql_set_charset('utf-8');

    Die PHP-Funktion funktioniert ab PHP 5.2.5 und MySQL 5.0.7

    Gruß, Daniel

  4. Hallo Forum,

    ich fange nochmal an.

    ich würde diese Website gerne auf utf-8 umstellen, kann aber leider nicht einschätzen, mit wieviel Aufwand zum Einen diese Umstellung im Moment und zum Anderen die Weiterentwicklung in Zukunft sein wird. Deshalb bin ich hier mir dem Thema aufgeschlagen. Ich habe geschrieben, was ich bisher versucht habe und wie es für mich aussieht. Dass das keinen Anspruch auf Richtigkeit hat, liegt in der Natur der Sache, denn sonst würde ich hier nicht nachfragen. Wenn etwas daran falsch ist, freue ich mich, wenn ich von euch korrigiert werde.

    Mein (Denk-)Modell
    ------------------
    Ich programmiere eine Website in XHTML. Die besteht aus genau einer Datei index.html, in der lauter ä,ü,ö usw. unmaskiert vorkommen. Jetzt würde ich diese Website gerne als UTF-8 ausliefern(?). Was ist zu tun? Was ich tun würde, wären zwei Dinge:

    a) ich würde index.html mit der Zeichencodierung utf-8 speichern.
    b) ich würde im Code das Metatag:
       <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
       ... einsetzen.
    Das ganze scheint korrekt zu sein. Das schliesse ich daraus, dass ä,ü und ö korrekt dargestellt werden und das Firefox sagt, die Kodierung sei UTF 8.

    ... allerdings nur auf meinem Entwicklungssystem, nicht aber auf dem Server, wo es letztlich laufen soll. Das schiebe ich auf die Information, die ich mit phpinfo() unter "HTTP Response Heiders" / "Content-Type" finde. Hier gibt es m.E. drei Möglichkeiten, das zu überschreiben:

    a) indem man die Konfiguration des Servers direkt ändert (php.ini?)
    b) mit der Direktive AddDefaultCharset in der htaccess (wenn man darf)
    c) mit php : header("Content-Type: text/html; charset=utf-8")

    Für mich kommt bis hierher nur c) in frage und ich benötige also eine index.php statt einer index.html, in die ich c) einsetze.

    Ist bis hierher alles korrekt?

    danke für Tipps und

    beste gruesse,
    heinetz

    1. Hallo

      Mein (Denk-)Modell

      ... Was ich tun würde, wären zwei Dinge:

      a) ich würde index.html mit der Zeichencodierung utf-8 speichern.
      b) ich würde im Code das Metatag:
         <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
         ... einsetzen.
      Das ganze scheint korrekt zu sein. Das schliesse ich daraus, dass ä,ü und ö korrekt dargestellt werden und das Firefox sagt, die Kodierung sei UTF 8.

      Für eine statische Datei soweit korrekt.

      ... allerdings nur auf meinem Entwicklungssystem, ...

      ... wo du es vermutlich als Datei in den Browser lädst, womit dein Metaelement wirksam wird.

      ... nicht aber auf dem Server, wo es letztlich laufen soll. Das schiebe ich auf die Information, die ich mit phpinfo() unter "HTTP Response Heiders" / "Content-Type" finde. Hier gibt es m.E. drei Möglichkeiten, das zu überschreiben:

      a) indem man die Konfiguration des Servers direkt ändert (php.ini?)
      b) mit der Direktive AddDefaultCharset in der htaccess (wenn man darf)
      c) mit php : header("Content-Type: text/html; charset=utf-8")

      Für mich kommt bis hierher nur c) in frage und ich benötige also eine index.php statt einer index.html, in die ich c) einsetze.

      Ist bis hierher alles korrekt?

      Ja, um Daten aus der DB holen, unbearbeitet in ein HTML-Template einfügen und das Resultat auszuliefern, reicht das mit den schon genannten Maßnahmen.

      Werden die Inhalte jedoch vor dem Zusammenbau noch per PHP verarbeitet, kommen die im Thread schon mehrfach erwähnten mb-Stringfunktionen in's Spiel. Die "normalen" PHP-Stringfunktionen können nämlich nicht mit Zeichen umgehen, die in mehr als einem Byte gespeichert werden, wie sie in UTF-8 nunmal vorkommen. Bei der Verwendung der mb-Stringfunktionen muss die zu verwendende Zeichenkodierung mit mb_internal_encoding angegeben werden (es gibt ja derer mehrere), damit die richtige Kodierung auch verwendet wird.

      Tschö, Auge

      --
      Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.
      Terry Pratchett, "Wachen! Wachen!"
      ie:{ fl:| br:> va:) ls:[ fo:) rl:( ss:| de:> js:| zu:}
      Veranstaltungsdatenbank Vdb 0.3
      1. Hallo Forum,

        Für eine statische Datei soweit korrekt.

        gut, danke.

        ... allerdings nur auf meinem Entwicklungssystem, ...

        ... wo du es vermutlich als Datei in den Browser lädst, womit dein Metaelement wirksam wird.

        genau. ich verstehe das so:

        Der Browser benötigt die Information, in welcher Zeichenkodierung er meine index.html darstellen soll. Wenn er die auf keine Weise übermittelt bekommen hat, gibt es wahrscheinlich einen Defaultwert in der Browserkonfiguration, der benutzt wird. Ansonsten wird, wenn die Information nicht vom Server kommt, das Metatag benutzt, was seinerseits keine Auswirkung hat, wenn im Header etwas anderes steht. Der kommt seinerseits vom Server, lässt sich aber mit php:header() überschreiben.

        Ja, um Daten aus der DB holen, unbearbeitet in ein HTML-Template einfügen und das Resultat auszuliefern, reicht das mit den schon genannten Maßnahmen.

        soweit war ich bisher noch garnicht, aber ...

        Mein Denkmodell #2
        ------------------
        Jetzt soll in meiner index.php Content angezeigt werden, der zuvor aus einer MySql-Datenbank geholt wurde. Der Content enthält wieder ä,ü und ö. Ich würde nach der Verbindung zum MySQL-Server folgendes SQL-Statement absetzen:
        mysql_query("SET NAMES 'utf8'");
        ... danach den Content per SQL-Statement aus der DB auslesen, in eine Variable speichern und dann mit php:echo im Quellcode ausgeben.

        Da kommen meine ersten Unsicherheiten ....

        1. Bei der Konfiguration der DB lässt sich auch irgendwo etwas zu Zeichenkodierungen festlegen. Ist es notwendig, auch das anzupassen?

        2. Wenn mein Content ausser 'ä','ü' und 'ö' z.B. '"' oder '<' enthält, dürften die ersten Probleme auftauchen und ich muss ihn also behandeln, bevor er dargestellt wird : htmlentinies() funktioniert nun nicht mehr,
        wenn ich's richtig gelesen habe und es muss statt dessen htmlspecialchars()
        verwendet werden. Richtig?

        tausend Dank für Tipps und

        beste gruesse,
        heinetz

        1. Tach!

          Der Browser benötigt die Information, in welcher Zeichenkodierung er meine index.html darstellen soll.

          Nein. Er bekommt vom Server einen Bytestrom. Und diesen muss er richtig interpretieren, damit er weiß, welche Zeichen sich dahinter verbergen. Beispielsweise kommt ein Zeichen in ISO-8859-1 als Byte X daher und daselbe Zeichen UTF-8-kodiert hat die Bytes Y und Z. Y und Z stehen in ISO-8859-1 aber für zwei andere Zeichen. Der Browser benötigt also zu diesem Zeitpunkt keine Darstellinformation sondern eine Interpretationsinformation.

          Wenn er die auf keine Weise übermittelt bekommen hat, gibt es wahrscheinlich einen Defaultwert in der Browserkonfiguration, der benutzt wird.

          Er rät, so gut er kann. Das kann funktionieren, geht aber prinzipbedingt nicht in allen Fällen glatt.

          Ansonsten wird, wenn die Information nicht vom Server kommt, das Metatag benutzt, was seinerseits keine Auswirkung hat, wenn im Header etwas anderes steht. Der kommt seinerseits vom Server, lässt sich aber mit php:header() überschreiben.

          Richtig.

          Jetzt soll in meiner index.php Content angezeigt werden, der zuvor aus einer MySql-Datenbank geholt wurde. Der Content enthält wieder ä,ü und ö. Ich würde nach der Verbindung zum MySQL-Server folgendes SQL-Statement absetzen:
          mysql_query("SET NAMES 'utf8'");

          mysql_set_charset() sollte zur Verfügung stehen, wenn deine PHP-Version nicht zu alt ist.

          ... danach den Content per SQL-Statement aus der DB auslesen, in eine Variable speichern und dann mit php:echo im Quellcode ausgeben.

          Das echo mag im Quelltext stehen, aber das ist nebensächlich. Interessant ist, wohin die Werte ausgegeben werden. Jedenfalls ist Voraussetzung, dass auch MySQL die richtige Zeichenkodierung kennt und nicht in der Vergangenheit die Daten irgendwie, nur nicht unter Angabe der korrekten Kodierung gespeichert wurden. Überprüfen kann man das einfach mit dem phpMyAdmin, der sollte keine (Umlaut-)Fehler anzeigen, wenn alles korrekt ist.

          1. Bei der Konfiguration der DB lässt sich auch irgendwo etwas zu Zeichenkodierungen festlegen. Ist es notwendig, auch das anzupassen?

          Jein. Empfehlenswert ist es, wenn die Kodierungsangabe der String-Felder (und zwar jedes einzeln) auf UTF-8 steht. Ansonsten kann das Feld nur die 255 ISO-8859-1/Latin1-Zeichen aufnehmen. Wenn die bisherige Kodierungsangabe zum Inhalt passt (z.B. PMA zeigt keine Fehler), dann kannst du die Angabe ändern und MySQL nimmt eine Umkodierung vor.

          Aber selbst wenn in den Feldern Latin1 steht, kannst du mit MySQL UTF-8 sprechen (über mysql_set_charset() oder SET NAMES). MySQL liefert dir die Daten in der ausgehandelten Kodierung und kodiert dazu gegebenenfalls zwischen Feldinhalten und deiner Verbindung um.

          1. Wenn mein Content ausser 'ä','ü' und 'ö' z.B. '"' oder '<' enthält, dürften die ersten Probleme auftauchen und ich muss ihn also behandeln, bevor er dargestellt wird : htmlentinies() funktioniert nun nicht mehr, wenn ich's richtig gelesen habe und es muss statt dessen htmlspecialchars() verwendet werden. Richtig?

          Der Kontextwechsel (Einfügen in HTML-Code) hat mit der Zeichenkodierung eigentlich nichts zu tun. Den musst du in jedem Fall beachten, und dazu ist htmlspecialchars() die richtige Funktion. Die beschränkt sich auf die HTML-eigenen Zeichen und lässt Umlaute und so weiter wie sie sind. Mit UTF-8 besteht keine Notwendigkeit, andere als die HTML-eigenen Zeichen zu ver-HTML-en.

          dedlfix.

          1. Hallo,

            Der Browser benötigt die Information, in welcher Zeichenkodierung er meine index.html darstellen soll.

            Nein. Er bekommt vom Server einen Bytestrom. Und diesen muss er richtig interpretieren, damit er weiß, welche Zeichen sich dahinter verbergen. Beispielsweise kommt ein Zeichen in ISO-8859-1 als Byte X daher und daselbe Zeichen UTF-8-kodiert hat die Bytes Y und Z. Y und Z stehen in ISO-8859-1 aber für zwei andere Zeichen. Der Browser benötigt also zu diesem Zeitpunkt keine Darstellinformation sondern eine Interpretationsinformation.

            ja, das ist wohl ein sehr feiner aber vielleicht wesentlicher Unterschied. Ich habe lange überlegt, ob das nicht genau das ist, was ich meinte.

            Jedenfalls ist Voraussetzung, dass auch MySQL die richtige Zeichenkodierung kennt und nicht in der Vergangenheit die Daten irgendwie, nur nicht unter Angabe der korrekten Kodierung gespeichert wurden. Überprüfen kann man das einfach mit dem phpMyAdmin, der sollte keine (Umlaut-)Fehler anzeigen, wenn alles korrekt ist.

            Unter PMA wird derzeit alles korrekt dargestellt. Ich gehe also davon aus, dass die Daten in meiner MySQL zusammen mit dem richtigen Zeichensatz gespeichert worden sind. Woher aber kannte MySQL den korrekten Zeichensatz?
            Bzw. was ist ausschlaggebend gewesen? Es gibt scheinbar den "Zeichensatz der Verbindung" zwischen MySQL und den Zeichensatz von MySQL-Tabellen bzw. sogar einzelner Felder?

            Jein. Empfehlenswert ist es, wenn die Kodierungsangabe der String-Felder (und zwar jedes einzeln) auf UTF-8 steht. Ansonsten kann das Feld nur die 255 ISO-8859-1/Latin1-Zeichen aufnehmen. Wenn die bisherige Kodierungsangabe zum Inhalt passt (z.B. PMA zeigt keine Fehler), dann kannst du die Angabe ändern und MySQL nimmt eine Umkodierung vor.

            Aber selbst wenn in den Feldern Latin1 steht, kannst du mit MySQL UTF-8 sprechen (über mysql_set_charset() oder SET NAMES). MySQL liefert dir die Daten in der ausgehandelten Kodierung und kodiert dazu gegebenenfalls zwischen Feldinhalten und deiner Verbindung um.

            Ich verstehe das so:
            --------------------
            MySQL(-Tabellen bzw. Felder) enthalten eine Kodierungsangabe (was wohl das ist, was man beim Anlegen der Tabellenstruktur festlegt). Hole ich mir die Daten in einem PHP-Skript per SQL-Statement dort ab, speichere sie dann in einer php-Variable, steht in dieser Variablen mein Content auf diese Weise kodiert. Will ich a) diese Daten dann im Browser ausgeben, muss für die Ausgabe die selbe Kodierung eingestellt sein.
            Sprich: Daten aus einer MySQL-Tabelle mit der Zeichenkodierung Latin1 werden in meiner PHP-Variablen gespeichert. Wird der Inhalt dieser Variablen beim Aufruf meiner index.php im Browser ausgegeben und steht im Header, bzw. Metatag die selbe Zeichenkodierungsangebe, in dem Fall also ISO-8859-1 wird der Inhalt der Variablen korrekt angezeigt und zwar unabhängig davon, mit welcher Zeichenkodierung index.php gespeichert wurde.

            Was verbirgt sich aber wohl hinter der Kodierung der Verbindung?

            Ist damit die Umkodierung gemeint? Sprich, nur wenn php die Daten aus der Latin1-Tabelle als UTF-8 kodiert zur Verfügung gestellt bekommen soll, muss php der DB mit mysql_set_charset() mitteilen, dass sie die Daten als UTF-8 liefern (also umwandeln) soll.

            Interessant wäre dann auch, wie die Anweisung in umgekehrter Richtung (also Daten in der MySQL-DB speichern) funktioniert.

            1. Wenn mein Content ausser 'ä','ü' und 'ö' z.B. '"' oder '<' enthält, dürften die ersten Probleme auftauchen und ich muss ihn also behandeln, bevor er dargestellt wird : htmlentinies() funktioniert nun nicht mehr, wenn ich's richtig gelesen habe und es muss statt dessen htmlspecialchars() verwendet werden. Richtig?

            Der Kontextwechsel (Einfügen in HTML-Code) hat mit der Zeichenkodierung eigentlich nichts zu tun. Den musst du in jedem Fall beachten, und dazu ist htmlspecialchars() die richtige Funktion. Die beschränkt sich auf die HTML-eigenen Zeichen und lässt Umlaute und so weiter wie sie sind. Mit UTF-8 besteht keine Notwendigkeit, andere als die HTML-eigenen Zeichen zu ver-HTML-en.

            Dann habe ich wohl noch etwas falsch verstanden ;)

            Ich meinte, dass a) 'ä','ü' und 'ö' im HTML-Quelltext bei einheitlich richtiger Zeichenkodierung weder in UTF-8 noch ISO-8859-1 maskiert werden müssen, damit sie richtig dargestellt werden die Zeichen '"' und '<' hingegen unabhängig von der Zeichenkodierung im HTML-Quelltext immer zu Problemen führen. Und dass während htmlentities(), was 'ä','ü' und 'ö' genauso wie '"' und '<' maskieren würde zwar mit den ISO-kodierten Daten umgehen kann, mit UTF-8-kodierten Daten aber nicht, für htmlspecialchars() die unterschiedliche Kodierung keine Rolle spielt. Ist also multibyte-sicher?

            tausend Dank für Tipps und

            beste gruesse,
            heinetz

            1. Tach!

              Unter PMA wird derzeit alles korrekt dargestellt. Ich gehe also davon aus, dass die Daten in meiner MySQL zusammen mit dem richtigen Zeichensatz gespeichert worden sind. Woher aber kannte MySQL den korrekten Zeichensatz?

              Zufall. Was auch immer die Default-Einstellung der Verbindungskodierung war, das Programm, das die Daten an MySQL übertragen hat, hat sie verwendet.

              Bzw. was ist ausschlaggebend gewesen? Es gibt scheinbar den "Zeichensatz der Verbindung" zwischen MySQL und den Zeichensatz von MySQL-Tabellen bzw. sogar einzelner Felder?

              Die Kodierungsangabe der einzelnen Felder ist ausschlaggebend. Jedes Feld kann seine eigene unterschiedliche Kodierung haben. Die Tabellen- und auch die Datenbank-Kodierung sind nur Default-Einstellungen, die beim Anlagen untergeordneter Elemente verwendet wird, wenn du keine explizite Angabe machst.

              Und wie schon gesagt, zwischen der Verbindungskodierung und der Feldkodierung wird gegebenenfalls umkodiert. (Nebenbei, man kann sogar einzelnen Stringliteralen eine eigene Kodierungsangabe mitgeben, so dass auch innerhalb des SQL-Statements unterschiedliche Kodierungen stehen können.)

              Ich verstehe das so:

              MySQL(-Tabellen bzw. Felder) enthalten eine Kodierungsangabe (was wohl das ist, was man beim Anlegen der Tabellenstruktur festlegt). Hole ich mir die Daten in einem PHP-Skript per SQL-Statement dort ab, speichere sie dann in einer php-Variable, steht in dieser Variablen mein Content auf diese Weise kodiert.

              Was für die Felder eingestellt ist, legt lediglich fest, was alles darin abgelegt werden kann. Für die Kommunikation mit den Clients ist ausschließlich die Verbindungskodierung relevant. (Ich sage vereinfacht "Verbindungskodierung", in Wirklichkeit sind es drei verschiedene Werte, zwei für den Weg zu MySQL und einer für das Resultset.) In deinen PHP-Variablen stehen nach dem Fetchen die Werte in der Verbindungskodierung (und nicht in der Feldkodierung, wenn diese eine andere war).

              Will ich a) diese Daten dann im Browser ausgeben, muss für die Ausgabe die selbe Kodierung eingestellt sein.

              Ja, oder du musst umkodieren. Üblicherweise will man das nicht, weil dadurch Zeichen verloren gehen können oder durch eine längere Ersatzschreibweise ausgetauscht werden müssen (NCR, Entitys).

              Sprich: Daten aus einer MySQL-Tabelle mit der Zeichenkodierung Latin1 werden in meiner PHP-Variablen gespeichert. Wird der Inhalt dieser Variablen beim Aufruf meiner index.php im Browser ausgegeben und steht im Header, bzw. Metatag die selbe Zeichenkodierungsangebe, in dem Fall also ISO-8859-1 wird der Inhalt der Variablen korrekt angezeigt und zwar unabhängig davon, mit welcher Zeichenkodierung index.php gespeichert wurde.

              Ja. Die Kodierung der PHP-Dateien (nebst Template-Dateien und dergleichen) hat nur Einfluss auf die Stringliterale, die in ihnen stehen.

              Was verbirgt sich aber wohl hinter der Kodierung der Verbindung?
              Ist damit die Umkodierung gemeint? Sprich, nur wenn php die Daten aus der Latin1-Tabelle als UTF-8 kodiert zur Verfügung gestellt bekommen soll, muss php der DB mit mysql_set_charset() mitteilen, dass sie die Daten als UTF-8 liefern (also umwandeln) soll.

              MySQL sollte immer über die tatsächlich auf der Verbindung verwendete Kodierung informiert werden, weil es sonst die ankommenden Bytes selbst falsch interpretiert und im weiteren Verlauf Stringfunktionen (vor allem Vergleichen und Sortieren) nicht richtig arbeiten können. Zudem bekommen dann Programme, die selbst eine korrekte Verbindungskodierung aushandeln, nicht richtig interpretierbare Daten geliefert. Wenn diese Programme dann selbst Daten schreiben, kommt es zu einen Mischmasch. Der PMA ist eines der korrekt arbeitenden Programme, so dass mit diesem die korrekte Speicherung der Daten kontrolliert werden kann.

              Interessant wäre dann auch, wie die Anweisung in umgekehrter Richtung (also Daten in der MySQL-DB speichern) funktioniert.

              Etwas komplexer, weil dafür zwei Werte zuständig sind. Bei Interesse bitte selbst nachlesen: (MySQL-Handbuch Connection Character Sets and Collations)

              Ich meinte, dass a) 'ä','ü' und 'ö' im HTML-Quelltext bei einheitlich richtiger Zeichenkodierung weder in UTF-8 noch ISO-8859-1 maskiert werden müssen, damit sie richtig dargestellt werden die Zeichen '"' und '<' hingegen unabhängig von der Zeichenkodierung im HTML-Quelltext immer zu Problemen führen.

              Stimmt.

              Und dass während htmlentities(), was 'ä','ü' und 'ö' genauso wie '"' und '<' maskieren würde zwar mit den ISO-kodierten Daten umgehen kann, mit UTF-8-kodierten Daten aber nicht, für htmlspecialchars() die unterschiedliche Kodierung keine Rolle spielt. Ist also multibyte-sicher?

              Stimmt nicht mehr. Sowohl htmlentities() als auch htmlspecialchars() verfügen über einen Parameter ($encoding) zur Angabe der Zeichenkodierung. Damit können beide ihre Aufgabe ordnungsgemäß erledigen. Es hat nur den Anschein, dass htmlspecialchars() auch ohne den Parameter multibytefest ist, wenn du lediglich die auf ASCII aufbauenden Kodierungen betrachtest. Es gibt mindestens eine asiatische Kodierung, die die "ASCII-Bytes" (00-7f) mehrfach verwendet.

              Dasselbe gilt für mysql(i)_real_escape_string(), das nicht bei allen Kodierungen richtig arbeiten kann, wenn nicht vorher mysql(i)_set_charset() verwendet wurde. SET NAMES geht direkt in das DBMS und hat keine Auswirkungen auf die Funktionen der MySQL-Client-API. mysql(i)_set_charset() informiert sowohl den Server als auch die MySQL-Client-API-Funktionen. Das ist der Grund, warum SET NAMES nur die zweite Wahl ist, aber keine negativen Auswirkung auf das Arbeiten mit ISO-8859-x und UTF-8 hat.

              dedlfix.

              1. Moin,

                ich muss das häppchenweise begreifen und versuche zusammenzufassen,
                was ich wie verstehe.

                1. PHP:

                Bis PHP (ohne MySQL) erscheint mir alles recht klar.

                2. MySQL: (PHP holt sich die Daten, beeinflusst sie zunächst aber nicht)

                a) Die Kodierungsangabe bezieht sich immer auf Tabellenfelder. Die Codierungsangabe einer Tabelle ist letztlich die Codierungsangabe der Felder in dieser Tabelle.

                b) Die Kodierungsangabe von Tabellenfeldern hat lediglich Einfluss darauf, welche Zeichen in ihr gespeichert werden können.

                c) Einzig die Kodierung der Verbindung zwischen PHP und MySQL hat Einfluss darauf, wie die Daten, die aus der DB ausgelesen werden, (um-)kodiert werden.

                d) Die Codierung der Felder hat keinen Einfluss auf die Codierung der Daten, die PHP im Resultset eines (My)SQL-Statements zur Verfügung stehen.

                e) sind z.B. die Tabellenfelder UTF-8-kodiert stehen sie im Resultset von PHP:mysql_query() in der Form kodiert zur Verfügung, wie die Verbindung zwischen MySQL und PHP kodiert ist.

                f) die Kodierung der Verbindung legt man mit mysql_set_charset() fest. Ohne diesen Befehl greift ein Default.

                alles richtig?

                beste gruesse,
                heinetz

                1. Tach!

                  ich muss das häppchenweise begreifen und versuche zusammenzufassen, was ich wie verstehe.

                  Im Wesentlichen scheint es mir, hast du es verstanden. Ich präzisiere nur noch einige Formulierungen.

                  1. MySQL: (PHP holt sich die Daten, beeinflusst sie zunächst aber nicht)

                  Stimmt. Da PHP grundlegend (noch) auf 1-Byte-Kodierungen ausgelegt ist, gibt es da auch keine Probleme. Problematisch wird es erst dann, wenn PHP in der Lage sein wird, diverse Kodierungen entgegenzunehmen und diese in ein internes Format umkodieren muss. Dann kann es zum Beispiel bei gesendetem ISO-8859-1 und angenommenem UTF-8 wegen der nicht möglichen fehlerfreien Interpretation zu Konvertierverlusten kommen. Aber das ist noch keine Gegenwart.

                  a) Die Kodierungsangabe bezieht sich immer auf Tabellenfelder. Die Codierungsangabe einer Tabelle ist letztlich die Codierungsangabe der Felder in dieser Tabelle.

                  Die Kodierungsangabe bezieht sich immer auf das, wofür sie vorgesehen ist. Bei CREATE DATABASE foo CHARACTER SET ... bezieht sie sich auf die Datenbank, bei CREATE TABLE foo (field1 VARCHAR(50) CHARACTER SET ..., field2 VARCHAR(50)) CHARACTER SET ... bezieht sie sich einmal auf das Feld und einmal auf die Tabelle. Für field2 ist keine explizite Angabe gemacht worden, also wird die Angabe für die Tabelle verwendet.

                  b) Die Kodierungsangabe von Tabellenfeldern hat lediglich Einfluss darauf, welche Zeichen in ihr gespeichert werden können.

                  Ja. Dazu kommt üblicherweise auch noch eine Kollationsangabe, die mit der Kodierung zusammenhängt, aber die kommt erst beim Stringverarbeiten (Sortieren, Vergleichen etc.) zum Einsatz.

                  c) Einzig die Kodierung der Verbindung zwischen PHP und MySQL hat Einfluss darauf, wie die Daten, die aus der DB ausgelesen werden, (um-)kodiert werden.

                  Sie bestimmt, wie die Daten zwischen Client und Server ausgetauscht werden. Wie MySQL auf die Felder zugreift, ist aus der Sicht des Clients nicht weiter von Belang.

                  d) Die Codierung der Felder hat keinen Einfluss auf die Codierung der Daten, die PHP im Resultset eines (My)SQL-Statements zur Verfügung stehen.

                  Stimmt. (Dass inkompatible Angaben zwischen beiden "Welten" zu Datenverlust beim Umkodieren führen kann, muss ich sicher nicht erwähnen.)

                  e) sind z.B. die Tabellenfelder UTF-8-kodiert stehen sie im Resultset von PHP:mysql_query() in der Form kodiert zur Verfügung, wie die Verbindung zwischen MySQL und PHP kodiert ist.

                  Ja, auch bei jeder beliebigen anderen Feld-Kodierungsangabe ist für den Client lediglich die Verbindungskodierungsangabe relevant.

                  f) die Kodierung der Verbindung legt man mit mysql_set_charset() fest. Ohne diesen Befehl greift ein Default.

                  Ja, damit ist alles perfekt. Wie gesagt ist für ISO-8859-x und UTF-8 auch ein SET NAMES gefahrlos möglich. Die Default-Werte hören in der Server-Konfiguration auf die Namen character_set_client, character_set_connection und character_set_results. Deren Default-Wert ist character-set-server.

                  dedlfix.

        2. @@heinetz:

          nuqneH

          Ansonsten wird, wenn die Information nicht vom Server kommt, das Metatag benutzt, was seinerseits keine Auswirkung hat, wenn im Header etwas anderes steht.

          Du redest wirr. Wenn im HTTP-Header etwas anderes steht, dann kommt die Information vom Server.

          Der Client kann nicht unterscheiden, ob es in der Serverkonfiguration gesetzt ist oder der HTTP-Header mit PHP gesetzt wurde.

          Lesestoff: Angabe der Zeichencodierung in HTML

          Qapla'

          --
          Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
          (Mark Twain)
          1. Stimmt,

            das klingt etwas wirr und ist besser in zwei Sätzen untergebracht.

            1. Wenn die Information nicht vom Server kommt, wird das Metatag benutzt.
            2. Das Metatag hat keine Auswirkung hat, wenn im Header etwas anderes steht.

            Klar, dass das was im Header steht bedingt durch die Konfiguration des Servers oder durch php:header() dort steht.

            gruesse,
            heinetz

    2. Hello,

      Mein (Denk-)Modell

      Ich programmiere eine Website in XHTML. Die besteht aus genau einer Datei index.html, in der lauter ä,ü,ö usw. unmaskiert vorkommen. Jetzt würde ich diese Website gerne als UTF-8 ausliefern(?). Was ist zu tun? Was ich tun würde, wären zwei Dinge:

      a) ich würde index.html mit der Zeichencodierung utf-8 speichern.
      b) ich würde im Code das Metatag:
         <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
         ... einsetzen.
      Das ganze scheint korrekt zu sein. Das schliesse ich daraus, dass ä,ü und ö korrekt dargestellt werden und das Firefox sagt, die Kodierung sei UTF 8.

      ... allerdings nur auf meinem Entwicklungssystem, nicht aber auf dem Server, wo es letztlich laufen soll. Das schiebe ich auf die Information, die ich mit phpinfo() unter "HTTP Response Heiders" / "Content-Type" finde. Hier gibt es m.E. drei Möglichkeiten, das zu überschreiben:

      a) indem man die Konfiguration des Servers direkt ändert (php.ini?)
      b) mit der Direktive AddDefaultCharset in der htaccess (wenn man darf)
      c) mit php : header("Content-Type: text/html; charset=utf-8")

      Für mich kommt bis hierher nur c) in frage und ich benötige also eine index.php statt einer index.html, in die ich c) einsetze.

      Ich halte die dritte Möglichkeit (als Ergänzung) im Übrigen für gar nicht schlecht, weil man damit der Datei bereits ansieht, wie sie behandelt zu werden hat.

      Da die Editoren teilweise selbsttätig die Codierung wechseln für die Anzeige oder, noch viel schlimmer, beim Abspeichern, ist diese Information gleich oben im Kopf der Datei mMn sehr hilfreich. Dann dentk man wenigstens daran, dem gerade verwendeten Editor als erstes das Eigenleben abzugewöhnen.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de