Sven: Zeichen-Wirr-Warr

Hallo!

Ich arbeite an einer Intranet-Seite und habe gehörige Probleme mit einigen wenigen Sonderzeichen (z.B. Gedankenstrich - auf 150 bei Latin1, typografische Anführungszeichen - z.B. auf 147 bei Latin 1).

Die meisten Sonderzeichen (Umlaute usw.) machen allerdings überhaupt kein Problem.

Im Browser wird per JavaScript ein HTTP-Request (POST) erzeugt und die Daten gehen an den Server (also nicht über ein Formular!). Zuvor werden Sie per escape() in Form gebracht. Hatte an dieser Stelle zuvor schon encodeURIComponent(), aber dann gehen nicht einmal die Umlaute.

Jedenfalls greift ein Perl-Skript auf die Daten über das CGI-Objekt zu und speichert sie in einer mySQL-Tabelle.

Für den Gedankenstrich landet E2 80 93 hexadezimal in der DB. Die escape-Methode wandelt ihn in %u2013 vor dem Versenden um, aber das macht keinen Unterschied zu encodeURIComponent, weil dort wird es gleich als %E2%80%93 maskiert. In der Datenbank landen jedenfalls immer die entsprechenden Zeichen (in Latin1 –).

Bei Umlauten hatte ich wie gesagt mit encodeURIComponent Probleme. Ö wird vor dem Versenden als %C3%96 maskiert (ich nehme an UTF16?) und so landen 2 Byte in der DB - entsprechend wird daraus 'Ö'. Mit escape() wird es als %D6 kodiert, was hexadezimal eben Ö in Latin1 ist.

Mein Verdacht: Kann es sein, dass das CGI-Objekt hier diese wie auch immer anders gearteten und maskierten Zeichen nicht korrekt zurückumwandelt?
Jedenfalls protokolliere ich alle Schreibzugriffe in die Tabelle und wenn ich das Logfile öffne (Midnight-Commander) sind die Zeichen im UPDATE-Query korrekt.
Immerhin ist es auch SUSE 9.1, wo meines Wissens im System defaultmäßig UTF8 zum Einsatz kommt.

Ich blick da irgendwie nicht durch.

danke für Hinweise
Sven

  1. hi,

    Im Browser wird per JavaScript ein HTTP-Request (POST) erzeugt und die Daten gehen an den Server (also nicht über ein Formular!).

    interessant.
    wie macht man POST per javascript ohne formular?

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. Hallo wahsaga!

      interessant.

      in der Tat!

      wie macht man POST per javascript ohne formular?

      so zumindest im IE:
      var request = new ActiveXObject("Msxml2.XMLHTTP");
      request.open( "POST", url, false );
      request.send( body );

      body ist dabei formulartypisch id=205&value=%20Abstand%20

      Geht in Mozilla-Browsern auch. Syntax habe ich jetzt nicht griffbereit, weil im Intranet eben IE gebraucht wird.

      gruß
      Sven

      1. hi,

        so zumindest im IE:
        var request = new ActiveXObject("Msxml2.XMLHTTP");

        also keine reine javascript-lösung, sondern Active-x.

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. grüssi

          also keine reine javascript-lösung, sondern Active-x.

          Uii, stimmt *rot-anlauf*

          Aber in Mozilla gehts dafür ohne ActiveX, ich verprechs *g*

          Ähm, rhetorische Gegenfrage: Ist das dann eine reine JavaScript-Lösung ohne C oder so?

          gruß
          Sven

  2. Hi!

    Vielleicht kennt sich jemand mit UTF und dem HTTP-Standard gut genug aus.

    Probiert einmal ein Formular aus, gebt den Gedankenstrich (Alt+150) in ein Textfeld ein und schickt es an den Server und lest den Parameter mit Perl aus (egal ob CGI.pm oder die handgestrickten Zeilen).

    Ihr werdet nur noch das lesen können: –

    Das entspricht eben der Zeichenfolge die vom Browser kodiert wird. Bei einem GET-Formular seht ihr es ja ohnedies in der Adresszeile

    http://someserver?test=%E2%80%93&send=send

    Da wird einfach paarweise genommen und zurückgewandelt in ein Byte.

    Was aber gemacht werden müsste, ist ein Dekodieren nach UTF8, denn das ist dieser 3-Byte-Code tatsächlich der Gedankenstrich.

    Deshalb war ich auch mit encodeURIComponent und dem Ö nie erfolgreich. Es wird nämlich als %C3%96 kodiert, was in Perl dann auch nicht mehr zu verwenden ist. escape dagegen macht daraus %D6 und das ist tatsächlich der hexadezimal-Wert des Ö in Latin1.

    Ich frage mich jetzt. Ist der Fehler wirklich bei CGI.pm?
    Ich denke.

    Soweit ich weiß, gibt es ja wirklich gewisse Wertbereiche in UTF8, die aus 1-, 2- oder 3-Bytes bestehen. Das wird dann wohl nicht korrekt ausgewertet.

    gruß
    Sven

    1. Hallo,

      Das entspricht eben der Zeichenfolge die vom Browser kodiert wird. Bei einem GET-Formular seht ihr es ja ohnedies in der Adresszeile
      http://someserver?test=%E2%80%93&send=send

      Das passiert aber nur, wenn das Formular in einem HTML-Dokument mit content="text/html; charset=UTF-8" steht.
      In einem HTML-Dokument mit content="text/html; charset=ISO-8859-1" würde das Formular
      http://someserver?test=%96&send=send
      senden.

      Deshalb war ich auch mit encodeURIComponent und dem Ö nie erfolgreich. Es wird nämlich als %C3%96 kodiert, was in Perl dann auch nicht mehr zu verwenden ist. escape dagegen macht daraus %D6 und das ist tatsächlich der hexadezimal-Wert des Ö in Latin1.

      Richtig. Die Funktion encodeURIComponent() encoded in UTF-8. Die Funktion escape() escaped den ISO-8859-1 Hex-Wert.

      Ich frage mich jetzt. Ist der Fehler wirklich bei CGI.pm?

      Wenn Du ein GET- bzw. POST-Request mit UTF-8-encoding sendest, also mit Formular und content="text/html; charset=UTF-8" oder mit encodeURIComponent(), muss der Server das dann natürlich auch als UTF-8 auswerten wollen. Kann CGI.pm das? Das sollte in der Doku dazu stehen. Von allein wird es das nicht machen. Das wirst Du irgendwo angeben müssen, wenn es überhaupt geht.

      viele Grüße

      Axel

      1. Servus!

        Das passiert aber nur, wenn das Formular in einem HTML-Dokument mit content="text/html; charset=UTF-8" steht.

        Ja, danke für den Hinweis (mittlerweile auch rausgefunden)

        Richtig. Die Funktion encodeURIComponent() encoded in UTF-8. Die Funktion escape() escaped den ISO-8859-1 Hex-Wert.

        Stimmt nicht ganz und da liegt das Problem.
        escape liefert beim Gedankenstrich eben nicht den Latin1-Wert (wäre %96), sondern %u2013 - also u für unicode und dann den Wert 8((

        muss der Server das dann natürlich auch als UTF-8 auswerten wollen. Kann CGI.pm das? Das sollte in der Doku dazu stehen. Von allein wird es das nicht machen. Das wirst Du irgendwo angeben müssen, wenn es überhaupt geht.

        Kann: Ja!
        Wie: Keine Ahnung. Schau die Doku nochmal genau durch, aber bis jetzt nix. Was wenn der Server gemischte Anfragen bekommt?

        Ich hab auch schon dem Autor geschrieben, der mich auf die neue Version verwiesen hat, die auch nicht hilft.

        Die eigentliche Ursache ist aber die escape-Funktion, die eben einige Zeichen nicht Latin1-kodiert.

        Wenn ich das Problem löse, läuft es.
        Kann ja nicht so schwierig sein ...

        gruß
        Sven

        1. Hallo,

          Richtig. Die Funktion encodeURIComponent() encoded in UTF-8. Die Funktion escape() escaped den ISO-8859-1 Hex-Wert.
          Stimmt nicht ganz und da liegt das Problem.
          escape liefert beim Gedankenstrich eben nicht den Latin1-Wert (wäre %96), sondern %u2013 - also u für unicode und dann den Wert 8((

          Aua, das ist böse, das sollte so nicht sein. http://www.byteshift.de/javascript-1415/CoreGuideJS15/fcns.html#1012712
          ...
          escape function returns the hexadecimal encoding of an argument in the ISO Latin character set.
          ...
          aber auch
          ...
          The escape and unescape functions do not work properly for non-ASCII characters and have been deprecated. In JavaScript 1.5 and later, use encodeURI, decodeURI, encodeURIComponent, and decodeURIComponent.
          ...

          Dann wirst Du es mit JavaScript also _grundsätzlich_ in UTF-8 und mit encodeURI() erledigen müssen.

          Was wenn der Server gemischte Anfragen bekommt?

          Das sollte man verhindern. Das kann ja eigentlich nur passieren, wenn der Ersteller der Anfrage, also bei einer HTTP-Anfrage vom Browser, der Ersteller der Web-Seite, das so macht, weil er einerseits dem Formular sagt, dass es ISO-Latin ist und andererseits mit JavaScript UTF-8 sendet.

          viele Grüße

          Axel