Daniel: Zeichencodierung ändern

problematische Seite

Hallo,

ich bin immer noch beim Relaunch der o.g. Seite, dabei möchte ich u.a. die Codierung der Seite und Datenbank ändern, von Latin1/ISO-8859-1 zu UTF8. Da sich einiges an der Datenstruktur ändert, lese ich die aktuelle Datenbank ein und schreibe die geänderten Daten in eine neue Datenbank. Die relevanten Zeilen:

$dsn_alt = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=latin1';
$dsn_neu = 'mysql:host=' . DB_HOST . ';dbname=drarbeit;charset=utf8mb4';

$db_alt = new PDO($dsn_alt, DB_USER, DB_PASS, $opt);
$db_neu = new PDO($dsn_neu, DB_USER, DB_PASS, $opt);

$value = mb_convert_encoding($value, "UTF-8", "ISO-8859-1");

Leider werden nicht alle Zeichen korrekt umgewandelt und ich finde das Problem nicht. Ein Beispiel (Absatz "Beschreibung"):

Aktuelles Angebot: http://drarbeit.de/drarbeit/php/arch_get.php?angebot=nr14680

Nach Umwandlung: http://drarbeit.de/test.html

Ich vermute, dass viele Nutzer ihren Text einfach aus Word per copy&paste einfügen, dabei werden diese Aufzählungszeichen mitgenommen.

Hat jemand eine Idee, warum die nicht richtig umgewandelt werden bzw. wie ich das hinbekomme?

Viele Grüße Daniel

  1. problematische Seite

    Hallo Daniel,

    ich bin immer noch beim Relaunch der o.g. Seite, dabei möchte ich u.a. die Codierung der Seite und Datenbank ändern, von Latin1/ISO-8859-1 zu UTF8.

    das ewige Mysterium Zeichencodierung. 😉

    $dsn_alt = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=latin1';
    $dsn_neu = 'mysql:host=' . DB_HOST . ';dbname=drarbeit;charset=utf8mb4';
    
    $db_alt = new PDO($dsn_alt, DB_USER, DB_PASS, $opt);
    $db_neu = new PDO($dsn_neu, DB_USER, DB_PASS, $opt);
    
    $value = mb_convert_encoding($value, "UTF-8", "ISO-8859-1");
    

    Das sieht im Prinzip richtig aus. Abgesehen davon, dass $value nirgends definiert wird. Das eigentliche Lesen aus der Datenbank hast du hier wohl weggelassen.

    Leider werden nicht alle Zeichen korrekt umgewandelt und ich finde das Problem nicht. Ein Beispiel (Absatz "Beschreibung"):

    Aktuelles Angebot: http://drarbeit.de/drarbeit/php/arch_get.php?angebot=nr14680

    Diese Seite kommt in Windows-1252 daher, nicht ISO-8859-1.

    Nach Umwandlung: http://drarbeit.de/test.html

    Hmm. Die Bullets werden zu Fragezeichen, also dem Ersatzzeicehn für "ungültig". Die verwendeten Bullets haben in Windows-1252 den Code 0x95. In ISO-8859-x ist aber der Bereich 0x80..0x9F nicht definiert. Deswegen setzt mb_convert_encoding() hier zu Recht ein "invalid character".

    Ich vermute, dass viele Nutzer ihren Text einfach aus Word per copy&paste einfügen, dabei werden diese Aufzählungszeichen mitgenommen.

    Hat jemand eine Idee, warum die nicht richtig umgewandelt werden bzw. wie ich das hinbekomme?

    Vermutlich würde es schon helfen, wenn du die Quell-Codierung korrekt als Windows-1252 angeben würdest.

    Einen schönen Tag noch
     Martin

    --
    Prostituierte zum Stammgast: Schön, dass du mal wieder gekommen bist.
    1. problematische Seite

      Hallo Der,

      Vermutlich würde es schon helfen, wenn du die Quell-Codierung korrekt als
      Windows-1252 angeben würdest.

      (Markierung als Code von mir)

      Was tatsächlich ein gültiger Encoding-Name für mb_convert_encoding ist.

      Rolf

      --
      sumpsi - posui - obstruxi
    2. problematische Seite

      Hallo Martin,

      Danke für Deine Hinweise!

      Das sieht im Prinzip richtig aus. Abgesehen davon, dass $value nirgends definiert wird. Das eigentliche Lesen aus der Datenbank hast du hier wohl weggelassen.

      Ja, korrekt, weil da nichts Codierungs-relevantes passiert.

      http://drarbeit.de/drarbeit/php/arch_get.php?angebot=nr14680

      Diese Seite kommt in Windows-1252 daher, nicht ISO-8859-1.

      Interessant, woran erkennst Du das? Im header steht

      <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

      und auch die Datenbank ist mit latin1_swedish_ci eingestellt (bitte frag nicht, warum swedish, ich habe keine Ahnung mehr, was ich mir vor 20 Jahren dabei gedacht habe...)

      Hmm. Die Bullets werden zu Fragezeichen, also dem Ersatzzeicehn für "ungültig". Die verwendeten Bullets haben in Windows-1252 den Code 0x95. In ISO-8859-x ist aber der Bereich 0x80..0x9F nicht definiert. Deswegen setzt mb_convert_encoding() hier zu Recht ein "invalid character".

      Vermutlich würde es schon helfen, wenn du die Quell-Codierung korrekt als Windows-1252 angeben würdest.

      Ich habe es versucht mit

      $value = mb_convert_encoding($value, "UTF-8", "Windows-1252");

      aber es bleibt bei den Fragezeichen statt Bullets.

      Was könnte ich noch versuchen?

      1. problematische Seite

        Hi,

        http://drarbeit.de/drarbeit/php/arch_get.php?angebot=nr14680

        Diese Seite kommt in Windows-1252 daher, nicht ISO-8859-1.

        Interessant, woran erkennst Du das? Im header steht

        an der Existenz des Bullets (CP1252, Zeichen x95 - in den Iso-Codierungen ist der Bereich [x80-xA0[ leer, in CP1252 gefüllt).

        Außerhalb des genannten Bereichs ist CP1252 identisch mit ISO-8859-1 …

        cu,
        Andreas a/k/a MudGuard

      2. problematische Seite

        Hallo,

        http://drarbeit.de/drarbeit/php/arch_get.php?angebot=nr14680

        Diese Seite kommt in Windows-1252 daher, nicht ISO-8859-1.

        Interessant, woran erkennst Du das?

        in den Seiteninformationen, die mir der Browser verrät (im Firefox z.B. Tools/Page Info):

        Screenshot Firefox (cropped)

        Im header steht

        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

        Das kommt aber nicht zum Tragen, weil der korrespondierende HTTP-Header, den der Server sendet, Vorrang hat.

        Vermutlich würde es schon helfen, wenn du die Quell-Codierung korrekt als Windows-1252 angeben würdest.

        Ich habe es versucht mit

        $value = mb_convert_encoding($value, "UTF-8", "Windows-1252");

        aber es bleibt bei den Fragezeichen statt Bullets.

        Schade. Genau so hatte ich es gemeint. Dann bin ich im Moment ratlos, und wir müssten tiefer ins Detail gehen. Gehen diese Zeichen eventuell schon beim Eintragen in die DB kaputt?

        Einen schönen Tag noch
         Martin

        --
        Prostituierte zum Stammgast: Schön, dass du mal wieder gekommen bist.
        1. problematische Seite

          Schade. Genau so hatte ich es gemeint. Dann bin ich im Moment ratlos, und wir müssten tiefer ins Detail gehen. Gehen diese Zeichen eventuell schon beim Eintragen in die DB kaputt?

          Nein, aber irgendwo anders. Danke für Deine Nachfrage, ich habe gerade nochmal rumprobiert und rätsele:

          Wenn ich in die Datenbank schaue (sowohl online als auch im lokalen Backup), werden die Zeichen richtig angezeigt. Auf der Seite online funktioniert es offensichtlich auch. Wenn ich die Daten aber lokal auslese und einfach nur (mit <meta charset="iso-8859-1">) ausgebe (per echo), erscheinen schon die Fragezeichen.

          Heute habe ich keine Zeit mehr, aber ich denke, ich werde demnächst mal versuchen, in der Original-Datenbank (lokales Backup) per phpMyAdmin oder HeidiSQL die Zeichenkodierung/Kollation zu ändern, bevor ich die Daten auslese und umschreibe. Vielleicht funktioniert das besser. Wobei, verstehen würde ich schon gerne, wo das Problem gerade liegt...

          Viele Grüße Daniel

          1. problematische Seite

            Hallo

            Heute habe ich keine Zeit mehr, aber ich denke, ich werde demnächst mal versuchen, in der Original-Datenbank (lokales Backup) per phpMyAdmin oder HeidiSQL die Zeichenkodierung/Kollation zu ändern, bevor ich die Daten auslese und umschreibe.

            Es ist nicht nur Charset und Kollation (letzteres ist nur für die alphabetische Sortierung zuständig, hier also nicht kriegsentscheidend), es ist auch der Charset der Datenbankverbindung, mit der du von einem Programm/Skript Daten lesen und schreiben lässt. Dafür gibt es in PHP spezielle Funktionen. In der MySQLi-Bibliothek ist das mysqli_set_charset beziehungsweise ihr OO-Pendant. Damit kannst du dann auch ISO-8859-1(5)-codierte Daten auslesen und von der DB-Engine automatisch in UTF-8 ausgeben lassen, wenn du genau diesen Charset für die Verbindung festlegst.

            Bei MySQL ist noch wichtig, dass es die Charsets utf8 und utf8mb4 gibt. Der erste kann 3-Byte-Zeichen verwalten, der zweite auch 4-Byte-Zeichen, was dann zum Beispiel Emojis beinhaltet.

            Dazu gehört aber auch, dass Skripte im selben Charset gespeichert und in diesem Charset vom Webserver ausgeliefert werden. Ebenfalls gehört dazu, dass der Webserver diesen Charset im Header ansagt, damit der Browser weiß, welchen Charset er bei der Ausgabe zu benutzen hat.

            Tschö, Auge

            --
            200 ist das neue 35.
            1. problematische Seite

              Es ist nicht nur Charset und Kollation (letzteres ist nur für die alphabetische Sortierung zuständig, hier also nicht kriegsentscheidend), es ist auch der Charset der Datenbankverbindung, mit der du von einem Programm/Skript Daten lesen und schreiben lässt. Dafür gibt es in PHP spezielle Funktionen. In der MySQLi-Bibliothek ist das mysqli_set_charset beziehungsweise ihr OO-Pendant. Damit kannst du dann auch ISO-8859-1(5)-codierte Daten auslesen und von der DB-Engine automatisch in UTF-8 ausgeben lassen, wenn du genau diesen Charset für die Verbindung festlegst.

              Okay, das klingt interessant. Ich arbeite mir PDO, da habe ich allerdings keine entsprechende Funktion gefunden. Ist das nicht dasselbe wie ich im dsn übergebe?

              Dazu gehört aber auch, dass Skripte im selben Charset gespeichert und in diesem Charset vom Webserver ausgeliefert werden. Ebenfalls gehört dazu, dass der Webserver diesen Charset im Header ansagt, damit der Browser weiß, welchen Charset er bei der Ausgabe zu benutzen hat.

              Woher weiß ich, wie Skripte auf meinem PC oder auf dem Webserver gespeichert werden? Und wie kann ich beeinflussen, was der Webserver im Header ansagt?

              Viele Grüße Daniel

              1. problematische Seite

                Servus!

                Woher weiß ich, wie Skripte auf meinem PC oder auf dem Webserver gespeichert werden? Und wie kann ich beeinflussen, was der Webserver im Header ansagt?

                Der Artikel ist grad aus mehreren zusammenkopiert worden und zeigt daher zwei Ansätze - erstmal von der Dokumentspeicherung bis hin zum Hosting und dann nochmal ausgehend vom Verhalten des Browsers, der erst nen Header sucht, dann im Dokument den meta-Tag sucht und dann vermutet, in welchem Format das Dokument vermutlich gespeichert worden ist:

                Zeichencodierung/Unicode_in_der_Praxis

                Herzliche Grüße

                Matthias Scharwies

                --
                Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
                1. problematische Seite

                  Zeichencodierung/Unicode_in_der_Praxis

                  Danke, sehr gute Zusammmenfassung! Habe ich mit Interesse durchgelesen.

                  Gruß

                  Daniel

              2. problematische Seite

                Hallo Daniel,

                Woher weiß ich, wie Skripte auf meinem PC oder auf dem Webserver gespeichert werden?

                das hast du selbst in der Hand: Beim Erzeugen oder Bearbeiten oder Speichern einer Textdatei (und nichts anderes ist ein Script im Prinzip) musst du die Zeichencodierung festlegen - oder der Editor tut das für dich und benutzt einen Defaultwert. Das ist oft noch ISO-8859-x oder Windows-1252, aber die bessere Wahl ist heutzutage UTF-8.

                Und wie kann ich beeinflussen, was der Webserver im Header ansagt?

                Das ist nicht ganz so trivial. Und auf die Schnelle finde ich auch den passenden Artikel im Wiki nicht. Aber du kannst entweder eine .htaccess-Datei anlegen und darin die festlegen, welche Codierung der Webserver angeben soll (AFAIR ist die richtige Direktive AddDefaultCharset). Oder, wenn du sowieso PHP verwendest, kannst du mit der Funktion header() den HTTP-Header "Content-Type: text/html; charset=utf-8" senden.

                Einen schönen Tag noch
                 Martin

                --
                Motto der DIY-Anhänger: If it ain't broken, fix it until it is.
                1. problematische Seite

                  @@Der Martin

                  aber die bessere Wahl ist heutzutage UTF-8.

                  Ich würde sagen: die einzig vernünftige Wahl.

                  Und wie kann ich beeinflussen, was der Webserver im Header ansagt?

                  Das ist nicht ganz so trivial. Und auf die Schnelle finde ich auch den passenden Artikel im Wiki nicht.

                  Einstellung des HTTP-charset-Parameters (Wozu macht man sich denn die Arbeit?)

                  Und dann ist da noch Einstellung des HTTP-charset-Parameters.

                  (AFAIR ist die richtige Direktive AddDefaultCharset).

                  Ja, AddDefaultCharset gibt’s auch.

                  Oder, wenn du sowieso PHP verwendest, kannst du mit der Funktion header() den HTTP-Header "Content-Type: text/html; charset=utf-8" senden.

                  Das halte ich für gar keine gute Idee, PHP anstatt der Serverkonfiguration für Dinge der Serverkonfiguration zu verwenden.

                  🖖 Живіть довго і процвітайте

                  --
                  When the power of love overcomes the love of power the world will know peace.
                  — Jimi Hendrix
                  1. problematische Seite

                    Das halte ich für gar keine gute Idee, PHP anstatt der Serverkonfiguration für Dinge der Serverkonfiguration zu verwenden.

                    Das kann durchaus sinnvoll sein. Nur die jeweils verwendete Architektur weiß im Zweifel, welcher Content-Type passt. Beispielsweise bei der Ausgabe eines PDF-Dokuments durch ein PHP-Script.

                2. problematische Seite

                  Danke, war mir bisher so nicht klar.

                  Komischerweise funktioniert mein Skript auf dem Server (richtige Kodierung), aber lokal (XAMPP) nicht, obwohl - soweit ich das überprüfen konnte - alles jetzt UTF-kodiert ist.

                  Aber auf dem Server ist für mich das entscheidende, daher beende ich jetzt mal meine Fehlersuche...

                  Danke für Eure vielen Hinweise, Tipps und Erklärungen!

                  Gruß

                  Daniel

      3. problematische Seite

        Hallo

        und auch die Datenbank ist mit latin1_swedish_ci eingestellt (bitte frag nicht, warum swedish, ich habe keine Ahnung mehr, was ich mir vor 20 Jahren dabei gedacht habe...)

        Ich wage zu behaupten: nichts.

        Du hast dir nichts dabei gedacht, weil das einstmals die Voreinstellung von MySQL beim erstellen von Servern war, was sich dann, wenn nichts anderes konfiguriert war, von Datenbanken über Tabellen zu Tabellenspalten durchgezogen hat. Damals hatten weder die Hoster, die im Normalfall als einzige die Grundkonfiguration eines MySQL-Servers beeinflussen konnten, noch die Hostingkunden und auch die meisten Entwickler das Bewusstsein dafür, dass das problematisch war und einem später auf die Füße fallen wird.

        Du hast damals höchstwahrscheinlich die Datenbank schlicht mit den Defaulteinstellungen des MySQL-Servers entworfen. Da kam damals halt latin1_swedish_ci raus.

        Tschö, Auge

        --
        200 ist das neue 35.
        1. problematische Seite

          Hallo

          und auch die Datenbank ist mit latin1_swedish_ci eingestellt (bitte frag nicht, warum swedish, ich habe keine Ahnung mehr, was ich mir vor 20 Jahren dabei gedacht habe...)

          Ich wage zu behaupten: nichts.

          Du hast dir nichts dabei gedacht, weil das einstmals die Voreinstellung von MySQL beim erstellen von Servern war, was sich dann, wenn nichts anderes konfiguriert war, von Datenbanken über Tabellen zu Tabellenspalten durchgezogen hat. Damals hatten weder die Hoster, die im Normalfall als einzige die Grundkonfiguration eines MySQL-Servers beeinflussen konnten, noch die Hostingkunden und auch die meisten Entwickler das Bewusstsein dafür, dass das problematisch war und einem später auf die Füße fallen wird.

          Du hast damals höchstwahrscheinlich die Datenbank schlicht mit den Defaulteinstellungen des MySQL-Servers entworfen. Da kam damals halt latin1_swedish_ci raus.

          Genau, Danke, jetzt erinnere ich mich auch wieder: Nichts 😉