Flury: UTF8 und DBI (mysql)

Hi zusammen,

ich hab mal wieder ne Frage ...

Ich hab empfange via Formular Daten in mein Perlscript (via cgi-modul).
Nun möchte ich diese Daten weiter in die DB laden (via DBI-Modul).
Soweit so gut. Jetzt hab ich mit meinem Zeichensatz "Probleme", also mit den ö, ä, ...
Ich hab gelesen, dass ich die Daten am besten utf8-kodiert in meine DB speichern soll. (Hoffe das stimmt). Nun ist die Frage wie mach ich das am besten?

Meine html-Seite mit Formular hat den meta-tag:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Mein Versuch im script:
$main::dbh->do("set character set utf8");
$main::dbh->do("set names utf8");
my $sql = qq{INSERT INTO x (uid) VALUES (?)};
my $sth = $main::dbh->prepare ($sql) || die "Kann Statement nicht vorbereiten: $DBI::errstr\n";
$sth->execute($par_uid);
$sth->finish;

Aber er speichert mir die Daten dennoch nicht utf-8 kodiert in der DB ab (das seh ich anhand der Darstellung im Browser bei phpmyadmin), sondern als normales öä (hmm vielleicht brauch ich mir da keinen Aufwand machen um das überhaupt zu kodieren, aber ich glaub das wäre eher unschön).

Oder habt ihr mir vielleicht mal ein Beispiel, wie ihr allgemein bei dem Problem perl/dbi/mysql/"Sonderzeichen" in DB schreiben, auslesen und wieder als html darstellen?

Was ich noch dazu sagen muss ist, dass ich meine mysql-db-Grundeinstellungen nicht verändern kann, da es eine gehostete DB ist. Aber ich hab ein paar Tabellen drin (von freeware-php-scripten erzeugt), die daten utf-8 kodiert abgespeichert haben, sprich die DB kann das prinzipiell mit den derzeitigen Einstellungen.

VIELEN DANK schonmal.

ciao,
Flury

  1. Moin Moin!

    Ich hab empfange via Formular Daten in mein Perlscript (via cgi-modul).
    Nun möchte ich diese Daten weiter in die DB laden (via DBI-Modul).
    Soweit so gut. Jetzt hab ich mit meinem Zeichensatz "Probleme", also mit den ö, ä, ...
    Ich hab gelesen, dass ich die Daten am besten utf8-kodiert in meine DB speichern soll. (Hoffe das stimmt).

    Nicht unbedingt. Wenn Du nur Zeichen aus ISO-8859-1 brauchst, reicht auch ISO-8859-1. UTF-8 enthält auch alle Zeichen aus ISO-8859-1, aber eben noch ein paar Tausend mehr.

    UTF-8 nur zu benutzen, weil es "gerade in Mode ist", halte ich für eine schlechte Idee.

    Nun ist die Frage wie mach ich das am besten?

    Nutze Perl 5.8.1 oder neuer. 5.6.x kann mit UTF-8 gar nicht umgehen (außer Du baust das Unicode-Handling komplett selbst), 5.8.0 hat ein paar üble Macken.

    Bring Perl dazu, die Eingaben als UTF-8 zu behandeln; das CGI-Modul macht das leider nicht ganz automatisch, insbesondere die alten Versionen sind völlig ohne UTF-8-Unterstützung. Du wirst kaum darum herumkommen, alle Parameter mit Hilfe des Encode-Moduls von UTF-8-Bytestreams auf "echte" Unicode-Strings umzucodieren. (Bytesteam: Byte==Char, UTF-8-Zeichen belegen 1..6 Zeichen = Bytes; Unicode-String: Byte!=Char, UTF-8-Zeichen belegen exakt ein Zeichen). Siehe auch perluniintro und dort verlinkte Perl-Dokumentation; insbesondere auch utf8::is_utf8().

    Die Unicode-Strings schickst Du durchs DBI-Modul in die Datenbank, je nach Datenbank ist dazu noch etwas Theater nötig. Aus der Datenbank kommen die Strings idealerweise gleich wieder als Unicode heraus, mit einem "binmode(STDOUT,':utf8')" sorgst Du dafür, dass die Unicode-Strings auch direkt nach STDOUT geschrieben werden können, ohne dass Du erneut das Encode-Modul für die Umwandlung von Unicode-Strings auf UTF-8-Bytestreams bemühen mußt.

    Meine html-Seite mit Formular hat den meta-tag:
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    Sinnlos, denn den Content-Type-Header kannst Du direkt per CGI::header() setzen, inklusive Charset. Neuere Versionen von CGI.pm schalten bei einer von vielen Schreibweisen von UTF-8 (utf8/utf-8/UTF8/UTF-8) eine rudimentäre Unicode-Unterstützung ein; siehe Source / Doku.

    Oder habt ihr mir vielleicht mal ein Beispiel, wie ihr allgemein bei dem Problem perl/dbi/mysql/"Sonderzeichen" in DB schreiben, auslesen und wieder als html darstellen?

    Siehe mein Unicode-Patch für DBD::ODBC 1.13, ist zwar überholt, aber durchaus noch lehrreich, insbesondere die neuen Tests in t/*.t. Im README findest Du auch einiges Know-How zu Unicode-Support verschiedener Datenbanken und DBDs.

    (Und nein, bitte diesen Patch NICHT einspielen. Er ist in DBD::ODBC 1.14 und neuer komplett enthalten und funktioniert dort auch auf Nicht-Windows-Systemen!)

    MySQL habe ich bislang immer vermieden, das Ding ist mir zu wenig saubere Datenbank und zu sehr eigenmächtige Müllhalde. Soweit ich mich erinnere, hast Du mit MySQL 3.x in Sachen Unicode echt schlechte Karten, 4 oder 5 sollen besser sein. Der aktuelle DBD::mysql hat ein experimentelles DB-Attribut mysql_enable_utf8, das standardmäßig false ist, analog zu DBD::Pg. Das sollte auf jeden Fall auf true gesetzt werden, bevor Du mit Unicode hantierst.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Hi,

      Ich hab empfange via Formular Daten in mein Perlscript (via cgi-modul).
      Nun möchte ich diese Daten weiter in die DB laden (via DBI-Modul).
      Soweit so gut. Jetzt hab ich mit meinem Zeichensatz "Probleme", also mit den ö, ä, ...
      Ich hab gelesen, dass ich die Daten am besten utf8-kodiert in meine DB speichern soll. (Hoffe das stimmt).

      Nicht unbedingt. Wenn Du nur Zeichen aus ISO-8859-1 brauchst, reicht auch ISO-8859-1. UTF-8 enthält auch alle Zeichen aus ISO-8859-1, aber eben noch ein paar Tausend mehr.

      UTF-8 nur zu benutzen, weil es "gerade in Mode ist", halte ich für eine schlechte Idee.

      okay, d.h. du empfiehlst die Daten quasi ohne umkodierung in die DB zu speichern?
      Die Website ist nicht wirklich für den asiatischen/arabaischen Raum, d.h. ich komme mit den Standardbuchstaben + äöü + evtl. Sonderzeichen wie € eigentlich aus.

      Nun ist die Frage wie mach ich das am besten?

      Nutze Perl 5.8.1 oder neuer. 5.6.x kann mit UTF-8 gar nicht umgehen (außer Du baust das Unicode-Handling komplett selbst), 5.8.0 hat ein paar üble Macken.

      Auf dem Server ist 5.8.8 installiert.

      ciao,
      Flury

  2. Mein Versuch im script:
    $main::dbh->do("set character set utf8");
    $main::dbh->do("set names utf8");

    Das ist wohl unnötig.

    Aber er speichert mir die Daten dennoch nicht utf-8 kodiert in der DB ab (das seh ich anhand der Darstellung im Browser bei phpmyadmin), sondern als normales öä (hmm vielleicht brauch ich mir da keinen Aufwand machen um das überhaupt zu kodieren, aber ich glaub das wäre eher unschön).

    Ich nehme an du meinst mit "normales öä" kein normales öä, ansonsten wäre die Frage was du erwartest?

    Ist die Tabelle auch auf den richtigen Zeichensatz eingestellt?

    Struppi.

    1. Hi,

      Ist die Tabelle auch auf den richtigen Zeichensatz eingestellt?

      ich hab sie ohne spezielle Parameter erzeugt, sprich sowas wie CREATE TABLE t( ... ) CHARACTER SET utf8 COLLATE utf8_general_ci; hab ich nicht gemacht.
      Ich hab die Tabelle via phpmyadmin erstellt (und damit denke ich mit den Standardparametern).

      ciao,
      Flury

      1. Ist die Tabelle auch auf den richtigen Zeichensatz eingestellt?

        ich hab sie ohne spezielle Parameter erzeugt, sprich sowas wie CREATE TABLE t( ... ) CHARACTER SET utf8 COLLATE utf8_general_ci; hab ich nicht gemacht.
        Ich hab die Tabelle via phpmyadmin erstellt (und damit denke ich mit den Standardparametern).

        und phpmyadmin sagt dir nicht mit welchen Zeichensatz das ist?

        Struppi.

        1. Hi,

          und phpmyadmin sagt dir nicht mit welchen Zeichensatz das ist?

          leider Nein ;( - da ich das bei einem Webhoster habe ist das irgendwie abgespeckt. Ich kann z.B. auch keine neue DB generieren.

          ciao,
          Flury

          1. und phpmyadmin sagt dir nicht mit welchen Zeichensatz das ist?

            leider Nein ;( - da ich das bei einem Webhoster habe ist das irgendwie abgespeckt. Ich kann z.B. auch keine neue DB generieren.

            Ich weiß ja nicht wie abgespeckt das ist, aber bei mir steht diese Info mehrfach irgendwo, z.b. auch in der Übersicht (Struktur)

            Struppi.

            1. Hi,

              Ich weiß ja nicht wie abgespeckt das ist, aber bei mir steht diese Info mehrfach irgendwo, z.b. auch in der Übersicht (Struktur)

              ich hab bei einem Bekannten gesehen, dass es bei ihm auch dransteht, aber wie gesagt bei mir leider nicht (und ich wüsste auch nicht, ob und wie diese Ansicht zu aktivieren wäre).

              ciao,
              Flury

  3. Moin!

    Ich hab gelesen, dass ich die Daten am besten utf8-kodiert in meine DB speichern soll. (Hoffe das stimmt). Nun ist die Frage wie mach ich das am besten?

    Die Verwendung von UTF-8 in allen Bereichen, in denen Zeichen vorkommen, ist definitiv eine sehr gute Idee. Ich kann da Alexanders unspezifizierte Kritik nicht nachvollziehen. Mit UTF-8 macht man sich das Leben sehr viel einfacher.

    Meine html-Seite mit Formular hat den meta-tag:
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    Das reicht unter Umständen nicht allein aus, sollte dein Server einen anderslautenden HTTP-Header senden, würde dieser Vorrang haben. Aber es ist ein Anfang.

    Mein Versuch im script:
    $main::dbh->do("set character set utf8");
    $main::dbh->do("set names utf8");
    my $sql = qq{INSERT INTO x (uid) VALUES (?)};
    my $sth = $main::dbh->prepare ($sql) || die "Kann Statement nicht vorbereiten: $DBI::errstr\n";
    $sth->execute($par_uid);
    $sth->finish;

    Sieht alles bestens aus.

    Aber er speichert mir die Daten dennoch nicht utf-8 kodiert in der DB ab (das seh ich anhand der Darstellung im Browser bei phpmyadmin), sondern als normales öä (hmm vielleicht brauch ich mir da keinen Aufwand machen um das überhaupt zu kodieren, aber ich glaub das wäre eher unschön).

    Was genau siehst du? PHPMyAdmin soll dir selbstverständlich Umlaute anzeigen, wenn Umlaute gespeichert sind. Diese "Ersatzdarstellung" mit A-Tilde-Knörks ist eine Fehldarstellung, wenn UTF-8-Bytes fälschlich als ISO-8859-1-Zeichen interpretiert werden. PHPMyAdmin macht diesen Fehler eben nicht.

    Da die Datenbank aber ohnehin eine Blackbox ist und du nicht wirklich an die darin gespeicherten Bytes rankommst (wozu auch), beschränke deine Betrachtung doch einfach auf das, was sich innerhalb von Perl abspielt. Wenn dort die korrekten Bytes im String stecken, ist alles bestens.

    Oder habt ihr mir vielleicht mal ein Beispiel, wie ihr allgemein bei dem Problem perl/dbi/mysql/"Sonderzeichen" in DB schreiben, auslesen und wieder als html darstellen?

    Das schöne an UTF-8 ist, dass es sehr pflegeleicht handhabbar auch dort ist, wo "nur" ISO-8859-1-Speicherplatz zur Verfügung steht. Aber im Grunde mußt du nichts anders machen: Die Verbindung zur Datenbank hast du schon auf UTF-8-Codierung gesetzt (das ist der Hauptfehler sonst), die Meta-Elemente der HTML-Seiten existieren auch. Die Datenbank-Textfelder sollten ebenfalls auf UTF-8 mit passender Kollation (Sortiervorschrift) gesetzt werden, das falsch zu machen hat aber erstmal keine unmittelbar negativen Auswirkungen, sondern höchstens subtile, sollten Zeichen zu speichern sein, die mit der abweichenden Codierung nicht darstellbar sind.

    - Sven Rautenberg

    --
    "Love your nation - respect the others."