Charset/Encoding für eine Webanwendung ändern

Debian macht sich hervorragend als Web- und Mailserver. Schau auch in den " Tipps und Tricks"-Bereich.
Antworten
Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Charset/Encoding für eine Webanwendung ändern

Beitrag von heisenberg » 20.02.2024 13:28:05

Hallo zusammen,

ich habe ein Problem, dass mir insgesamt recht komplex zu sein scheint. Ich kann es zumindest selbst nicht komplett erfassen. Es geht darum, das aktuell Fehler in der Behandlung von Umlauten bestehen und ich diese Fehler beheben möchte. Fehler ist z. B. dass ich ein XWiki (Wiki auf JAVA-Basis) habe. Wenn ich im XWiki die Historie benutze, dann sind die Umlaute in den damit wiederhergestellten Seiten zerstört. D. h. die Anzeige zeigt nicht die Umlaute sondern Zeichenmüll mit mehreren Zeichen Länge.

Insgesamt sind da mehrere Komponenten mit im Spiel:
  1. Das Betriebssystem (Ubuntu 20.04)
  2. Ein Webserver (auf dem Host-OS)
  3. Ein Tomcat-Docker-Container ( Tomcat 8/Java-Anwendung)
  4. Ein MySQL-Docker-Container ( mysql 5.7 )
  5. Andere Anwendungen die als weitere Docker-Container über den Webserver auf dem Host-OS angebunden sind.
Tomcat 8 ist alt/EOL. Ist mir bewusst. MySQL 5.7 ist alt/EOL. Ist mir bewusst. Wer nichts anderes als den Hinweis darauf zu schreiben hat, darf sich gerne hier raushalten.

Meine Fragen sind für mich:
  1. Wenn ich jetzt am Apache Encoding-Einstellungen ändere (z. B. AddDefaultCharset utf8 setzen), muss ich vermutlich jede Anwendung prüfen, bzw. anpassen und deren Daten konvertieren? Wenn ich das nicht tue, gibt's in allen Anwendungen vermutlich den Datensupergau? Das ist das kritische an der Geschichte. D. h. die Auswirkung auf die anderen Anwendungen.
  2. Was muss ich alles tun, um eine Anwendung umzustellen?
Die Einstellungen der Komponenten:
  1. Das Betriebssystem

    Das Betriebssystem hat diese Einstellungen:

    Code: Alles auswählen

    # locale
    
    LANG=en_US.UTF-8
    LANGUAGE=
    LC_CTYPE="en_US.UTF-8"
    LC_NUMERIC="en_US.UTF-8"
    LC_TIME="en_US.UTF-8"
    LC_COLLATE="en_US.UTF-8"
    LC_MONETARY="en_US.UTF-8"
    LC_MESSAGES="en_US.UTF-8"
    LC_PAPER="en_US.UTF-8"
    LC_NAME="en_US.UTF-8"
    LC_ADDRESS="en_US.UTF-8"
    LC_TELEPHONE="en_US.UTF-8"
    LC_MEASUREMENT="en_US.UTF-8"
    LC_IDENTIFICATION="en_US.UTF-8"
    LC_ALL=
    
    Das müsste also vermutlich auf de_DE.UTF-8 (-> /etc/defaults/locale)? (/etc/locale.gen hat de_DE.UTF-8 aktiviert)
  2. Der Webserver (apache): Keine Einstellung gesetzt.

    Vermutlich AddDefaultCharset utf8 aktivieren?
  3. Anwendungsserver (Tomcat 8/Docker)

    Code: Alles auswählen

    # Im docker container (verm. vom OS übenrommen)
    # set |grep -E "(LANG|LC)"
    LANG=en_US.UTF-8
    LANGUAGE=en_US:en
    LC_ALL=en_US.UTF-8
    
    Änderungen vom Host-OS werden vermutlich übernommen. Ansonsten ist die Default-Einstellung ab Tomcat 8 auch UTF-8. Das sollte also passen.
  4. Mysql (v5.7, docker)

    Code: Alles auswählen

    SELECT default_character_set_name FROM information_schema.SCHEMATA  WHERE schema_name = "xwikistable";
    +----------------------------+
    | default_character_set_name |
    +----------------------------+
    | latin1                     |
    +----------------------------+
    
    Da müsste ich dann vermutlich die Daten konvertieren und zusätzlich das Charset auf etwas passendes setzen (utf8mb4?)? (Andere Anwendungen auf dem gleichen Server verwenden in Ihrer Datenbank auch latin1 als character set).
  5. Die Anwendung selbst auf UTF8 konfigurieren.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Charset/Encoding für eine Webanwendung ändern

Beitrag von heisenberg » 20.02.2024 17:38:00

Ich habe jetzt mal ein Testsetup gemacht und das wiki dorthin geklont und anschließend diese Anleitung hier befolgt:

https://medium.com/@jesseproudman/getti ... 31e75383db

Das ist im Wesentlichen:
  • Umgebung komplett auf UTF-8 umstellen
  • mysql-Tabellen dumpen (=latin1 kodierung)
  • das Characterset in den Dumps auf UTF-8 umstellen
  • die Dumps erneut importieren (mysql soll dabei erkennen, dass die Daten nicht UTF-8 sind und konvertiert auf Verdacht mal von latin1 nach UTF-8)
Mehrfach gelesen und mehrfach neu angefangen. Ergebnis: Wiki-Inhalte sind danach total im Eimer.

Das habe ich hier auch noch gefunden, das auf dem ersten basiert. Damit hatte ich mehr Erfolg. Das werde ich mir jetzt nochmal genauer anschauen:

https://gist.github.com/mdemblani/34d30 ... 9b88be143a
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Benutzeravatar
oln
Beiträge: 487
Registriert: 05.01.2021 09:41:24

Re: Charset/Encoding für eine Webanwendung ändern

Beitrag von oln » 21.02.2024 08:03:51

Moin,
also nach deiner Umstellung würde ich mir mal die Daten im phpmyadmin ansehen. Da kannst du dann im Browser den Charset umstellen. Wenn du dort zu einem vernünftigen Ergebnis kommst, dann ist es der Connectionstring von deiner Java-Anwendung. Dort kannst du dann den Charset mitgeben, den du im Browser gewählt hast.

Evtl. noch dem Apache im Charset mitgeben.
Gruß Ole
AbuseIPDB

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Charset/Encoding für eine Webanwendung ändern

Beitrag von heisenberg » 21.02.2024 13:15:38

Bzgl. der Webserver-Charset-Geschichte: Ich muss beim Apachen ja nicht AddDefaultCharset setzen, sondern kann das ja nur für einen VirtualHost tun. Dann sind andere Virtualhosts nicht betroffen.

Ansonsten hat die komplette Konvertierung bisher nicht funktioniert. Wenn ich Seiten aus der Beitragshistorie von XWiki hole, bearbeite und wieder abspeichere, dann sind die Umlaute zerstört. Vermutlich könnte man das auch noch fixen. Das bräuchte aber vermutlich noch einige Stunden mehr.

Was aber funktioniert ist, wenn ich das Encoding in MySQL ändere, die Seiten dann bearbeite und dann abspeichere. Wenn ich diese Daten aus der Beitragshistorie hole, dann werden die sauber angezeigt. D. h. ich werde die komplette Historie aller Beiträge einmal löschen - dann ist die halt weg und ab da kann man wieder fehlerfrei mit der ab dann neu erzeugten Historie arbeiten. Das geht bei XWiki so, dass wenn ich die Top-Level-Page des Wikis inklusive aller Unterseiten ohne die Historie exportiere und dann wieder importiere - und dabei alle Seiten überschreiben lasse.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Charset/Encoding für eine Webanwendung ändern

Beitrag von heisenberg » 24.02.2024 00:34:15

Ich habe das jetzt wie ungefähr angedacht durchgeführt.

Im Einzelnen:
  • Alles gesichert
  • Apache: In den relevanten Virtualhosts das UseDefaultCharSet utf8 gesetzt.
  • Im MySQL in der Main-Config gesetzt:

    Code: Alles auswählen

    [mysqld]
    character_set_server=utf8mb4
    collation_server=utf8mb4_unicode_ci
    
    [client]
    default-character-set = utf8mb4
    
    [mysql]
    default-character-set = utf8mb4
    
  • Die Variablen im Anwendungscontainer sind noch auf:

    Code: Alles auswählen

    LANG=en_US.UTF-8
    LANGUAGE=en_US:en
    LC_ALL=en_US.UTF-8
    
  • im mysql die Datenbank umgestellt:

    Code: Alles auswählen

    ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
  • Anschließend Anwendung und DB neu gestartet.
  • Jetzt noch alle Tabellen umgestellt

    Code: Alles auswählen

    for t in $(mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" \
        -D "$MYSQL_DATABASE" -B -e "show tables" |grep -v "Tables_in_");do 
    
        echo $t
        mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -D "$MYSQL_DATABASE" -B \
           -e "SET FOREIGN_KEY_CHECKS = 0;ALTER TABLE $t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
        
    done
    Die FOREIGN_KEY_CHECKS konnte ich ausstellen, weil ich anschließend sowieso alle Wiki-Seiten per Backup eingespielt habe. Wenn nicht müsste man dann zwingend tatsächlich die Daten konvertieren. Sonst würde vermutlich gar nix mehr funktionieren, weil die Keys nicht mehr zusammen passen.
  • Ich hatte hier noch ein paar Fehler, dass die Felder zu groß würden. (UTF8 braucht mehr Platz als latin1). Deswegen habe ich auf grob per Daumenpeilung ein paar Tabellenfelder angepasst. Das war die Fehlermeldung:

    Code: Alles auswählen

    ERROR 1071 (42000) at line 1: Specified key was too long; max key length is 3072 bytes
    Die betreffenden Tabellen habe ich mir DESCRIBE tablename; angeschaut. Da waren insgesamt 3 Tabellen mit varchar(768) Feldelementen drin. Die habe ich reduziert auf varchar(512), per:

    Code: Alles auswählen

    alter table xwikirecyclebin modify column XDD_FULLNAME varchar(512);
    Mal hoffen dass das passt. Anschließend habe ich das Tabellen-Encoding-Script von oben noch mal drüber laufen lassen. Hat dann komplett funktioniert. Hier macht ein mehrmaliges aufrufen nix aus, weil ja nicht die Daten konvertiert werden, sondern nur die Encoding-Einstellungen gesetzt werden.
  • geprüft ob alle Einstellungen im Mysql jetzt auf utf8 stehen:

    Code: Alles auswählen

    mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
    +--------------------------+--------------------+
    | Variable_name            | Value              |
    +--------------------------+--------------------+
    | character_set_client     | utf8mb4            |
    | character_set_connection | utf8mb4            |
    | character_set_database   | utf8               |
    | character_set_filesystem | binary             |
    | character_set_results    | utf8mb4            |
    | character_set_server     | utf8mb4            |
    | character_set_system     | utf8               |
    | collation_connection     | utf8mb4_general_ci |
    | collation_database       | utf8_general_ci    |
    | collation_server         | utf8mb4_unicode_ci |
    +--------------------------+--------------------+
    10 rows in set (0.00 sec)
    
  • In der XWiki-Administration gab es auch nochmal einen Punkt. Mysql-Encoding prüfen. Die waren dann auch nach einem Neustart immer noch auf latin1. Dann habe ich nochmal durchgestartet und dann hat es gepasst.
  • Anschließend habe ich nochmal einen mysqldump gemacht, um zu sehen ob noch irgendwo "latin1" dort auftaucht. Die einzelnen Felder könnten selbst nochmal eine Encoding-Definition haben. Das war nicht der Fall.
  • Alle Wikiseiten via Import aus eingespielt (alles überschrieben mit history reset).
  • Anschließend noch das Wiki durchgeschaut und etwas mit der History hin- und hergespielt. Klappt alles.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Charset/Encoding für eine Webanwendung ändern

Beitrag von heisenberg » 24.02.2024 00:54:58

Bzgl. der Meldung, dass die varchar(768) Felder mit utf8 zu lang wären: Das wundert mich. Die maximale Keylänge war 3072 Bytes.

UTF-8 hat bis zu 4 Bytes pro Zeichen. 768 * 4 = 3072. Das ist genau die Länge der kritischen Felder gewesen.

Tatsächlich konnte ich jetzt einige Felder wieder zurück auf varchar(768) stellen. Bei einem ging aber nur varchar(764), bei einem Anderen nur varchar(761).
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Antworten